public static function setUpBeforeClass() { parent::setUpBeforeClass(); self::$fixturesDirectory = realpath(dirname(dirname(__DIR__)) . '/fixtures'); $app = App::create(array('name' => 'Curry Unit Tests', 'adminEmail' => '*****@*****.**', 'cache' => array('method' => 'none'), 'pageCache' => false, 'autoBackup' => false, 'projectPath' => self::$fixturesDirectory, 'migrationVersion' => App::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'))); $app->boot(); // Empty database $con = \Propel::getConnection(); $con->beginTransaction(); try { foreach (\Curry\Util\Propel::getModels(false) as $model) { \PropelQuery::from($model)->deleteAll(); } $con->commit(); } catch (\Exception $e) { $con->rollBack(); throw $e; } $setup = new \Curry\Backend\Setup($app); $setup->saveConfiguration(array('admin' => array('username' => 'admin', 'password' => 'admin'))); $app->cache->clean(); }
/** * Should be called before calling doRebuild(). */ public static function initRebuild() { $models = array(); foreach (Propel::getModels() as $classes) { foreach ($classes as $model) { if (in_array('Curry_ISearchable', class_implements($model))) { $models[] = $model; } } } if (\Curry\App::getInstance()['indexerClass']) { $models[] = '@custom'; } $ses = new \Zend\Session\Container(__CLASS__); $ses->models = $models; $ses->model = 0; $ses->offset = 0; $ses->limit = 10; $ses->failed = 0; $ses->success = 0; }
/** * 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; }
/** * Restore database. */ public function showRestore() { $this->showMainMenu(); $tables = array(); $selectedTables = array(); $disabledTables = array(); foreach (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) . ' (' . Helper::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); }