/** * Restore page from serialized object. * * @param Page $page * @param array $pageData * @param array $pageMap */ public static function restorePage(Page $page, array $pageData, array $pageMap) { unset($pageData['id']); unset($pageData['uid']); unset($pageData['name']); unset($pageData['url']); if ($pageData['redirect_page']) { $page->setRedirectPage(self::findPageByMap($pageData['redirect_page'], $pageMap)); } $page->fromArray($pageData, BasePeer::TYPE_FIELDNAME); $page->save(); if (!$pageData['revision']) { return; } // Create new revision $pr = new PageRevision(); $pr->setPage($page); $pr->setBasePage(self::findPageByMap($pageData['revision']['base_page'], $pageMap)); $pr->fromArray($pageData['revision'], BasePeer::TYPE_FIELDNAME); $pr->setDescription('Copied'); $page->setWorkingPageRevision($pr); $page->save(); // Add module data... $order = array(); $parentPages = ArrayHelper::objectsToArray($page->getWorkingPageRevision()->getInheritanceChain(true), null, 'getPageId'); $inheritedModules = $pr->getModules(); foreach ($pageData['revision']['modules'] as $module) { $pm = null; if (!$module['is_inherited']) { $pm = PageModuleQuery::create()->findOneByUid($module['uid']); if ($pm && !in_array($pm->getPageId(), $parentPages)) { // Page module exists, but is not in our "inheritance chain" // Give the module a new unique-id, and create the module here $pm->setUid(Helper::getUniqueId()); $pm->save(); $pm = null; } } else { // find inherited module foreach ($inheritedModules as $inheritedModule) { if ($inheritedModule->getUid() == $module['uid']) { $pm = $inheritedModule; break; } } } if (!$pm) { $pm = new PageModule(); $pm->setPage($page); $pm->fromArray($module, BasePeer::TYPE_FIELDNAME); } if (!$module['is_inherited']) { $rm = new RevisionModule(); $rm->setPageModule($pm); $rm->setPageRevision($pr); } foreach ($module['datas'] as $moduleData) { $md = new ModuleData(); $md->setPageModule($pm); $md->setPageRevision($pr); $md->fromArray($moduleData, BasePeer::TYPE_FIELDNAME); } $order[] = $pm->getUid(); } $pr->save(); $modules = ArrayHelper::objectsToArray($pr->getModules(), 'getUid'); if (array_keys($modules) !== $order) { foreach ($order as $uid) { $module = $modules[$uid]; $sortorder = new ModuleSortorder(); $sortorder->setPageModule($module); $sortorder->setPageRevision($pr); $sortorder->insertAtBottom(); $sortorder->save(); } } $page->setActivePageRevision($pr); $page->save(); }
/** * Swap position of modules. * * @todo Fix ugly $_POST hack. * * @throws Exception */ public function showSwapModules() { $page = self::getPage(PageAccessPeer::PERM_CONTENT); $pageRevision = $page->getPageRevision(); $a = (int) $_POST['a']; $b = (int) $_POST['b']; $modules = ArrayHelper::objectsToArray($pageRevision->getModules(), null, 'getPageModuleId'); $aIndex = array_search($a, $modules); $bIndex = array_search($b, $modules); if ($aIndex === false || $bIndex === false) { throw new Exception('Unable to find modules to swap.'); } $modules[$aIndex] = $b; $modules[$bIndex] = $a; $list = new Curry_Backend_ContentList($this, $pageRevision); $_POST['item'] = array_map('json_encode', $modules); $list->sortItems(array()); }
/** * Get path details. * * @param string $path * @param string $parent * @param array $highlighted * @param array $selected * @return array */ public function getPathInfo($path, $parent, $highlighted, $selected) { $p = array('Path' => $parent, 'IsRoot' => false, 'UploadUrl' => (string) url('', array('module', 'path' => $parent, 'action' => 'Upload')), 'files' => array()); $realpath = realpath($this->app['wwwPath'] . DIRECTORY_SEPARATOR . $path); $dit = new DirectoryIterator($realpath); foreach ($dit as $entry) { $name = $entry->getFilename(); $vpath = $parent . '/' . $name; if ($name[0] === '.') { continue; } if (isset($_GET['filter'])) { if ($_GET['filter'] == 'folder' && !$entry->isDir()) { continue; } if ($entry->isFile() && !self::matchFilter($_GET['filter'], $name)) { continue; } } $p['files'][] = array('Name' => $name, 'IsHighlighted' => $name == $highlighted, 'IsSelected' => in_array($vpath, $selected), 'IsFolder' => $entry->isDir(), 'Icon' => $entry->isDir() ? 'icon-folder-' . ($name == $highlighted ? 'open' : 'close') : PathHelper::getIconFromExtension(pathinfo($entry->getPathname(), PATHINFO_EXTENSION)), 'Url' => (string) url('', array('module', 'path' => $vpath)), 'Path' => $vpath); } ArrayHelper::sortOn($p['files'], array('IsFolder', 'Name'), array(ArrayHelper::SORT_PROPERTY | ArrayHelper::SORT_REVERSE, ArrayHelper::SORT_PROPERTY | ArrayHelper::SORT_CASEINSENSITIVE)); return $p; }
/** * Restore database from file. * * @todo Fix $maxExecutionTime. * * @param string|resource $file * @param array|null $tables * @param float $maxExecutionTime * @param int $continueLine * @param AbstractLegacyBackend|null $backend * @return bool True on success, false otherwise. */ public static function restoreFromFile($file, $tables = null, $maxExecutionTime = 0, $continueLine = 0, AbstractLegacyBackend $backend = null) { global $CURRY_DATABASE_RESTORE; $CURRY_DATABASE_RESTORE = true; $fp = is_string($file) ? fopen($file, "r") : $file; $t = microtime(true); $total = 0; $skipped = 0; $failed = 0; $session = new \Zend\Session\Container(__CLASS__); $con = Propel::getConnection(); $con->beginTransaction(); $adapter = Propel::getDB(); if ($adapter instanceof DBMySQL) { $con->exec("SET foreign_key_checks = 0"); } // Read header $firstline = stream_get_line($fp, self::MAX_LINE_LENGTH, "\n"); $header = json_decode($firstline, true); if (is_array($header) && isset($header['header'])) { $header = $header['header']; // Check header version $version = isset($header['version']) ? (int) $header['version'] : 0; if ($version > self::VERSION) { throw new Exception('Unsupported database version. The file you are trying to restore from is from a newer version of currycms.'); } // Check page version $pageVersion = isset($header['page-version']) ? (int) $header['page-version'] : 0; if ($pageVersion > Page::VERSION) { throw new Exception('Unsupported page version. The file you are trying to restore from is from a newer version of currycms.'); } if ($backend) { $backend->addMessage("Restoring from " . $header['date']); } if ($pageVersion !== Page::VERSION) { if ($backend) { $backend->addMessage("Migrating data from version {$pageVersion} to " . Page::VERSION, AbstractBackend::MSG_WARNING); } Page::preMigrate($pageVersion); } } else { throw new Exception('Invalid header'); } // Empty tables if ($continueLine == 0) { foreach (Propel::getModels() as $classes) { foreach ($classes as $table) { try { if (is_array($tables) && !in_array($table, $tables)) { continue; } if (!method_exists($table, 'delete')) { if ($backend) { $backend->addMessage("Skipping read-only table: {$table}", AbstractBackend::MSG_WARNING); } continue; } $tableName = PropelQuery::from($table)->getTableMap()->getName(); // use basePeer to avoid foreign key emulation in Normal peer class BasePeer::doDeleteAll($tableName, $con); } catch (Exception $e) { throw new Exception('Unable to empty table ' . $table . ': ' . $e->getMessage()); } } } if ($backend) { $backend->addMessage("Cleared tables in " . round(microtime(true) - $t, 2) . "s"); } $t = microtime(true); } else { $total = $session->total; $skipped = $session->skipped; $failed = $session->failed; if ($backend) { $backend->addMessage("Continuing from line {$continueLine}."); } for ($i = 0; $i < $continueLine; ++$i) { stream_get_line($fp, self::MAX_LINE_LENGTH, "\n"); } } $currentTable = null; $buffer = array(); while (!feof($fp)) { // Read line $data = json_decode(stream_get_line($fp, self::MAX_LINE_LENGTH, "\n"), true); ++$total; if (is_array($data) && isset($data['table'])) { if (is_array($tables) && !in_array($data['table'], $tables) || !method_exists($data['table'], 'delete')) { ++$skipped; continue; } // Verify columns for new table if ($data['table'] !== $currentTable && $currentTable !== null && $backend) { $backend->addMessage('Restoring rows for table ' . $data['table']); $columns = ArrayHelper::objectsToArray(PropelQuery::from($data['table'])->getTableMap()->getColumns(), null, 'getPhpName'); $added = array_diff($columns, array_keys($data['values'])); $removed = array_diff(array_keys($data['values']), $columns); if (count($added)) { $backend->addMessage('New column(s): ' . join(', ', $added), AbstractBackend::MSG_WARNING); } if (count($removed)) { $backend->addMessage('Removed column(s): ' . join(', ', $removed), AbstractBackend::MSG_WARNING); } } // Flush buffer when changing tables if ($data['table'] !== $currentTable || count($buffer) >= self::MULTIINSERT_MAXBUFFER) { if ($currentTable !== null && count($buffer)) { Propel::doMultiInsert($currentTable, $buffer); } $currentTable = $data['table']; $buffer = array(); } // Migrate data if ($pageVersion !== Page::VERSION) { if (!Page::migrateData($data['table'], $data['values'], $pageVersion)) { continue; } } $buffer[] = $data['values']; } else { if ($backend) { $backend->addMessage('Unable to read data on line ' . $total, AbstractBackend::MSG_ERROR); } ++$failed; } // check execution time if ($maxExecutionTime && App::getInstance()->getExecutionTime() > $maxExecutionTime) { if ($currentTable !== null && count($buffer)) { Propel::doMultiInsert($currentTable, $buffer); } $session->total = $total; $session->skipped = $skipped; $session->failed = $failed; $params = array('module' => 'Curry_Backend_Database', 'view' => 'ContinueRestore', 'file' => $file, 'tables' => $tables, 'line' => $total, 'max_execution_time' => $maxExecutionTime); AbstractLegacyBackend::redirect(url('', $params)->getAbsolute("&", true)); } } // Flush buffer if ($currentTable !== null && count($buffer)) { Propel::doMultiInsert($currentTable, $buffer); } if ($pageVersion !== Page::VERSION) { Page::postMigrate($pageVersion); } if ($adapter instanceof DBMySQL) { $con->exec("SET foreign_key_checks = 1"); } $con->commit(); $CURRY_DATABASE_RESTORE = false; if ($backend) { if ($skipped) { $backend->addMessage("Skipped {$skipped} rows"); } if ($failed) { $backend->addMessage("Failed to add {$failed} rows", AbstractBackend::MSG_ERROR); } $backend->addMessage("Added " . ($total - $skipped - $failed) . " / {$total} rows in " . round(microtime(true) - $t, 2) . "s", !$failed ? AbstractBackend::MSG_SUCCESS : AbstractBackend::MSG_ERROR); } if (is_string($file)) { fclose($fp); } return !$failed; }
/** * Internal function to read and cascade all ModuleData objects. */ protected function populateModuleData() { // get PageRevision ancestors $ancestors = array_reverse($this->getPageRevision()->getInheritanceChain(true)); $ancestors = ArrayHelper::objectsToArray($ancestors, null, 'getPageRevisionId'); $ancestors = array_flip($ancestors); $keys = array(); $depth = array(); $lang = array(); $moduleDatas = $this->getPageModule()->getModuleDatas(); foreach ($moduleDatas as $key => $moduleData) { if ($moduleData->getLangcode() && $moduleData->getLangcode() !== $this->langcode) { continue; } if (!array_key_exists($moduleData->getPageRevisionId(), $ancestors)) { continue; } $keys[] = $key; $depth[] = $ancestors[$moduleData->getPageRevisionId()]; $lang[] = $moduleData->getLangcode() ? 1 : 0; } $moduleDatas->clearIterator(); // PropelCollection causes memory leak in php 5.3 unless we explicitly clear the iterator array_multisort($depth, $lang, $keys); foreach ($keys as $key) { $this->addData($moduleDatas[$key]); } }
public function sortItems($params) { ModuleSortorderQuery::create()->filterByPageRevision($this->pageRevision)->delete(); $wrappers = $this->pageRevision->getPageModuleWrappers(); $unsortedIds = ArrayHelper::objectsToArray($wrappers, false, 'getPageModuleId'); $wrapperById = ArrayHelper::objectsToArray($wrappers, 'getPageModuleId'); // Get primary keys $items = $_POST['item']; if (!is_array($items)) { throw new Exception('Expected array POST variable `item`.'); } $sortedIds = array(); foreach ($items as $item) { $pk = json_decode($item, true); if ($pk === null) { throw new Exception('Invalid primary key for item: ' . $item); } if (!array_key_exists($pk, $wrapperById)) { throw new Exception('Module not found when sorting'); } $sortedIds[] = $pk; } if ($sortedIds !== $unsortedIds) { foreach ($wrappers as $wrapper) { $sortorder = $wrapper->getSortorder(true); $sortorder->insertAtBottom(); $sortorder->save(); } $pks = array(); foreach ($sortedIds as $id) { $pks[] = array($id, $this->pageRevision->getPageRevisionId()); } Propel::sortableReorder($pks, 'ModuleSortorder'); } $this->pageRevision->setUpdatedAt(time()); $this->pageRevision->save(); }
/** {@inheritdoc} */ public function toTwig() { $flashvars = array(); foreach ($this->flashvars as $flashvar) { $flashvars[$flashvar['name']] = $flashvar['value']; } if ($this->module) { $moduleTemplate = $this->template ? $this->app->twig->loadTemplate($this->template) : null; $flashvars[$this->moduleFlashvar] = $this->module->showFront($moduleTemplate); } if (in_array("get", $this->addToFlashvars)) { ArrayHelper::extend($flashvars, $_GET); } if (in_array("post", $this->addToFlashvars)) { ArrayHelper::extend($flashvars, $_POST); } if (in_array("cookie", $this->addToFlashvars)) { ArrayHelper::extend($flashvars, $_COOKIE); } $options = array(); $options['expressInstall'] = $this->expressInstall; $options['target'] = $this->target; $options['attributes'] = count($this->attributes) ? $this->attributes : null; $options['params'] = count($this->params) ? $this->params : null; $options['flashvars'] = count($flashvars) ? $flashvars : null; $options['alternativeContent'] = $this->alternativeContent; $flashContent = FlashUtil::embed($this->method, $this->flash, $this->width, $this->height, $this->version, $options); return array('Source' => $this->flash, 'Target' => $this->target, 'AlternativeContent' => $this->alternativeContent, 'Html' => $flashContent['html'], 'Script' => $flashContent['script']); }
/** * Render a page and return content. * * @param array $vars * @param array $options * @return Response */ public function render(array $vars = array(), array $options = array()) { $twig = $this->app->twig; $prevPage = isset($this->app->page) ? $this->app->page : null; $prevPageRevision = isset($this->app->pageRevision) ? $this->app->pageRevision : null; $prevGenerator = isset($this->app->generator) ? $this->app->generator : null; $this->app->page = $this->getPage(); $this->app->pageRevision = $this->pageRevision; $this->app->generator = $this; // TODO: Rename curry to app? $appVars = $this->app->globals; if (isset($vars['curry'])) { ArrayHelper::extend($appVars, $vars['curry']); } $vars['curry'] = ArrayHelper::extend($appVars, $this->getGlobals()); foreach ($vars as $k => $v) { $twig->addGlobal($k, $v); } $moduleContent = $this->generate($options); if (isset($options['pageModuleId'])) { $pageModuleId = $options['pageModuleId']; $pageModuleWrappers = $this->getPageModuleWrappers(); if (isset($pageModuleWrappers[$pageModuleId])) { $pageModuleWrapper = $pageModuleWrappers[$pageModuleId]; return $moduleContent[$pageModuleWrapper->getTarget()]; } else { throw new \Exception('PageModule with id = ' . $pageModuleId . ' not found on page.'); } } $event = new RenderEvent($this->getTemplateObject(), $moduleContent); $this->app->dispatcher->dispatch(GeneratorEvents::RENDER, $event); $response = new Response($event->getTemplate()->render($event->getContent())); // restore app variables $this->app->page = $prevPage; $this->app->pageRevision = $prevPageRevision; $this->app->generator = $prevGenerator; return $response; }
/** * Load configuration. * * @param string|array|null $config * @param bool $loadUserConfig * @return array */ protected static function getConfig($config, $loadUserConfig = true) { $userConfig = array(); $configPath = null; $projectPath = null; if (is_string($config)) { // Load configuration from file $configPath = realpath($config); if (!$configPath) { throw new Exception('Configuration file not found: ' . $config); } $projectPath = PathHelper::path(true, dirname($configPath), '..'); if ($loadUserConfig) { $userConfig = (require $configPath); } } else { if (is_array($config)) { // Configuration provided by array if ($loadUserConfig) { $userConfig = $config; } } else { if ($config === null || $config === false) { // Skip configuration } else { throw new Exception('Unknown configuration format.'); } } } // Attempt to find project path if (!$projectPath) { $projectPath = PathHelper::path(true, getcwd(), '..', 'cms'); } if (!$projectPath) { $projectPath = PathHelper::path(true, getcwd(), 'cms'); } // default config $config = array('startTime' => isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(true), 'name' => "untitled", 'baseUrl' => '/', 'adminEmail' => "*****@*****.**", 'divertOutMailToAdmin' => false, 'statistics' => false, 'applicationClass' => 'Curry\\App', 'defaultGeneratorClass' => 'Curry\\Generator\\HtmlGenerator', 'forceDomain' => false, 'revisioning' => false, 'umask' => 02, 'locale' => array('en_US.UTF-8', 'en_US.UTF8', 'UTF-8', 'UTF8'), 'liveEdit' => true, 'secret' => 'SECRET', 'errorNotification' => false, 'basePath' => PathHelper::path(true, dirname(__FILE__), '..', '..'), 'projectPath' => $projectPath, 'wwwPath' => getcwd(), 'configPath' => $configPath, 'cache' => array('method' => 'auto'), 'mail' => array('method' => 'sendmail'), 'log' => array(), 'maintenance' => array('enabled' => false), 'defaultEditor' => 'tinyMCE', 'migrationVersion' => self::MIGRATION_VERSION, 'pageCache' => true, 'autoPublish' => false, 'developmentMode' => false, 'autoUpdateIndex' => false, 'password' => array('algorithm' => PASSWORD_BCRYPT, 'options' => array('cost' => 10))); if ($loadUserConfig) { ArrayHelper::extend($config, $userConfig); } // Fix base url $config['baseUrl'] = url($config['baseUrl'])->getAbsolute(); if (!$config['projectPath']) { throw new Exception('Project path could not be found, please use a configuration file to specify the path'); } $secondaryConfig = array('vendorPath' => PathHelper::path($config['basePath'], 'vendor'), 'tempPath' => self::getTempDir($config['projectPath']), 'trashPath' => PathHelper::path($config['projectPath'], 'data', 'trash'), 'autoBackup' => $config['developmentMode'] ? 0 : 86400, 'errorReporting' => $config['developmentMode'] ? -1 : false, 'propel' => array('conf' => PathHelper::path($config['projectPath'], 'config', 'propel.php'), 'projectClassPath' => PathHelper::path($config['projectPath'], 'propel', 'build', 'classes')), 'template' => array('root' => PathHelper::path($config['projectPath'], 'templates'), 'options' => array('debug' => (bool) $config['developmentMode'], 'cache' => PathHelper::path($config['projectPath'], 'data', 'cache', 'templates'), 'base_template_class' => '\\Curry\\Twig\\Template')), 'backend' => array('basePath' => 'admin/', 'placeholderExclude' => array(), 'theme' => 'vindaloo', 'loginCookieExpire' => 31536000, 'loginTokenExpire' => 31536000), 'mail' => array('options' => array()), 'domainMapping' => array('enabled' => false, 'domains' => array()), 'sharedController' => !file_exists($config['wwwPath'] . '/shared')); $config = ArrayHelper::extend($secondaryConfig, $config); return $config; }
/** {@inheritdoc} */ public function toTwig() { return array('images' => ArrayHelper::objectsToArray($this->images, null, array($this, 'getImageProperties'))); }
/** * Twig callback to get subpages for page. * * @param \Page $page * @return array|\Curry_Twig_CollectionWrapper */ public function twigGetSubpages(\Page $page) { if ($page->isLeaf()) { return array(); } $subpages = array(); /** @var \Page[] $children */ $children = \Page::getCachedChildren($page); foreach ($children as $subpage) { if ($subpage->getEnabled() && ($this->showHidden || $subpage->getVisible())) { $subpages[] = $subpage; } } if ($children instanceof \PropelCollection) { $children->clearIterator(); } // set order switch ($this->sortOrder) { case self::ORDER_SORTINDEX_DESC: ArrayHelper::sortOn($subpages, 'getTreeLeft', ArrayHelper::SORT_REVERSE); break; case self::ORDER_NAME_ASC: ArrayHelper::sortOn($subpages, 'getName'); break; case self::ORDER_NAME_DESC: ArrayHelper::sortOn($subpages, 'getName', ArrayHelper::SORT_REVERSE); break; } return new \Curry_Twig_CollectionWrapper($subpages, array($this, 'twigGetPage')); }
public function setOptions(array $options) { if (isset($options['actions'])) { foreach ($options['actions'] as $name => $action) { $this->addAction($name, $action); } unset($options['actions']); } if (isset($options['columns'])) { foreach ($options['columns'] as $name => $column) { $this->addColumn($name, $column); } unset($options['columns']); } foreach ($options as $k => $v) { if (method_exists($this, 'set' . $k)) { $this->{'set' . $k}($v); } else { if (property_exists($this, $k)) { if (is_array($this->{$k})) { ArrayHelper::extend($this->{$k}, $v); } else { $this->{$k} = $v; } } else { continue; } } unset($options[$k]); } ArrayHelper::extend($this->options, $options); }
protected static function getBasePageSelect(Page $page = null, $basePageId = null, $advanced = false) { $pages = array('' => '[ Do not inherit ]'); $templatePage = Curry_Backend_Page::getTemplatePage(); if ($templatePage) { $pages['Templates'] = PagePeer::getSelect($templatePage); if ($advanced) { $pages['Pages'] = array_diff_key(PagePeer::getSelect(), $pages['Templates']); } else { if ($basePageId && !array_key_exists($basePageId, $pages['Templates'])) { $basePage = PageQuery::create()->findPk($basePageId); $pages['Pages'] = array($basePageId => $basePage ? $basePage->getName() : '<Unknown>'); } } } else { $pages += PagePeer::getSelect(); } $dependantPages = array(); if ($page) { $dependantPages = ArrayHelper::objectsToArray($page->getDependantPages(), null, 'getPageId'); $dependantPages[] = $page->getPageId(); } $pageSelect = array('select', array('label' => 'Base page', 'multiOptions' => $pages, 'value' => $basePageId, 'description' => 'The page which content and templates will be inherited from.', 'disable' => $dependantPages, 'onchange' => "\$(this).closest('form').find('.base-preview').attr('src', '" . url('', array('module', 'view' => 'BasePreview')) . "&page_id=' + \$(this).val());")); $imageElement = array('rawHtml', array('label' => 'Preview', 'value' => '<img src="' . url('', array('module', 'view' => 'BasePreview', 'page_id' => $basePageId)) . '" class="base-preview" />')); return array($pageSelect, $imageElement); }
protected function getFileAccessList($query = null, $formOptions = array(), $listOptions = array()) { if (!$query) { $query = FilebrowserAccessQuery::create(); } $o = array('columnElements' => array('path' => array('filebrowser', array('filebrowserOptions' => array('local' => false), 'finderOptions' => array('type' => 'folder'), 'allowEmpty' => false, 'validators' => array(array('callback', false, array('callback' => array($this, 'validatePath')))))), 'write' => array('select', array('label' => 'Access', 'multiOptions' => array('' => 'Read', '1' => 'Read / Write'))))); ArrayHelper::extend($o, $formOptions); $modelForm = new Curry_Form_ModelForm('FilebrowserAccess', $o); $modelForm->path->getValidator('callback')->setMessage("Invalid permissions to path '%value%'"); $form = new Curry_ModelView_Form($modelForm); $o = array('title' => 'File permissions', 'modelForm' => $form, 'columns' => array('write' => array('label' => 'Access', 'display' => '{{Write?"Read / Write":"Read"}}'))); ArrayHelper::extend($o, $listOptions); $list = new Curry_ModelView_List($query, $o); return $list; }
/** * Import data into table from CSV file. * * @todo Add support for propel advanced columns (array). * * @throws Exception */ public function showImport() { $modelClass = $_GET['table']; $tableMap = PropelQuery::from($modelClass)->getTableMap(); $columnOptions = ArrayHelper::objectsToArray($tableMap->getColumns(), 'getName', 'getPhpName'); $pks = array(); foreach ($tableMap->getColumns() as $column) { if ($column->isPrimaryKey()) { $pks[] = $column->getName(); } } $form = new Curry_Form(array('method' => 'post', 'action' => url('', $_GET), 'elements' => array('file' => array('file', array('label' => 'CSV File', 'valueDisabled' => true)), 'mode' => array('select', array('label' => 'Mode', 'multiOptions' => array(self::IMPORT_REPLACE => 'Replace', self::IMPORT_APPEND => 'Append', self::IMPORT_UPDATE => 'Update', self::IMPORT_UPDATE_OR_INSERT => 'Update or insert'))), 'skip_first' => array('checkbox', array('label' => 'Skip first line', 'value' => true)), 'columns' => array('text', array('label' => 'Columns in file', 'value' => join(',', array_keys($columnOptions)))), 'use_columns' => array('multiselect', array('label' => 'Columns to use', 'multiOptions' => $columnOptions, 'value' => array_keys($columnOptions), 'size' => min(10, count($columnOptions)))), 'delimiter' => array('text', array('label' => 'Delimiter', 'value' => ',')), 'enclosure' => array('text', array('label' => 'Enclosure', 'value' => '"')), 'escape' => array('text', array('label' => 'Escape', 'value' => '\\')), 'null_value' => array('text', array('label' => 'Null', 'value' => 'Ø')), 'submit' => array('submit', array('label' => 'Import'))))); $fields = array_slice(array_keys($form->getElements()), 2, -1); $form->addDisplayGroup($fields, 'advanced', array('legend' => 'Advanced options', 'class' => 'advanced', 'order' => 2)); $this->addMainContent('<h2>Import: ' . htmlspecialchars($modelClass) . '</h2>'); if (isPost() && $form->isValid($_POST)) { $mode = $form->mode->getValue(); $skipFirst = $form->skip_first->getValue(); $columns = explode(',', $form->columns->getValue()); $useColumns = $form->use_columns->getValue(); $delimiter = $form->delimiter->getValue(); $enclosure = $form->enclosure->getValue(); $escape = $form->escape->getValue(); $nullValue = $form->null_value->getValue(); if (!$form->file->isUploaded()) { throw new Exception('Error when uploading file.'); } // Check for non-existent columns $nonExistent = array_filter(array_diff($columns, array_keys($columnOptions))); if (count($nonExistent)) { throw new Exception('Unknown column in column list: ' . join(', ', $nonExistent)); } // Open csv file $fileInfo = $form->file->getFileInfo(); $fp = fopen($fileInfo['file']['tmp_name'], "r"); if (!$fp) { throw new Exception('Unable to open file'); } // Wrap in transaction $deleted = 0; $updated = 0; $inserted = 0; $con = \Propel::getConnection(PropelQuery::from($modelClass)->getDbName()); $con->beginTransaction(); try { // Replace will empty the table if ($mode === self::IMPORT_REPLACE) { $deleted = PropelQuery::from($modelClass)->deleteAll(); } // Read csv lines while (($data = fgetcsv($fp, 0, $delimiter, $enclosure, $escape)) !== false) { if (count($data) !== count($columns)) { throw new Exception('Invalid column count ' . count($data) . ', expected ' . count($columns)); } if ($skipFirst) { $skipFirst = false; continue; } $data = array_combine($columns, $data); $pkData = array(); // Check for null values and collect primary key foreach ($data as $k => $v) { if ($v === $nullValue) { $data[$k] = $v = null; } if (in_array($k, $pks)) { $pkData[$k] = $v; } } $obj = null; if ($mode === self::IMPORT_UPDATE || $mode === self::IMPORT_UPDATE_OR_INSERT) { // attempt to find existing object using pk if (count($pkData) === count($pks)) { $obj = new $modelClass(); $obj->fromArray($pkData, BasePeer::TYPE_FIELDNAME); $obj = PropelQuery::from($modelClass)->findPk($obj->getPrimaryKey()); } if (!$obj && $mode === self::IMPORT_UPDATE_OR_INSERT) { // not found, create new $obj = new $modelClass(); } } else { // REPLACE, APPEND $obj = new $modelClass(); } // Remove unused columns foreach ($data as $k => $v) { if (!in_array($k, $useColumns)) { unset($data[$k]); } } if ($obj) { // Unset primary key columns in data when appending if ($mode === self::IMPORT_APPEND) { foreach ($pks as $pk) { if (array_key_exists($pk, $data)) { unset($data[$pk]); } } } $obj->fromArray($data, BasePeer::TYPE_FIELDNAME); if ($obj->isNew()) { // allows insert of custom primary key BasePeer::doInsert($obj->buildCriteria(), $con); ++$inserted; } else { $updated += $obj->save(); } } } $con->commit(); } catch (Exception $e) { $con->rollBack(); throw $e; } if ($deleted) { $this->addMessage('Deleted: ' . $deleted); } if ($inserted) { $this->addMessage('Inserted: ' . $inserted); } if ($updated) { $this->addMessage('Updated: ' . $updated); } $this->addMessage('All done.', self::MSG_SUCCESS); } else { $this->addMainContent($form); } }
/** {@inheritdoc} */ public function toTwig() { return array('links' => ArrayHelper::objectsToArray($this->links, null, array($this, 'getLinkProperties'))); }