public static function setUpBeforeClass() { parent::setUpBeforeClass(); self::$fixturesDirectory = realpath(dirname(dirname(__DIR__)) . '/fixtures'); \Curry_Core::init(array('curry' => array('name' => 'Curry Unit Tests', 'adminEmail' => '*****@*****.**', 'autoBackup' => false, 'projectPath' => self::$fixturesDirectory, 'migrationVersion' => \Curry_Core::MIGRATION_VERSION, 'template' => array('root' => self::$fixturesDirectory . '/templates', 'options' => array('cache' => false)), 'propel' => array('conf' => self::$fixturesDirectory . '/propel/build/conf/curry-conf.php', 'projectClassPath' => self::$fixturesDirectory . '/propel/build/classes')))); // Empty database $con = \Propel::getConnection(); $con->beginTransaction(); try { foreach (\Curry_Propel::getModels(false) as $model) { \PropelQuery::from($model)->deleteAll(); } $con->commit(); } catch (Exception $e) { $con->rollBack(); throw $e; } $setup = new \Curry_Backend_Setup(); $setup->saveConfiguration(array('template' => 'empty', 'admin' => array('username' => 'admin', 'password' => 'admin'), 'user' => array('username' => 'user', 'password' => 'user'))); }
protected function getQueryMap() { if (is_null($this->queryMap)) { $this->queryMap = array(); $models = Curry_Propel::getModels(false); foreach ($models as $model) { $peerClass = "{$model}Peer"; $tableMap = $peerClass::getTableMap(); $this->queryMap[$model] = array(); // introspect columns for text types foreach ($tableMap->getColumns() as $columnMap) { if ($columnMap->isText() && $columnMap->getType() != 'CHAR') { $this->queryMap[$model][] = $columnMap; } } } } return $this->queryMap; }
/** * Get search criteria with filters and sorting applied. * * @return ModelCriteria */ public function getCriteria() { // build criteria $q = clone $this->query; // search field if ($_POST['query'] && $_POST['qtype']) { $qtype = $_POST['qtype']; $query = $_POST['query']; if ($this->tableMap->hasColumn($qtype)) { $field = $this->modelClass . "." . $this->tableMap->getColumn($qtype)->getPhpName(); } elseif (Curry_Propel::hasI18nColumn($qtype, $this->tableMap)) { $i18nBehavior = Curry_Propel::getBehavior('i18n', $this->tableMap); $q->joinI18n(isset($_GET['locale']) ? $_GET['locale'] : $i18nBehavior['default_locale']); $field = "{$this->modelClass}I18n" . '.' . Curry_Propel::getI18nColumn($qtype, $this->tableMap)->getPhpName(); } else { $field = $this->modelClass . "." . $qtype; } $searchMethod = isset($this->searchMethod[$qtype]) ? $this->searchMethod[$qtype] : self::SEARCH_LIKE; switch ($searchMethod) { case self::SEARCH_EQUAL: $q->where("{$field} = ?", $query); break; case self::SEARCH_LIKE: $q->where("{$field} " . Criteria::LIKE . " ?", "%{$query}%"); break; case self::SEARCH_TERMS_ANY: case self::SEARCH_TERMS_ALL: $terms = preg_split('/\\s+/', trim($query)); $conditions = array(); foreach ($terms as $i => $term) { $name = 'c' . $i; $q->condition($name, "{$field} " . Criteria::LIKE . " ?", "%{$term}%"); $conditions[] = $name; } $q->combine($conditions, $searchMethod == self::SEARCH_TERMS_ALL ? Criteria::LOGICAL_AND : Criteria::LOGICAL_OR); break; default: } } // sort on field if ($_POST['sortname'] && $_POST['sortorder']) { $q->clearOrderByColumns(); try { if ($this->tableMap->hasColumn($_POST['sortname'])) { $field = $this->tableMap->getColumn($_POST['sortname'])->getPhpName(); } else { // Is raw PhpName in case of virtualColumns $field = $_POST['sortname']; } if ($_POST['sortorder'] == 'asc') { $q->orderBy($field, CRITERIA::ASC); } if ($_POST['sortorder'] == 'desc') { $q->orderBy($field, CRITERIA::DESC); } } catch (Exception $e) { trace($e); } } return $q; }
public function templateToString($template, BaseObject $obj) { $tpl = Curry_Twig_Template::loadTemplateString($template); return $tpl->render(Curry_Propel::toTwig($obj)); }
/** * Insert module and return generated content. * * @param Curry_PageModuleWrapper $pageModuleWrapper * @return string */ protected function insertModule(Curry_PageModuleWrapper $pageModuleWrapper) { Curry_Core::log(($pageModuleWrapper->getEnabled() ? 'Inserting' : 'Skipping') . ' module "' . $pageModuleWrapper->getName() . '" of type "' . $pageModuleWrapper->getClassName() . '" with target "' . $pageModuleWrapper->getTarget() . '"'); if (!$pageModuleWrapper->getEnabled()) { return ""; } $cached = false; $devMode = Curry_Core::$config->curry->developmentMode; if ($devMode) { $time = microtime(true); $sqlQueries = Curry_Propel::getQueryCount(); $userTime = Curry_Util::getCpuTime('u'); $systemTime = Curry_Util::getCpuTime('s'); $memoryUsage = memory_get_usage(true); } $this->moduleCache = array(); $module = $pageModuleWrapper->createObject(); $module->setPageGenerator($this); $cp = $module->getCacheProperties(); $cacheName = $this->getModuleCacheName($pageModuleWrapper, $module); // try to use cached content if ($cp !== null && ($cache = Curry_Core::$cache->load($cacheName)) !== false) { $cached = true; $this->insertCachedModule($cache); $content = $cache['content']; } else { $template = null; if ($pageModuleWrapper->getTemplate()) { $template = Curry_Twig_Template::loadTemplate($pageModuleWrapper->getTemplate()); } else { if ($module->getDefaultTemplate()) { $template = Curry_Twig_Template::loadTemplateString($module->getDefaultTemplate()); } } if ($template && $template->getEnvironment()) { $twig = $template->getEnvironment(); $twig->addGlobal('module', array('Id' => $pageModuleWrapper->getPageModuleId(), 'ClassName' => $pageModuleWrapper->getClassName(), 'Name' => $pageModuleWrapper->getName(), 'ModuleDataId' => $pageModuleWrapper->getModuleDataId(), 'Target' => $pageModuleWrapper->getTarget())); } $content = (string) $module->showFront($template); if ($cp !== null) { $this->moduleCache['content'] = $content; $this->saveModuleCache($cacheName, $cp->getLifetime()); } } if ($devMode) { $time = microtime(true) - $time; $userTime = Curry_Util::getCpuTime('u') - $userTime; $systemTime = Curry_Util::getCpuTime('s') - $systemTime; $memoryUsage = memory_get_usage(true) - $memoryUsage; $sqlQueries = $sqlQueries !== null ? Curry_Propel::getQueryCount() - $sqlQueries : null; $cpuLimit = Curry_Core::$config->curry->debug->moduleCpuLimit; $timeLimit = Curry_Core::$config->curry->debug->moduleTimeLimit; $memoryLimit = Curry_Core::$config->curry->debug->moduleMemoryLimit; $sqlLimit = Curry_Core::$config->curry->debug->moduleSqlLimit; if ($userTime + $systemTime > $cpuLimit || $time > $timeLimit) { trace_warning('Module generation time exceeded limit'); } if ($memoryUsage > $memoryLimit) { trace_warning('Module memory usage exceeded limit'); } if ($sqlQueries > $sqlLimit) { trace_warning('Module sql query count exceeded limit'); } // add module debug info $this->moduleDebugInfo[] = array($pageModuleWrapper->getName(), $pageModuleWrapper->getClassName(), $pageModuleWrapper->getTemplate(), $pageModuleWrapper->getTarget(), $cached, round($time * 1000.0), round(($userTime + $systemTime) * 1000.0), Curry_Util::humanReadableBytes($memoryUsage), Curry_Util::humanReadableBytes(memory_get_peak_usage(true)), $sqlQueries !== null ? $sqlQueries : 'n/a'); } return $content; }
public static function toTwig(BaseObject $obj, $checkToTwig = true, $includeRelated = true, $includeVirtual = true, $includeI18n = true) { if ($checkToTwig && method_exists($obj, 'toTwig')) { return $obj->toTwig(); } $tableMap = PropelQuery::from(get_class($obj))->getTableMap(); $p = $obj->toArray(BasePeer::TYPE_PHPNAME); if ($includeRelated) { foreach ($tableMap->getRelations() as $relation) { if (in_array($relation->getType(), array(RelationMap::ONE_TO_MANY, RelationMap::MANY_TO_MANY))) { $name = $relation->getPluralName(); $p[lcfirst($name)] = new Curry_OnDemand(function () use($obj, $name) { return Curry_Array::objectsToArray($obj->{'get' . $name}(), null, array('Curry_Propel', 'toTwig')); }); } else { $name = $relation->getName(); $p[lcfirst($name)] = new Curry_OnDemand(function () use($obj, $name) { $rel = $obj->{'get' . $name}(); return $rel ? Curry_Propel::toTwig($rel) : null; }); } } } // Automatic URL $p['Url'] = new Curry_OnDemand(function () use($obj, $tableMap) { $params = array(); foreach ($tableMap->getPrimaryKeys() as $pk) { $params[$pk->getName()] = $obj->{'get' . $pk->getPhpName()}(); } return url(L(get_class($obj) . 'Url'), $params); }); // Virtual columns if ($includeVirtual) { $p = array_merge($p, $obj->getVirtualColumns()); } // I18n behavior columns if ($includeI18n && self::hasBehavior('i18n', $tableMap)) { $translation = $obj->getCurrentTranslation(); $p = array_merge($p, $translation->toArray()); } return $p; }
/** * Render the specified page revision. * * @param PageRevision $pageRevision * @param Curry_Request $request * @param array $vars * @param array $options */ protected function render(PageRevision $pageRevision, Curry_Request $request, array $vars, array $options) { Curry_Core::log('Showing page ' . $pageRevision->getPage()->getName() . ' (PageRevisionId: ' . $pageRevision->getPageRevisionId() . ')', Zend_Log::NOTICE); $time = microtime(true); $queries = Curry_Propel::getQueryCount(); $cacheName = __CLASS__ . '_Page_' . md5($request->getUri()); $cacheLifetime = $pageRevision->getPage()->getCacheLifetime(); $doCache = $request->getMethod() === 'GET' && $cacheLifetime !== 0; if ($doCache) { ob_start(); } $generator = self::createPageGenerator($pageRevision, $request); $generator->display($vars, $options); if ($doCache) { $cache = array('page_id' => $pageRevision->getPageId(), 'page_revision_id' => $pageRevision->getPageRevisionId(), 'headers' => headers_list(), 'content' => ob_get_flush()); Curry_Core::$cache->save($cache, $cacheName, array(), $cacheLifetime < 0 ? false : $cacheLifetime); } if (Curry_Core::$config->curry->updateTranslationStrings) { Curry_Language::updateLanguageStrings(); } $time = microtime(true) - $time; $queries = $queries !== null ? Curry_Propel::getQueryCount() - $queries : null; Curry_Core::triggerHook('Curry_Application::render', $pageRevision->getPageId(), $pageRevision->getPageRevisionId(), $time, $queries); }
public function sortItems($params) { ModuleSortorderQuery::create()->filterByPageRevision($this->pageRevision)->delete(); $wrappers = $this->pageRevision->getPageModuleWrappers(); $unsortedIds = Curry_Array::objectsToArray($wrappers, false, 'getPageModuleId'); $wrapperById = Curry_Array::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()); } Curry_Propel::sortableReorder($pks, 'ModuleSortorder'); } $this->pageRevision->setUpdatedAt(time()); $this->pageRevision->save(); }
/** * Shutdown function to execute at the end of the request. This function * is called automatically so there is no need to call it explicitly. */ public static function shutdown() { $error = error_get_last(); if ($error !== null && $error['type'] == E_ERROR) { $e = new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']); self::showException($e); } if (self::$logger) { self::$throwExceptionsOnError = false; $queryCount = Curry_Propel::getQueryCount(); $generationTime = self::getExecutionTime(); self::log("Generation time: " . round($generationTime, 3) . "s", Zend_Log::NOTICE); self::log("Peak memory usage: " . Curry_Util::humanReadableBytes(memory_get_peak_usage()), Zend_Log::NOTICE); self::log("SQL query count: " . ($queryCount !== null ? $queryCount : 'n/a'), Zend_Log::NOTICE); if (self::$writer instanceof Zend_Log_Writer_Firebug && !headers_sent()) { // Flush log data to browser $channel = Zend_Wildfire_Channel_HttpHeaders::getInstance(); $response = $channel->getResponse(); $channel->flush(); //$response->sendHeaders(); // send headers manually so http status (3xx) doesn't get overridden foreach ($response->getRawHeaders() as $header) { header($header); } foreach ($response->getHeaders() as $header) { header($header['name'] . ': ' . $header['value'], $header['replace']); } } } }
/** * Restore database from file. * * @todo Fix $maxExecutionTime. * * @param string|resource $file * @param array|null $tables * @param float $maxExecutionTime * @param int $continueLine * @param Curry_Backend|null $backend * @return bool True on success, false otherwise. */ public static function restoreFromFile($file, $tables = null, $maxExecutionTime = 0, $continueLine = 0, Curry_Backend $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_Namespace(__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, Curry_Backend::MSG_WARNING); } Page::preMigrate($pageVersion); } } else { throw new Exception('Invalid header'); } // Empty tables if ($continueLine == 0) { foreach (Curry_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}", Curry_Backend::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 = Curry_Array::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), Curry_Backend::MSG_WARNING); } if (count($removed)) { $backend->addMessage('Removed column(s): ' . join(', ', $removed), Curry_Backend::MSG_WARNING); } } // Flush buffer when changing tables if ($data['table'] !== $currentTable || count($buffer) >= self::MULTIINSERT_MAXBUFFER) { if ($currentTable !== null && count($buffer)) { Curry_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, Curry_Backend::MSG_ERROR); } ++$failed; } // check execution time if ($maxExecutionTime && Curry_Core::getExecutionTime() > $maxExecutionTime) { if ($currentTable !== null && count($buffer)) { Curry_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); url('', $params)->redirect(302, true); } } // Flush buffer if ($currentTable !== null && count($buffer)) { Curry_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", Curry_Backend::MSG_ERROR); } $backend->addMessage("Added " . ($total - $skipped - $failed) . " / {$total} rows in " . round(microtime(true) - $t, 2) . "s", !$failed ? Curry_Backend::MSG_SUCCESS : Curry_Backend::MSG_ERROR); } if (is_string($file)) { fclose($fp); } return !$failed; }
/** * Restore database. */ public function showRestore() { $this->showMainMenu(); $tables = array(); $selectedTables = array(); $disabledTables = array(); foreach (Curry_Propel::getModels() as $package => $classes) { $tables[$package] = array(); foreach ($classes as $table) { $tables[$package][$table] = $table; if (method_exists($table, 'save')) { $selectedTables[] = $table; } else { $disabledTables[] = $table; } } } $files = array('' => '-- Select file --', 'upload' => '[ Upload from computer ]', 'remote' => '[ From remote server ]'); $path = Curry_Backend_DatabaseHelper::createBackupName('*.txt'); foreach (array_reverse(glob($path)) as $file) { $files[$file] = basename($file) . ' (' . Curry_Util::humanReadableBytes(filesize($file)) . ')'; } $form = new Curry_Form(array('action' => url('', array("module", "view", "page_id")), 'method' => 'post', 'enctype' => 'multipart/form-data', 'elements' => array('tables' => array('multiselect', array('label' => 'Tables', 'multiOptions' => $tables, 'value' => $selectedTables, 'disable' => $disabledTables, 'size' => 15)), 'file' => array('select', array('label' => 'From file', 'multiOptions' => $files, 'class' => 'trigger-change', 'onchange' => "\$('#uploadfile-label').next().andSelf()[this.value == 'upload'?'show':'hide']();" . "\$('#remote-label').next().andSelf()[this.value == 'remote'?'show':'hide']();")), 'uploadfile' => array('file', array('label' => 'Upload file', 'valueDisabled' => true)), 'remote' => array('text', array('label' => 'Remote')), 'max_execution_time' => array('text', array('label' => 'Max execution time', 'value' => '', 'description' => 'Input time in seconds to allow interruption if the time taken to restore would exceed the maximum execution time.'))))); $form->addElement('submit', 'Go'); if (isPost() && $form->isValid($_POST)) { if ($form->file->getValue() == 'upload') { if (!$form->uploadfile->isUploaded()) { throw new Exception('No file was uploaded.'); } $fileinfo = $form->uploadfile->getFileInfo(); Curry_Backend_DatabaseHelper::restoreFromFile($fileinfo['uploadfile']['tmp_name'], $form->tables->getValue(), 0, 0, $this); } else { if ($form->file->getValue() == 'remote') { if (!$form->remote->getValue()) { throw new Exception('No remote URL set'); } $url = url($form->remote->getValue()); $post = array('login_username' => $url->getUser(), 'login_password' => $url->getPassword(), 'tables' => '*', 'name' => 'db.txt', 'type' => 'local'); $url->setUser(null)->setPassword(null)->setPath('/admin.php')->add(array('module' => 'Curry_Backend_Database', 'view' => 'Backup')); $context = stream_context_create(array('http' => array('method' => 'POST', 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'content' => http_build_query($post)))); $fp = fopen($url, 'r', false, $context); Curry_Backend_DatabaseHelper::restoreFromFile($fp, $form->tables->getValue(), 0, 0, $this); fclose($fp); } else { if ($form->file->getValue()) { Curry_Backend_DatabaseHelper::restoreFromFile($form->file->getValue(), $form->tables->getValue(), (int) $form->max_execution_time->getValue(), 0, $this); } } } } $this->addMainContent($form); }
/** * Should be called before calling doRebuild(). */ public static function initRebuild() { $models = array(); foreach (Curry_Propel::getModels() as $classes) { foreach ($classes as $model) { if (in_array('Curry_ISearchable', class_implements($model))) { $models[] = $model; } } } if (Curry_Core::$config->curry->indexerClass) { $models[] = '@custom'; } $ses = new Zend_Session_Namespace(__CLASS__); $ses->models = $models; $ses->model = 0; $ses->offset = 0; $ses->limit = 10; $ses->failed = 0; $ses->success = 0; }
/** * Override formatter function for one item. * * @param PDOStatement $stmt * @return mixed */ public function formatOne(PDOStatement $stmt) { $item = parent::format($stmt); if ($this->formatterFunction) { return call_user_func($this->formatterFunction, $item); } if (is_object($item) && $item instanceof BaseObject) { return Curry_Propel::toTwig($item); } return $item; }