From e32f2373af20180ad3c6e2fd8978ff8ffb146377 Mon Sep 17 00:00:00 2001 From: Daif Alotaibi Date: Tue, 25 Apr 2017 08:33:54 +0300 Subject: [PATCH] Add up and down option for migrate and seed commands. Add setup function to migration and seed file to prepare the data array. Rollback the migration or the seed using down option. Remove rollback command. Remove version_by_name function. --- CHANGELOG.md | 14 +- application/controllers/Creator/Creator.php | 2 + .../Creator/commands/Migrate_Command.php | 112 ++++++++------- .../Creator/commands/Rollback_Command.php | 92 ------------- .../Creator/commands/Seed_Command.php | 127 +++++++++--------- .../Creator/templates/migration.php | 26 +++- .../controllers/Creator/templates/seeder.php | 27 +++- application/core/ER_Controller.php | 2 +- application/core/ER_Migration.php | 25 ++++ .../migrations/20160901000000_ertikazos.php | 38 ++++-- .../seeds/20160901000000_ertikazos.php | 39 ++++-- 11 files changed, 280 insertions(+), 224 deletions(-) delete mode 100644 application/controllers/Creator/commands/Rollback_Command.php diff --git a/CHANGELOG.md b/CHANGELOG.md index fc17e1f..24c7c0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## 1.3.0 - 2017-04-25 +### Added +- Add `up` and `down` option for migrate and seed commands. +- Add `setup` function to migration and seed file to prepare the data array. + +### Changed +- Rollback the migration or the seed using `down` option. + +### Removed +- Remove rollback command. +- Remove version_by_name function. + ## 1.2.0 - 2017-03-23 ### Added - Implement ErtikazOS store. @@ -36,6 +48,6 @@ make_label function can used to print the input label. - Remove unused $models variable from ER_Controller. - Remove unneeded files. -## [1.0.0] - 2016-10-02 +## 1.0.0 - 2016-10-02 ### Added - Initial Commit. diff --git a/application/controllers/Creator/Creator.php b/application/controllers/Creator/Creator.php index 8a771d3..700bb76 100644 --- a/application/controllers/Creator/Creator.php +++ b/application/controllers/Creator/Creator.php @@ -76,6 +76,8 @@ public function index() } } $this->_print("", "", "\n"); + $this->_print("ErtikazOS: ", "", ""); + $this->_print($this::ER_VERSION, "warning", "\n\n"); $this->_print("Usage:", "warning", "\n"); foreach ($this->commands as $key => $command) { diff --git a/application/controllers/Creator/commands/Migrate_Command.php b/application/controllers/Creator/commands/Migrate_Command.php index 4e9e378..a8f9c99 100644 --- a/application/controllers/Creator/commands/Migrate_Command.php +++ b/application/controllers/Creator/commands/Migrate_Command.php @@ -22,7 +22,12 @@ function __construct() $this->config->load('migration'); // auto-load Migration and Seeder include_once(APPPATH . 'core/ER_Migration.php'); - include_once(APPPATH . 'core/ER_Seeder.php'); + // auto create file_path to track files + if(!$this->db->field_exists('file_path', config_item('migration_table'))) + { + $fields = array('file_path' => array('type' => 'varchar', 'constraint' => 64)); + $this->dbforge->add_column(config_item('migration_table'), $fields); + } } /** @@ -37,11 +42,15 @@ public static function commands() { return [ 'name' => 'migrate', - 'desc' => 'Migrate the database to last migration version.', + 'desc' => 'Migrate all file to database or passed $version or $name.', 'vars' => [ [ - 'name' => '$version', - 'desc' => 'Migrate this $version number.', + 'name' => '$version or $name', + 'desc' => 'Migrating file by its [success]$version[/success] or [success]$name[/success].', + ], + [ + 'name' => '$direction', + 'desc' => 'Migrating direction [success]up[/success] or [success]down[/success].', ], ], ]; @@ -52,62 +61,75 @@ public static function commands() * migrate command. * */ - public function migrate($target_version = FALSE) + public function migrate($target_version = FALSE, $direction = 'up') { - $target_version = $this->version_by_name($target_version); - $current_version = $this->db->select('version')->get(config_item('migration_table'))->row(); - if($target_version !== FALSE) + $this->_print('', ''); + if($target_version === FALSE) + { + $migration_path = '*_*.php'; + } + elseif(preg_match('/[0-9]{14}/', $target_version)) + { + $migration_path = ''.$target_version.'_*.php'; + } else + { + $migration_path = '*_'.strtolower($target_version).'.php'; + } + + // find migration files + foreach (glob(config_item('migration_path').$migration_path) as $key => $migration_file) { - if($target_version > $current_version->version) + list($timestamp, $filename) = explode('_', basename($migration_file)); + // search for the migration file in database + $migration_row = $this->db->select('file_path')->get_where(config_item('migration_table'), array('file_path' => basename($migration_file)))->row(); + + require_once(config_item('migration_path').''.basename($migration_file)); + $migration = 'Migration_'.ucfirst(explode('.', $filename)[0]); + + if(!class_exists($migration)) { - if ($this->migration->version($target_version) === FALSE) + $this->_print("migration class '$migration' is not found", 'error'); + continue; + } + // new migration instance + $migration = new $migration; + if(strtolower($direction) == 'down') + { + if($migration_row) { - show_error($this->migration->error_string()); + $migration->down(); + + $this->db->delete(config_item('migration_table'), array('file_path' => basename($migration_file))); + $this->_print(basename($migration_file).' Un-Migrated.', 'success'); } else { - $this->_print("Migrate has been executed", 'success'); + // migration file is not migrated yet + $this->_print(basename($migration_file).' is not migrated yet.', 'success'); + continue; } } else { - $this->_print("Nothing to migrate", 'error'); - return; - } - } - else - { - if ($this->migration->current() === FALSE) - { - show_error($this->migration->error_string()); - } - else - { - $this->_print("Migrate has been executed", 'success'); - } - } - } - - /** - * - * Get target version by name. - * - */ - public function version_by_name($target_version) - { - if(!preg_match('/[0-9]{14}/', $target_version) && $target_version !== FALSE) - { - $version = glob(config_item('migration_path').'*_'.$target_version.'.php'); - if(isset($version[0])) - { - $version = explode('_', basename($version[0])); - if(isset($version[0])) + if($migration_row) { - return $version[0]; + // migrated file is already migrated + $this->_print(basename($migration_file).' is already migrated.', 'warning'); + continue; + } + else + { + $migration->up(); + $this->db->insert(config_item('migration_table'), array('file_path' => basename($migration_file))); + $this->_print(basename($migration_file).' Migrated.', 'success'); } } } - return $target_version; + if(!isset($migration_file)) + { + $this->_print("Migrating target '$target_version' is not found.", 'error'); + } + $this->_print('', ''); } } diff --git a/application/controllers/Creator/commands/Rollback_Command.php b/application/controllers/Creator/commands/Rollback_Command.php deleted file mode 100644 index 3937b27..0000000 --- a/application/controllers/Creator/commands/Rollback_Command.php +++ /dev/null @@ -1,92 +0,0 @@ -load->library('migration'); - $this->load->library('directory'); - $this->load->helper('directory'); - $this->config->load('migration'); - // auto-load Migration and Seeder - include_once(APPPATH . 'core/ER_Migration.php'); - include_once(APPPATH . 'core/ER_Seeder.php'); - } - - /** - * commands function. - * - * return command list as array. - * - * @access public - * @return array - */ - public static function commands() - { - return [ - 'name' => 'rollback', - 'desc' => 'Rollback the database to the perverse migration version.', - ]; - } - - /** - * - * rollback command. - * - */ - public function rollback($target_version = FALSE) - { - $migration_files = $this->migration->find_migrations(); - $current_version = $this->db->select('version')->get(config_item('migration_table'))->row(); - // rollback the last migration file - if($target_version === FALSE) - { - foreach ($migration_files as $migration_version => $migration_file) - { - if($migration_version < $current_version->version) - { - $target_version = $migration_version; - } - } - } - // rollback to the target version - if($target_version > 0 && $target_version < $current_version->version) - { - if(!array_key_exists($target_version, $migration_files)) - { - $this->_print("Rollback version '" . $target_version . "' is not found", 'error'); - return; - } - } - else - { - $this->_print("Nothing to rollback", 'error'); - return; - } - - if ($this->migration->version($target_version) === FALSE) - { - show_error($this->migration->error_string()); - } - else - { - $this->_print("Rollback to migration version '" . $target_version . "' done", 'success'); - } - } - -} - -?> \ No newline at end of file diff --git a/application/controllers/Creator/commands/Seed_Command.php b/application/controllers/Creator/commands/Seed_Command.php index c62c26b..4c1216b 100644 --- a/application/controllers/Creator/commands/Seed_Command.php +++ b/application/controllers/Creator/commands/Seed_Command.php @@ -19,12 +19,16 @@ function __construct() { parent::__construct(); $this->load->library('migration'); - $this->load->library('directory'); - $this->load->helper('directory'); $this->config->load('migration'); // auto-load Migration and Seeder include_once(APPPATH . 'core/ER_Migration.php'); include_once(APPPATH . 'core/ER_Seeder.php'); + // auto create file_path to track files + if(!$this->db->field_exists('file_path', config_item('migration_table'))) + { + $fields = array('file_path' => array('type' => 'varchar', 'constraint' => 64)); + $this->dbforge->add_column(config_item('migration_table'), $fields); + } } /** @@ -39,11 +43,15 @@ public static function commands() { return [ 'name' => 'seed', - 'desc' => 'Seed database with last seeder file.', + 'desc' => 'Seed all file to database or the passed $version or $name..', 'vars' => [ [ - 'name' => '$version', - 'desc' => 'Seed this $version number.', + 'name' => '$version or $name', + 'desc' => 'Seeding file by its [success]$version[/success] or [success]$name[/success].', + ], + [ + 'name' => '$direction', + 'desc' => 'Seeding direction [success]up[/success] or [success]down[/success].', ], ], ]; @@ -54,76 +62,75 @@ public static function commands() * seed command. * */ - public function seed($target_version = FALSE) + public function seed($target_version = FALSE, $direction = 'up') { - $target_version = $this->version_by_name($target_version); - if(!$this->db->field_exists('seed_version', config_item('migration_table'))) + $this->_print('', ''); + if($target_version === FALSE) { - $fields = array('seed_version' => array('type' => 'BIGINT', 'constraint' => 20)); - $this->dbforge->add_column(config_item('migration_table'), $fields); + $seed_path = 'seeds/*_*.php'; } - $seed_version = $this->db->select('seed_version')->get(config_item('migration_table'))->row(); - // if $target_version is not set, use migration version - if($target_version === FALSE) + elseif(preg_match('/[0-9]{14}/', $target_version)) { - $target_version = $this->db->select('version')->get(config_item('migration_table'))->row(); - $target_version = $target_version->version; + $seed_path = 'seeds/'.$target_version.'_*.php'; + } else + { + $seed_path = 'seeds/*_'.strtolower($target_version).'.php'; } - // if $target_version bigger than old one - if($target_version > $seed_version->seed_version) + + // find seeds files + foreach (glob(config_item('migration_path').$seed_path) as $key => $seed_file) { - $seed_files = directory_map(config_item('migration_path').'seeds/', 1); - if(is_array($seed_files)) + list($timestamp, $filename) = explode('_', basename($seed_file)); + // search for the seed file in database + $seed_row = $this->db->select('file_path')->get_where(config_item('migration_table'), array('file_path' => 'seeds/'.basename($seed_file)))->row(); + + require_once(config_item('migration_path').'seeds/'.basename($seed_file)); + $seeder = ucfirst(explode('.', $filename)[0]).'_Seeder'; + + if(!class_exists($seeder)) { - foreach ($seed_files as $key => $seed_file) + $this->_print("seed class '$seeder' is not found", 'error'); + continue; + } + // new seed instance + $seeder = new $seeder; + if(strtolower($direction) == 'down') + { + if($seed_row) + { + $seeder->down(); + + $this->db->delete(config_item('migration_table'), array('file_path' => 'seeds/'.basename($seed_file))); + $this->_print('seeds/'.basename($seed_file).' Un-Seeded.', 'success'); + } + else { - list($timestamp, $filename) = explode('_', basename($seed_file)); - // $timestamp must be less than $target_version and bigger than old target version - if($timestamp <= $target_version && $timestamp > $seed_version->seed_version) - { - require_once(config_item('migration_path').'seeds/'.$seed_file); - $seeder = ucfirst(explode('.', $filename)[0]).'_Seeder'; - if(class_exists($seeder)) - { - $seeder = new $seeder; - $seeder->up(); - $this->_print('seeds/'.$seed_file." Seeded.", 'success'); - $this->db->update(config_item('migration_table'), array('seed_version' => $target_version)); - } - else - { - $this->_print("seed class '$seeder' is not found", 'error'); - } - } + // seed is not seeded yet + $this->_print('seeds/'.basename($seed_file).' is not seeded yet.', 'success'); + continue; } } - } - else - { - $this->_print("Nothing to seed", 'error'); - } - } - - /** - * - *Get target version by name. - * - */ - public function version_by_name($target_version) - { - if(!preg_match('/[0-9]{14}/', $target_version) && $target_version !== FALSE) - { - $version = glob(config_item('migration_path').'seeds/*_'.$target_version.'.php'); - if(isset($version[0])) + else { - $version = explode('_', basename($version[0])); - if(isset($version[0])) + if($seed_row) { - return $version[0]; + // seed is already seeded + $this->_print('seeds/'.basename($seed_file).' is already seeded.', 'warning'); + continue; + } + else + { + $seeder->up(); + $this->db->insert(config_item('migration_table'), array('file_path' => 'seeds/'.basename($seed_file))); + $this->_print('seeds/'.basename($seed_file).' Seeded.', 'success'); } } } - return $target_version; + if(!isset($seed_file)) + { + $this->_print("Seeding target '$target_version' is not found.", 'error'); + } + $this->_print('', ''); } } diff --git a/application/controllers/Creator/templates/migration.php b/application/controllers/Creator/templates/migration.php index 9b9a07e..ebd3e4c 100644 --- a/application/controllers/Creator/templates/migration.php +++ b/application/controllers/Creator/templates/migration.php @@ -12,16 +12,38 @@ function __construct(){ parent::__construct(); } - public function up() + /** + * prepare the migration array + * + * @return void + */ + public function setup() { // migration array // $this->migration[''] = []; + } + + // migrating + public function up() + { + // prepare migration array + $this->setup(); // migrating the above array $this->migrating(); } + // un-migrating public function down() { - + // prepare migration array + $this->setup(); + // remove migration + foreach ($this->migration as $table => $fields) + { + if(get_instance()->db->count_all($table) == 0) + { + get_instance()->dbforge->drop_table($table, TRUE); + } + } } } diff --git a/application/controllers/Creator/templates/seeder.php b/application/controllers/Creator/templates/seeder.php index 87f0be3..f4cc1fd 100644 --- a/application/controllers/Creator/templates/seeder.php +++ b/application/controllers/Creator/templates/seeder.php @@ -12,15 +12,38 @@ function __construct(){ parent::__construct(); } - public function up() + /** + * prepare the seeds array + * + * @return void + */ + public function setup() { // seeds array // $this->seeds[''] = []; - // seeding the above array + } + + // seeding + public function up() + { + // prepare seeds array + $this->setup(); + // seeding the seeds $this->seeding(); } + // un-seeding public function down() { + // prepare seeds array + $this->setup(); + // delete the seeded data + foreach ($this->seeds as $table => $rows) + { + foreach ($rows as $key => $where) + { + get_instance()->db->delete($table, $where); + } + } } } diff --git a/application/core/ER_Controller.php b/application/core/ER_Controller.php index e20e6f7..3bd9ee2 100644 --- a/application/core/ER_Controller.php +++ b/application/core/ER_Controller.php @@ -13,7 +13,7 @@ class ER_Controller extends CI_Controller{ /** * The current version of ErtikazOS */ - const ER_VERSION = '1.2.0'; + const ER_VERSION = '1.3.0'; /** * The variables array diff --git a/application/core/ER_Migration.php b/application/core/ER_Migration.php index d158219..b8f1398 100644 --- a/application/core/ER_Migration.php +++ b/application/core/ER_Migration.php @@ -26,6 +26,31 @@ function __construct(){ parent::__construct(); } + /** + * Retrieves current schema version, override CI_Migration class + * + * @return string Current migration version + */ + protected function _get_version() + { + $row = $this->db->select('version')->get($this->_migration_table)->row(); + return $row ? $row->version : '0'; + } + + // -------------------------------------------------------------------- + + /** + * Stores the current schema version, override CI_Migration class + * + * @param string $migration Migration reached + * @return void + */ + protected function _update_version($migration) + { + $this->db->update($this->_migration_table, array( + 'version' => $migration + )); + } /** * migrating the database diff --git a/application/migrations/20160901000000_ertikazos.php b/application/migrations/20160901000000_ertikazos.php index 43392aa..a9522ee 100644 --- a/application/migrations/20160901000000_ertikazos.php +++ b/application/migrations/20160901000000_ertikazos.php @@ -12,8 +12,14 @@ function __construct(){ parent::__construct(); } - public function up() + /** + * prepare the migration array + * + * @return void + */ + public function setup() { + // migration array // er_settings table $this->migration['er_settings'] = array( 'name' => 'er_settings', @@ -204,7 +210,7 @@ public function up() //table suffix 'user_create_by' => array( 'type' => 'INT', - 'constraint' => 11, + 'constraint' => 11, 'default' => '0' ), 'user_update_by' => array( @@ -426,22 +432,30 @@ public function up() ), 'attributes' => array('ENGINE' => 'MyISAM'), ); + } - // do the migration + // migrating + public function up() + { + // prepare migration array + $this->setup(); + // migrating the above array $this->migrating(); - } + // un-migrating public function down() { - $this->dbforge->drop_table('er_settings', TRUE); - $this->dbforge->drop_table('er_apps', TRUE); - $this->dbforge->drop_table('er_groups', TRUE); - $this->dbforge->drop_table('er_users', TRUE); - $this->dbforge->drop_table('er_users_ses', TRUE); - $this->dbforge->drop_table('er_users_rels', TRUE); - $this->dbforge->drop_table('er_permissions', TRUE); - $this->dbforge->drop_table('er_logs', TRUE); + // prepare migration array + $this->setup(); + // remove migration + foreach ($this->migration as $table => $fields) + { + if(get_instance()->db->count_all($table) == 0) + { + get_instance()->dbforge->drop_table($table, TRUE); + } + } } } ?> \ No newline at end of file diff --git a/application/migrations/seeds/20160901000000_ertikazos.php b/application/migrations/seeds/20160901000000_ertikazos.php index b7226ce..6f0ba01 100644 --- a/application/migrations/seeds/20160901000000_ertikazos.php +++ b/application/migrations/seeds/20160901000000_ertikazos.php @@ -2,13 +2,26 @@ defined('BASEPATH') OR exit('No direct script access allowed'); class Ertikazos_Seeder extends ER_Seeder { - public function up() + /** + * Class constructor + * + * @return void + */ + function __construct() { get_instance()->load->model('Admin/App_model'); get_instance()->load->model('Admin/User_model'); get_instance()->load->model('Admin/Group_model'); get_instance()->load->model('User/Notify_model'); + } + /** + * prepare the seeds array + * + * @return void + */ + public function setup() + { $this->seeds['er_apps'] = array( // User application array( @@ -377,21 +390,29 @@ public function up() 'user_status' => User_model::STATUS_ACTIVE ), ); + } + public function up() + { + // prepare seeds array + $this->setup(); // seeding the seeds $this->seeding(); - } public function down() { - get_instance()->db->delete('er_settings'); - get_instance()->db->delete('er_apps'); - get_instance()->db->delete('er_groups'); - get_instance()->db->delete('er_users'); - get_instance()->db->delete('er_users_ses'); - get_instance()->db->delete('er_users_rels'); - get_instance()->db->delete('er_permissions'); + // prepare seeds array + $this->setup(); + + // delete the seeded data + foreach ($this->seeds as $table => $rows) + { + foreach ($rows as $key => $where) + { + get_instance()->db->delete($table, $where); + } + } } } ?> \ No newline at end of file