/** * @static * @param object $obj a simple object with migration information (from a migration list) * @param string $method * @param array $options * @return mixed */ public static function runMigration(&$obj, $method = 'up', array $options = array()) { // if true, exceptions will not cause the script to exit $forced = isset($options['forced']) ? $options['forced'] : false; // if true, only echo back the SQL to be run $dryrun = isset($options['dryrun']) ? $options['dryrun'] : false; $db_config = MpmDbHelper::get_db_config(); $migrations_table = $db_config->migrations_table; $filename = MpmStringHelper::getFilenameFromTimestamp($obj->timestamp); $classname = 'Migration_' . str_replace('.php', '', $filename); // make sure the file exists; if it doesn't, skip it but display a message $migration_file = MpmListHelper::get_migration_file(MPM_DB_PATH . $filename); if (!$migration_file) { echo "\n\tMigration " . $obj->timestamp . ' (ID ' . $obj->id . ') skipped - file missing.'; return; } // file exists -- run the migration require_once $migration_file; $migration = new $classname(); $msg = "# Performing " . strtoupper($method) . " migration " . $obj->timestamp . ' (ID ' . $obj->id . ')'; if (!empty($migration->info)) { $msg .= "\n# {$migration->info}"; } echo "\n" . $msg . " ... "; MpmSqlLogger::log_to_file("\n" . $msg . "\n"); if ($migration instanceof MpmMigration) { $dbObj = MpmDbHelper::getPdoObj(); } else { $dbObj = MpmDbHelper::getMysqliObj(); } if ($dryrun) { $dbObj->dryrun = true; } $dbObj->beginTransaction(); if ($method == 'down') { $active = 0; } else { $active = 1; } try { $migration->{$method}($dbObj); $sql = "UPDATE `{$migrations_table}` SET `active` = '{$active}' WHERE `id` = {$obj->id}"; $dbObj->internal_exec($sql); } catch (Exception $e) { $dbObj->rollback(); echo "failed!"; echo "\n"; $clw = MpmCommandLineWriter::getInstance(); $clw->writeLine($e->getMessage(), 12); if (!$forced) { echo "\n\n"; // Return with non-0 error code to notify external caller to stop the deployment exit(1); } else { return; } } $dbObj->commit(); echo "done."; }
/** * Object constructor. * * @uses MpmDbHelper::test() * @uses MpmListHelper::mergeFilesWithDb() * * @param array $arguments an array of command line arguments (minus the first two elements which should already be shifted off from the MpmControllerFactory) * * @return MpmController */ public function __construct($command = 'help', $arguments = array()) { $this->arguments = $arguments; $this->command = $command; if ($command != 'help' && $command != 'init') { MpmDbHelper::test(); MpmListHelper::mergeFilesWithDb(); } }
/** * Clears the migrations table and then rebuilds it. * * @uses MpmListHelper::mergeFilesWithDb() * @uses MpmDbHelper::doSingleRowSelect() * * @return void */ public function reloadMigrations() { echo 'Clearing out existing migration data... '; $this->dbObj->exec('TRUNCATE TABLE `mpm_migrations`'); echo 'done.', "\n\n", 'Rebuilding migration data... '; MpmListHelper::mergeFilesWithDb(); echo 'done.', "\n"; if ($this->initialMigrationTimestamp != null) { echo "\n", 'Updating initial migration timestamp to ', $this->initialMigrationTimestamp, '... '; $result = MpmDbHelper::doSingleRowSelect('SELECT COUNT(*) AS total FROM `mpm_migrations` WHERE `timestamp` = "' . $this->initialMigrationTimestamp . '"', $this->dbObj); if ($result->total == 1) { $this->dbObj->exec('UPDATE `mpm_migrations` SET `is_current` = 0'); $this->dbObj->exec('UPDATE `mpm_migrations` SET `is_current` = 1 WHERE `timestamp` = "' . $this->initialMigrationTimestamp . '"'); $this->dbObj->exec('UPDATE `mpm_migrations` SET `active` = 1 WHERE `timestamp` <= "' . $this->initialMigrationTimestamp . '"'); } echo 'done.', "\n"; } }
/** * Determines what action should be performed and takes that action. * * @uses MPM_DB_PATH * @uses MpmDbHelper::test() * @uses MpmListHelper::getFiles() * @uses MpmCommandLineWriter::getInstance() * @uses MpmCommandLineWriter::addText() * @uses MpmCommandLineWriter::write() * @uses MpmDbHelper::getMethod() * @uses MpmUpController::displayHelp() * * @return void */ public function doAction() { // make sure system is init'ed MpmDbHelper::test(); // get date stamp for use in generating filename $date_stamp = date('Y_m_d_H_i_s'); $filename = $date_stamp . '.php'; $vars = array('timestamp' => $date_stamp); //$classname = 'Migration_' . $date_stamp; // get list of files $files = MpmListHelper::getFiles(); // if filename is taken, throw error if (in_array($filename, $files)) { $obj = MpmCommandLineWriter::getInstance(); $obj->addText('Unable to obtain a unique filename for your migration. Please try again in a few seconds.'); $obj->write(); } // create file if (MpmDbHelper::getMethod() == MPM_METHOD_PDO) { $file = MpmTemplateHelper::getTemplate('pdo_migration.txt', $vars); } else { $file = MpmTemplateHelper::getTemplate('mysqli_migration.txt', $vars); } // write the file $fp = fopen(MPM_DB_PATH . $filename, "w"); if ($fp == false) { $obj = MpmCommandLineWriter::getInstance(); $obj->addText('Unable to write new migration file.'); $obj->write(); } $success = fwrite($fp, $file); if ($success == false) { $obj = MpmCommandLineWriter::getInstance(); $obj->addText('Unable to write new migration file.'); $obj->write(); } fclose($fp); // display success message $obj = MpmCommandLineWriter::getInstance(); $obj->addText('New migration created: file /db/' . $filename); $obj->write(); }
/** * Determines what action should be performed and takes that action. * * @uses MpmDbHelper::test() * @uses MpmMigrationHelper::getCurrentMigrationTimestamp() * @uses MpmMigrationHelper::getCurrentMigrationNumber() * @uses MpmListHelper::getFullList() * @uses MpmCommandLineWriter::getInstance() * @uses MpmCommandLineWriter::writeHeader() * @uses MpmCommandLineWriter::writeFooter() * * @return void */ public function doAction() { // make sure we're init'd MpmDbHelper::test(); // get latest timestamp $latest = MpmMigrationHelper::getCurrentMigrationTimestamp(); // get latest number $num = MpmMigrationHelper::getCurrentMigrationNumber(); // get list of migrations $list = MpmListHelper::getFullList(); // get command line writer $clw = MpmCommandLineWriter::getInstance(); $clw->writeHeader(); if (empty($latest)) { echo "You have not performed any migrations yet."; } else { echo "You are currently on migration {$num} -- " . $latest . '.'; } echo "\n"; $clw->writeFooter(); }
/** * Determines what action should be performed and takes that action. * * @uses MpmListController::displayHelp() * @uses MpmListHelper::getFullList() * @uses MpmListHelper::getTotalMigrations() * @uses MpmCommandLineWriter::getInstance() * @uses MpmCommandLineWriter::addText() * @uses MpmCommandLineWriter::write() * * @return void */ public function doAction() { $page = 1; $per_page = 30; if (isset($this->arguments[0])) { $page = $this->arguments[0]; } if (isset($this->arguments[1])) { $per_page = $this->arguments[1]; } if (!is_numeric($per_page)) { $per_page = 30; } if (!is_numeric($page)) { $page = 1; } $start_idx = ($page - 1) * $per_page; $list = MpmListHelper::getFullList($start_idx, $per_page); $total = MpmListHelper::getTotalMigrations(); $total_pages = ceil($total / $per_page); $clw = MpmCommandLineWriter::getInstance(); if ($total == 0) { $clw->addText('No migrations exist.'); } else { $clw->addText("WARNING: Migration numbers may not be in order due to interleaving.", 4); $clw->addText(" "); $clw->addText("#\t\tTimestamp", 6); $clw->addText("=========================================", 4); foreach ($list as $obj) { if (strlen($obj->id) > 1) { $clw->addText($obj->id . "\t" . $obj->timestamp, 6); } else { $clw->addText($obj->id . "\t\t" . $obj->timestamp, 6); } } $clw->addText(" "); $clw->addText("Page {$page} of {$total_pages}, {$total} migrations in all.", 4); } $clw->write(); }
/** * Determines what action should be performed and takes that action. * * @uses MpmListController::displayHelp() * @uses MpmListHelper::getFullList() * @uses MpmListHelper::getTotalMigrations() * @uses MpmCommandLineWriter::getInstance() * @uses MpmCommandLineWriter::addText() * @uses MpmCommandLineWriter::write() * * @return void */ public function doAction() { $page = 1; $per_page = 30; if (isset($this->arguments[0])) { $page = $this->arguments[0]; } if (isset($this->arguments[1])) { $per_page = $this->arguments[1]; } if (!is_numeric($per_page)) { $per_page = 30; } if (!is_numeric($page)) { $page = 1; } $start_idx = ($page - 1) * $per_page; $list = MpmListHelper::getFullList($start_idx, $per_page, true); $total = MpmListHelper::getTotalMigrations(); $total_pages = ceil($total / $per_page); $clw = MpmCommandLineWriter::getInstance(); if ($total == 0) { $clw->addText('No migrations exist.'); } else { $clw->addText("WARNING: Migration numbers may not be in order due to interleaving.", 4); $clw->addText(" "); $clw->addText("#\t\tTimestamp\t\tDescription", 6); $clw->addText(str_repeat('=', 80), 4); foreach ($list as $obj) { // "highlight" the current migration $id = $obj->is_current ? "*" . $obj->id . "*" : $obj->id; $id_indent = strlen($id) > 1 ? "\t" : "\t\t"; $clw->addText($id . $id_indent . $obj->timestamp . "\t" . $obj->info, 6); } $clw->addText(" "); $clw->addText("Page {$page} of {$total_pages}, {$total} migrations in all.", 4); } $clw->write(); }
/** * Returns an array of migration filenames. * * @uses MpmListHelper::getListOfFiles() * * @return array */ public static function getFiles() { $files = array(); $list = MpmListHelper::getListOfFiles(); foreach ($list as $obj) { $files[] = $obj->filename; } return $files; }
/** * Clears the migrations table and then rebuilds it. * * @uses MpmListHelper::mergeFilesWithDb() * @uses MpmDbHelper::doSingleRowSelect() * * @return void */ public function reloadMigrations() { if ($this->dryrun) { echo "No clear out existing migration data for dry-run.\n"; } else { $db_config = MpmDbHelper::get_db_config(); $migrations_table = $db_config->migrations_table; echo 'Clearing out existing migration data... '; $this->dbObj->internal_exec('TRUNCATE TABLE `' . $migrations_table . '`'); echo 'done.', "\n\n", 'Rebuilding migration data... '; MpmListHelper::mergeFilesWithDb(); echo 'done.', "\n"; if ($this->initialMigrationTimestamp != null) { echo "\n", 'Updating initial migration timestamp to ', $this->initialMigrationTimestamp, '... '; $result = MpmDbHelper::doSingleRowSelect('SELECT COUNT(*) AS total FROM `' . $migrations_table . '` WHERE `timestamp` = "' . $this->initialMigrationTimestamp . '"', $this->dbObj); if ($result->total == 1) { $this->dbObj->internal_exec('UPDATE `' . $migrations_table . '` SET `is_current` = 0'); $this->dbObj->internal_exec('UPDATE `' . $migrations_table . '` SET `is_current` = 1 WHERE `timestamp` = "' . $this->initialMigrationTimestamp . '"'); $this->dbObj->internal_exec('UPDATE `' . $migrations_table . '` SET `active` = 1 WHERE `timestamp` <= "' . $this->initialMigrationTimestamp . '"'); } echo 'done.', "\n"; } } }
/** * Determines what action should be performed and takes that action. * * @uses MpmLatestController::displayHelp() * @uses MpmDbHelper::test() * @uses MpmMigrationHelper::getMigrationCount() * @uses MpmCommandLineWriter::getInstance() * @uses MpmMigrationHelper::getLatestMigration() * @uses MpmUpController::doAction() * * @param bool $quiet supresses certain text when true * * @return void */ public function doAction($quiet = false) { // make sure we're init'd MpmDbHelper::test(); //get completed migrations from database //get migrations from file $oldest_migration_id = MpmMigrationHelper::getOldestMigration(); $current_timestamp = MpmMigrationHelper::getCurrentMigrationTimestamp(); $current_num = MpmMigrationHelper::getCurrentMigrationNumber(); /*$latest_num = MpmMigrationHelper::getLatestMigration(); $latest_timestamp = MpmMigrationHelper::getTimestampFromId($latest_num);*/ $db_migrations = MpmListHelper::getListFromDb($current_timestamp, 'down'); $files = MpmListHelper::getListOfFiles(); $all_file_timestamps = MpmListHelper::getTimestampArray($files); $file_timestamps = array(); foreach ($all_file_timestamps as $timestamp) { if ($timestamp <= $current_timestamp) { $file_timestamps[] = $timestamp; } } end($all_file_timestamps); $latest_timestamp = current($all_file_timestamps); //compare timestamps that are in either array to timestamps that are in both arrays to find missing timestamps in either //$missing_merges = array_diff(array_unique( array_merge($file_timestamps,$db_migrations) ), array_intersect($file_timestamps,$db_migrations) ); $missing_database = array_diff($file_timestamps, $db_migrations); $missing_files = array_diff($db_migrations, $file_timestamps); $missing_merges = array_merge($missing_files, $missing_database); sort($missing_merges); reset($missing_merges); $oldest_missing = current($missing_merges); $clw = MpmCommandLineWriter::getInstance(); $clw->writeHeader(); if (!$current_num) { echo 'You have not run any migrations'; } else { echo "You are currently on migration {$current_num} -- " . $current_timestamp . '.'; } if (!empty($missing_files)) { echo "\n\nCompleted migrations that are no longer in migrations directory\n----------\n"; foreach ($missing_files as $file) { echo " {$file}\n"; } } if (!empty($missing_database)) { echo "\n\nOld migrations that have not been run\n----------"; foreach ($missing_database as $db) { echo "\n {$db}"; } } if ($current_timestamp < $latest_timestamp) { echo "\nLatest migration is: {$latest_timestamp}."; } if ($oldest_missing && $oldest_missing <= $current_timestamp || $current_timestamp < $latest_timestamp) { echo "\n\n--- Migration Path --------------------------\n"; $post_down_timestamp = $current_timestamp; if ($oldest_missing && $oldest_missing <= $current_timestamp) { //find target down timestamp $previous_migration = MpmMigrationHelper::getNextTimestamp($oldest_missing, 'down'); if ($previous_migration) { $post_down_timestamp = $previous_migration->timestamp; echo "\n Migrate down to: {$previous_migration->id} -- {$previous_migration->timestamp}"; } else { $post_down_timestamp = 0; echo "\n Remove all migrations"; } } if ($post_down_timestamp < $latest_timestamp) { echo "\n Migrate up to latest: {$latest_timestamp}"; } } else { echo "\n\n You are up to date"; } /*$total_migrations = MpmMigrationHelper::getMigrationCount(); if ($total_migrations == 0) { $clw = MpmCommandLineWriter::getInstance(); $clw->addText('No migrations exist.'); $clw->write(); exit; } $to_id = MpmMigrationHelper::getLatestMigration(); $obj = new MpmUpController('up', array ( $to_id, $forced )); $obj->doAction($quiet); */ $clw->writeFooter(); }
/** * Determines what action should be performed and takes that action. * * @uses MpmLatestController::displayHelp() * @uses MpmDbHelper::test() * @uses MpmMigrationHelper::getMigrationCount() * @uses MpmCommandLineWriter::getInstance() * @uses MpmMigrationHelper::getLatestMigration() * @uses MpmUpController::doAction() * * @param bool $quiet supresses certain text when true * * @return void */ public function doAction($quiet = false) { // make sure we're init'd MpmDbHelper::test(); $clw = MpmCommandLineWriter::getInstance(); $clw->writeHeader(); // are we forcing this? $forced = ''; if (isset($this->arguments[0]) && strcasecmp($this->arguments[0], '--force') == 0) { $forced = '--force'; } //get completed migrations from database //get migrations from file $oldest_migration_id = MpmMigrationHelper::getOldestMigration(); $current_timestamp = MpmMigrationHelper::getCurrentMigrationTimestamp(); $current_num = MpmMigrationHelper::getCurrentMigrationNumber(); //$latest_num = MpmMigrationHelper::getLatestMigration(); //$latest_timestamp = MpmMigrationHelper::getTimestampFromId($latest_num); $db_migrations = MpmListHelper::getListFromDb($current_timestamp, 'down'); $files = MpmListHelper::getListOfFiles(); $all_file_timestamps = MpmListHelper::getTimestampArray($files); $file_timestamps = array(); foreach ($all_file_timestamps as $timestamp) { if ($timestamp <= $current_timestamp) { $file_timestamps[] = $timestamp; } } end($file_timestamps); $latest_timestamp = current($file_timestamps); //compare timestamps that are in either array to timestamps that are in both arrays to find missing timestamps in either //$missing_merges = array_diff(array_unique( array_merge($file_timestamps,$db_migrations) ), array_intersect($file_timestamps,$db_migrations) ); $missing_database = array_diff($file_timestamps, $db_migrations); $missing_files = array_diff($db_migrations, $file_timestamps); $missing_merges = array_merge($missing_files, $missing_database); sort($missing_merges); reset($missing_merges); $oldest_missing = current($missing_merges); try { if ($oldest_missing && $oldest_missing <= $current_timestamp) { $previous_migration = MpmMigrationHelper::getNextTimestamp($oldest_missing, 'down'); if ($previous_migration) { $target_down = $previous_migration->id; } else { $target_down = -1; } $down = new MpmDownController('down', array($target_down, $forced, true)); $down->doAction($quiet); } //merge files with database MpmListHelper::mergeFilesWithDb(); $newest_id = MpmMigrationHelper::getLatestMigration(); if ($newest_id) { $newest_timestamp = MpmMigrationHelper::getTimestampFromId($newest_id); $current_timestamp = MpmMigrationHelper::getCurrentMigrationTimestamp(); if ($newest_timestamp > $current_timestamp) { $obj = new MpmUpController('up', array($newest_id, $forced, true)); $obj->doAction($quiet); } else { echo "\nUp to Date"; } } else { echo "\nUp to Date"; } } catch (Exception $e) { echo "\n\nERROR: " . $e->getMessage() . "\n\n"; exit; } $clw->writeFooter(); }
/** * Determines what action should be performed and takes that action. * * @uses MPM_DB_PATH * @uses MpmDbHelper::test() * @uses MpmListHelper::getFiles() * @uses MpmCommandLineWriter::getInstance() * @uses MpmCommandLineWriter::addText() * @uses MpmCommandLineWriter::write() * @uses MpmDbHelper::getMethod() * @uses MpmUpController::displayHelp() * * @return void */ public function doAction() { // make sure system is init'ed MpmDbHelper::test(); // get date stamp for use in generating filename $date_stamp = date('Y_m_d_H_i_s'); $filename = $date_stamp . '.php'; $classname = 'Migration_' . $date_stamp; // get list of files $files = MpmListHelper::getFiles(); // if filename is taken, throw error if (in_array($filename, $files)) { $obj = MpmCommandLineWriter::getInstance(); $obj->addText('Unable to obtain a unique filename for your migration. Please try again in a few seconds.'); $obj->write(); } // create file if (MpmDbHelper::getMethod() == MPM_METHOD_PDO) { $file = "<?php\n\n"; $file .= 'class ' . $classname . ' extends MpmMigration' . "\n"; $file .= "{\n\n"; $file .= "\t" . 'public function up(PDO &$pdo)' . "\n"; $file .= "\t{\n\t\t\n"; $file .= "\t}\n\n"; $file .= "\t" . 'public function down(PDO &$pdo)' . "\n"; $file .= "\t{\n\t\t\n"; $file .= "\t}\n\n"; $file .= "}\n\n"; $file .= "?>"; } else { $file = "<?php\n\n"; $file .= 'class ' . $classname . ' extends MpmMysqliMigration' . "\n"; $file .= "{\n\n"; $file .= "\t" . 'public function up(ExceptionalMysqli &$mysqli)' . "\n"; $file .= "\t{\n\t\t\n"; $file .= "\t}\n\n"; $file .= "\t" . 'public function down(ExceptionalMysqli &$mysqli)' . "\n"; $file .= "\t{\n\t\t\n"; $file .= "\t}\n\n"; $file .= "}\n\n"; $file .= "?>"; } // write the file $fp = fopen(MPM_DB_PATH . $filename, "w"); if ($fp == false) { $obj = MpmCommandLineWriter::getInstance(); $obj->addText('Unable to write new migration file.'); $obj->write(); } $success = fwrite($fp, $file); if ($success == false) { $obj = MpmCommandLineWriter::getInstance(); $obj->addText('Unable to write new migration file.'); $obj->write(); } fclose($fp); // display success message $obj = MpmCommandLineWriter::getInstance(); $obj->addText('New migration created: file /db/' . $filename); $obj->write(); }