/** * Primary task entry point * * @param array $args The current supplied options. */ public function execute($args) { $output = "Started: " . date('Y-m-d g:ia T') . "\n\n"; $output .= "[db:status]: \n"; $util = new Ruckusing_Util_Migrator($this->_adapter); $migrations = $util->get_executed_migrations(); $files = $util->get_migration_files($this->get_framework()->migrations_directory(), 'up'); $applied = array(); $not_applied = array(); foreach ($files as $file) { if (in_array($file['version'], $migrations)) { $applied[] = $file['class'] . ' [ ' . $file['version'] . ' ]'; } else { $not_applied[] = $file['class'] . ' [ ' . $file['version'] . ' ]'; } } if (count($applied) > 0) { $output .= $this->_displayMigrations($applied, 'APPLIED'); } if (count($not_applied) > 0) { $output .= $this->_displayMigrations($not_applied, 'NOT APPLIED'); } $output .= "\n\nFinished: " . date('Y-m-d g:ia T') . "\n\n"; return $output; }
/** * Run migrations * * @param array $migrations nigrations to run * @param $string $target_method direction to migrate to 'up'/'down' * @param string $destination version to migrate to * * @return array */ private function run_migrations($migrations, $target_method, $destination) { $last_version = -1; foreach ($migrations as $file) { $full_path = $this->_migratorDirs[$file['module']] . DIRECTORY_SEPARATOR . $file['file']; if (is_file($full_path) && is_readable($full_path)) { require_once $full_path; $klass = Ruckusing_Util_Naming::class_from_migration_file($file['file']); $obj = new $klass($this->_adapter); $start = $this->start_timer(); try { //start transaction $this->_adapter->start_transaction(); $result = $obj->{$target_method}(); //successfully ran migration, update our version and commit $this->_migrator_util->resolve_current_version($file['version'], $target_method); $this->_adapter->commit_transaction(); } catch (Ruckusing_Exception $e) { $this->_adapter->rollback_transaction(); //wrap the caught exception in our own throw new Ruckusing_Exception(sprintf("%s - %s", $file['class'], $e->getMessage()), Ruckusing_Exception::MIGRATION_FAILED); } $end = $this->end_timer(); $diff = $this->diff_timer($start, $end); $this->_return .= sprintf("========= %s ======== (%.2f)\n", $file['class'], $diff); $last_version = $file['version']; $exec = true; } } //update the schema info $result = array('last_version' => $last_version); return $result; }
/** * Update the local schema to handle multiple records versus the prior architecture * of storing a single version. In addition take all existing migration files * and register them in our new table, as they have already been executed. */ public function update_schema_for_timestamps() { //only create the table if it doesnt already exist $this->_adapter->create_schema_version_table(); //insert all existing records into our new table $migrator_util = new Ruckusing_Util_Migrator($this->_adapter); $files = $migrator_util->get_migration_files($this->migrations_directories(), 'up'); foreach ($files as $file) { if ((int) $file['version'] >= PHP_INT_MAX) { //its new style like '20081010170207' so its not a candidate continue; } //query old table, if it less than or equal to our max version, then its a candidate for insertion $query_sql = sprintf("SELECT version FROM %s WHERE version >= %d", RUCKUSING_SCHEMA_TBL_NAME, $file['version']); $existing_version_old_style = $this->_adapter->select_one($query_sql); if (count($existing_version_old_style) > 0) { //make sure it doesnt exist in our new table, who knows how it got inserted? $new_vers_sql = sprintf("SELECT version FROM %s WHERE version = %d", $this->_adapter->get_schema_version_table_name(), $file['version']); $existing_version_new_style = $this->_adapter->select_one($new_vers_sql); if (empty($existing_version_new_style)) { // use sprintf & %d to force it to be stripped of any leading zeros, we *know* this represents an old version style // so we dont have to worry about PHP and integer overflow $insert_sql = sprintf("INSERT INTO %s (version) VALUES (%d)", $this->_adapter->get_schema_version_table_name(), $file['version']); $this->_adapter->query($insert_sql); } } } }
/** * Indicate if a class name is already used * * @param string $classname The class name to test * @param string $migrationDir The directory of migration files * * @return bool */ public static function classNameIsDuplicated($classname, $migrationDir) { $migrationFiles = Ruckusing_Util_Migrator::get_migration_files($migrationDir, 'up'); $classname = strtolower($classname); foreach ($migrationFiles as $file) { if (strtolower($file['class']) == $classname) { return true; } } return false; }
/** * test target version with runnable migrations going down, no current version */ public function test_get_runnable_migrations_going_down_with_target_version_no_current() { $migrator_util = new Ruckusing_Util_Migrator($this->adapter); $this->insert_dummy_version_data(array(3, '20090122193325')); $actual_down_files = $migrator_util->get_runnable_migrations($this->migrations_dirs, 'down', 1, false); $expect_down_files = array(array('version' => '20090122193325', 'class' => 'AddNewTable', 'file' => '20090122193325_AddNewTable.php', 'module' => 'default'), array('version' => 3, 'class' => 'AddIndexToBlogs', 'file' => '003_AddIndexToBlogs.php', 'module' => 'default')); $this->assertEquals($expect_down_files, $actual_down_files); $this->clear_dummy_data(); $this->insert_dummy_version_data(array(3)); $actual_down_files = $migrator_util->get_runnable_migrations($this->migrations_dirs, 'down', 1, false); $expect_down_files = array(array('version' => 3, 'class' => 'AddIndexToBlogs', 'file' => '003_AddIndexToBlogs.php', 'module' => 'default')); $this->assertEquals($expect_down_files, $actual_down_files); //go all the way down! $this->clear_dummy_data(); $this->insert_dummy_version_data(array(1, 3, '20090122193325')); $actual_down_files = $migrator_util->get_runnable_migrations($this->migrations_dirs, 'down', 0, false); $expect_down_files = array(array('version' => '20090122193325', 'class' => 'AddNewTable', 'file' => '20090122193325_AddNewTable.php', 'module' => 'default'), array('version' => 3, 'class' => 'AddIndexToBlogs', 'file' => '003_AddIndexToBlogs.php', 'module' => 'default'), array('version' => 1, 'class' => 'CreateUsers', 'file' => '001_CreateUsers.php', 'module' => 'default')); $this->assertEquals($expect_down_files, $actual_down_files); }
/** * test target version with runnable migrations going up, no current version, new module just added */ public function test_get_runnable_migrations_going_up_with_target_version_no_current_new_module() { $migrator_util = new Ruckusing_Util_Migrator($this->adapter); $this->insert_dummy_version_data(array(1, 3)); $actual_up_files = $migrator_util->get_runnable_migrations($this->migrations_dirs, 'up', false); // need to up with new migrations form new module folder $expect_up_files = array(array('version' => 2, 'class' => 'JustNewMigration', 'file' => '002_JustNewMigration.php', 'module' => 'additional'), array('version' => '20090122193325', 'class' => 'AddNewTable', 'file' => '20090122193325_AddNewTable.php', 'module' => 'default')); $this->assertEquals($expect_up_files, $actual_up_files); // order of up doesn't influence on order of down $this->clear_dummy_data(); $this->insert_dummy_version_data(array(1, 3, 2, '20090122193325')); $actual_down_files = $migrator_util->get_runnable_migrations($this->migrations_dirs, 'down', 0, false); $expect_down_files = array(array('version' => '20090122193325', 'class' => 'AddNewTable', 'file' => '20090122193325_AddNewTable.php', 'module' => 'default'), array('version' => 3, 'class' => 'AddIndexToBlogs', 'file' => '003_AddIndexToBlogs.php', 'module' => 'default'), array('version' => 2, 'class' => 'JustNewMigration', 'file' => '002_JustNewMigration.php', 'module' => 'additional'), array('version' => 1, 'class' => 'CreateUsers', 'file' => '001_CreateUsers.php', 'module' => 'default')); $this->assertEquals($expect_down_files, $actual_down_files); }