From b6b52a96e4fa10319b49f78de8ad35d5bf72d00c Mon Sep 17 00:00:00 2001 From: Mohammad Yaghobi Date: Sat, 31 Oct 2020 03:23:43 +0330 Subject: [PATCH] v1.2.0 CLI mode added. Some improvements. #1 --- composer.json | 3 +- lib/db/sql/migrations.php | 204 ++++++++++++++++++++++++-------------- 2 files changed, 133 insertions(+), 74 deletions(-) diff --git a/composer.json b/composer.json index e6cd680..baf032a 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ }, "require": { "bcosca/fatfree-core": "^3.6", - "ikkez/f3-schema-builder": "^2.2.4" + "ikkez/f3-schema-builder": "^2.2.4", + "html2text/html2text": "^4.3.1" } } \ No newline at end of file diff --git a/lib/db/sql/migrations.php b/lib/db/sql/migrations.php index 053df78..d400245 100644 --- a/lib/db/sql/migrations.php +++ b/lib/db/sql/migrations.php @@ -2,7 +2,7 @@ /** * @package F3 Migrations - * @version 1.1.2 + * @version 1.2.0 * @link http://github.com/myaghobi/F3-Migrations Github * @author Mohammad Yaghobi * @copyright Copyright (c) 2020, Mohammad Yaghobi @@ -12,8 +12,9 @@ namespace DB\SQL; class Migrations extends \Prefab { - private $version = '1.1.2'; + private $version = '1.2.0'; private $path; + private $dbVersion; private static $log; private $classPrefix = 'migration_case'; private $model; @@ -29,28 +30,29 @@ class Migrations extends \Prefab { */ function __construct(\DB\SQL $db) { $this->f3 = \Base::instance(); - + if ($this->f3->get('DEBUG') < 3) { return; } - if ($this->f3->get('migrations.ENABLE')===false) { + if ($this->f3->get('migrations.ENABLE') === false) { return; } - self::$log=$this->f3->get('migrations.LOG')?:true; + self::$log = $this->f3->get('migrations.LOG') ?: true; - $path = $this->f3->get('migrations.PATH')?:'db'.DIRECTORY_SEPARATOR.'migrations'; + $path = $this->f3->get('migrations.PATH') ?: 'db' . DIRECTORY_SEPARATOR . 'migrations'; // this line will help us to make a relative path $baseClass = new \ReflectionClass('Base'); $this->path = dirname($baseClass->getFileName()) . DIRECTORY_SEPARATOR . $path; $this->db = $db; $this->model = new \DB\SQL\MigrationsModel($this->db); + $this->dbVersion = $this->model->dbVersion(); $this->f3->route('GET /migrations', 'DB\SQL\Migrations->showHome'); $this->f3->route(array( - 'GET /migrations/@action', + 'GET /migrations/@action', 'GET /migrations/@action/@target' ), 'DB\SQL\Migrations->doIt'); } @@ -63,16 +65,14 @@ function __construct(\DB\SQL $db) { * @return void */ function showHome($f3) { - $versionCurrent = $this->currentDBVersion(); - $base = $f3->get('BASE'); // going to make a list of available versions to upgrade $upgradeCases = $this->upgradeCases(); foreach ($upgradeCases as &$case) { - $case = "$case"; + $case = "
  • $case
  • "; } - $upgradesList = implode(', ', $upgradeCases); + $upgradesList = implode('', $upgradeCases); // going to make a list of available versions to downgrade $downgradeCases = $this->downgradeCases(); @@ -84,9 +84,9 @@ function showHome($f3) { $downgradeCases[] = 0; } foreach ($downgradeCases as &$case) { - $case = "$case"; + $case = "
  • $case
  • "; } - $downgradeList = implode(', ', $downgradeCases); + $downgradeList = implode('', $downgradeCases); $actions = array( @@ -94,13 +94,13 @@ function showHome($f3) { "name" => "Migrate", "title" => "Migrate to highest case", "desc" => "Use migrate to run all of the migrations you have created.", - "extra" => "Targets: " . ($upgradesList ?: 'none'), + "extra" => "", ), "rollback" => array( "name" => "Rollback", "title" => "Rollback all cases", "desc" => "Use rollback to get back on your migrations.", - "extra" => "Targets: " . ($downgradeList ?: 'none'), + "extra" => "", ), "refresh" => array( "name" => "Refresh", @@ -130,13 +130,13 @@ function showHome($f3) { $list = ''; foreach ($actions as $action => $array) { - $list .= "
    $array[name] ($action)
    "; - $list .= "
    $array[desc]
    $array[extra]
    "; + $list .= "
    $array[name] ($action)
    "; + $list .= "
    $array[desc]
    $array[extra]
    "; } - $list = "
    $list
    DB Version: $versionCurrent"; + $list = "
    $list
    DB Version: $this->dbVersion"; - $error = !is_dir($this->path)?'The PATH is not valid!':''; - $error = !file_exists($this->path)?'The PATH is not exists!':''; + $error = !is_dir($this->path) ? 'The PATH is not valid!' : ''; + $error = !file_exists($this->path) ? 'The PATH is not exists!' : ''; print $this->serve("Migrations", $list, $error); } @@ -248,7 +248,7 @@ function migrate($f3, $target) { * @param int $target * @return void */ - function rollback($f3, $target=null) { + function rollback($f3, $target = null) { if ($this->downgrade($target)) { $this->applyCases(); } @@ -300,41 +300,39 @@ function retry($f3) { } - /** - * get current version of database according to last migration - * - * @return string - */ - function currentDBVersion() { - $lastCase = $this->model->findCases(1, true); - $versionCurrent = isset($lastCase[0]->version) ? $lastCase[0]->version : '0'; - - return $versionCurrent; - } - - /** * register some cases(records) in the migrations table * * @return bool */ function upgrade($versionTarget = null) { + $res = true; $cases = $this->upgradeCases($versionTarget); - if (count($cases) == 0) { - // there is nothing to do - self::logIt($versionTarget?"Already migrated to $versionTarget!":"There is nothing to do."); - return false; - } - - $stepId = uniqid(); - foreach ($cases as $version) { - // all of migrations with higher version than current version of db - if (version_compare($versionTarget, $version) >= 0) { - $this->model->addCase($version, 1, $stepId); + if (count($this->getMigrationCases($versionTarget)) == 0) { + self::logIt("Target version '$versionTarget' not found!"); + $res = false; + } else if (($status = version_compare($versionTarget, $this->dbVersion)) == 0) { + self::logIt("Already migrated to '$versionTarget'!"); + $res = false; + } else if ($status < 0) { + self::logIt("Choose a version higher than '$this->dbVersion' or use rollback!"); + $res = false; + } else if (count($cases) == 0) { + self::logIt("There is nothing to do!"); + $res = false; + } + + if ($res) { + $stepId = uniqid(); + foreach ($cases as $version) { + // all of migrations with higher version than current version of db + if (version_compare($versionTarget, $version) >= 0) { + $this->model->addCase($version, 1, $stepId); + } } } - return true; + return $res; } @@ -345,9 +343,7 @@ function upgrade($versionTarget = null) { * @return string[] */ function upgradeCases(&$versionTarget = null) { - $versionCurrent = $this->currentDBVersion(); - - $versions = $this->getMigrationCases(true); + $versions = $this->getMigrationCases(null, true); // sort array by version usort($versions, function ($a, $b) { return version_compare($a, $b); @@ -360,7 +356,7 @@ function upgradeCases(&$versionTarget = null) { $result = array(); - $status = version_compare($versionTarget, $versionCurrent); + $status = version_compare($versionTarget, $this->dbVersion); // do we need to upgrade if ($status <= 0) { @@ -369,7 +365,7 @@ function upgradeCases(&$versionTarget = null) { foreach ($versions as $version) { $statusToFile = version_compare($versionTarget, $version); - $statusToCurrent = version_compare($version, $versionCurrent); + $statusToCurrent = version_compare($version, $this->dbVersion); // all higher versions than current version of db if ($statusToCurrent == 1 && $statusToFile >= 0) { @@ -386,19 +382,33 @@ function upgradeCases(&$versionTarget = null) { * @return bool */ function downgrade($versionTarget = null) { - // load all migrated to rollback + $res = true; $cases = $this->downgradeCases($versionTarget); - if (count($cases) == 0) { - self::logIt("No any migration case available to make rollback/reset!"); - return false; - } - - $stepId = uniqid(); - foreach ($cases as $version) { - $this->model->addCase($version, -1, $stepId); + if (count($this->model->findCase($versionTarget)) == 0 && $versionTarget > 0) { + self::logIt("Target version '$versionTarget' not found!"); + $res = false; + } else if (version_compare($versionTarget, '0') < 0) { + self::logIt("The target version is invalid!"); + $res = false; + } else if (($status = version_compare($versionTarget, $this->dbVersion)) == 0) { + self::logIt("The version already is '$versionTarget'!"); + $res = false; + } else if ($status > 0) { + self::logIt("Choose a version lower than the current version of your database as the target version or use migrate!"); + $res = false; + } else if (count($cases) == 0) { + self::logIt("There is nothing to do!"); + $res = false; + } + + if ($res) { + $stepId = uniqid(); + foreach ($cases as $version) { + $this->model->addCase($version, -1, $stepId); + } } - return true; + return $res; } @@ -409,15 +419,13 @@ function downgrade($versionTarget = null) { * @return string[] */ function downgradeCases(&$versionTarget = null) { - $versionCurrent = $this->currentDBVersion(); - // get lowes version if target version is not specified if ($versionTarget == null) { $versionTarget = 0; } - $status = version_compare($versionTarget, $versionCurrent); + $status = version_compare($versionTarget, $this->dbVersion); $result = array(); // do we need to downgrade @@ -428,7 +436,7 @@ function downgradeCases(&$versionTarget = null) { $cases = $this->model->findCases(0, true); foreach ($cases as $case) { $statusToCase = version_compare($versionTarget, $case->version); - $statusToCurrent = version_compare($case->version, $versionCurrent); + $statusToCurrent = version_compare($case->version, $this->dbVersion); // all lower versions than current version if ($statusToCurrent <= 0 && $statusToCase < 0) { @@ -438,6 +446,7 @@ function downgradeCases(&$versionTarget = null) { return $result; } + /** * apply the cases registered in the migrations table * @@ -463,9 +472,9 @@ function applyCases() { } $class = $classes[$incomplete->version]; $methodName = $this->classPrefix . '_' . $this->getSafeVersionNumber($incomplete->version); - + eval(" \$this->$methodName=" . str_replace([''], '', $class)); - + $schema = new \DB\SQL\Schema($this->db); if ($status > 0) { $result = @$this->$methodName->up($this->f3, $this->db, $schema); @@ -473,7 +482,7 @@ function applyCases() { $result = @$this->$methodName->down($this->f3, $this->db, $schema); } - self::logIt(($status>0?'Upgrade':'Downgrade')." from $incomplete->version: " . ($result ? 'done' : 'failed') . '', !$result); + self::logIt(($status > 0 ? 'Upgrade to' : 'Downgrade from') . " $incomplete->version: " . ($result ? 'done' : 'failed') . '', !$result); if (!$result) { break; @@ -489,12 +498,12 @@ function applyCases() { * * @return array */ - function getMigrationCases($loadJustVersions = false) { + function getMigrationCases($version = null, $loadJustVersions = false) { $classes = array(); if (file_exists($this->path) && is_dir($this->path)) { $directoryIterator = new \RecursiveDirectoryIterator($this->path); $iteratorIterator = new \RecursiveIteratorIterator($directoryIterator); - $fileList = new \RegexIterator($iteratorIterator, '/migration_case_((.*?)).php/'); + $fileList = new \RegexIterator($iteratorIterator, '/migration_case_' . $version . '((.*?)).php/'); foreach ($fileList as $file) { $classVersion = $this->getFileVersionNumber($file); if ($loadJustVersions) { @@ -550,7 +559,7 @@ function getFileVersionNumber($path) { * @param bool $resetResult * @return void */ - static function logIt($message, $error=false, $resetResult = false) { + static function logIt($message, $error = false, $resetResult = false) { $f3 = \Base::instance(); if ($resetResult) { $f3->set('lastLog', array()); @@ -561,7 +570,7 @@ static function logIt($message, $error=false, $resetResult = false) { if ($error) { $f3->set('lastLogError', $error); } - + if (self::$log) { $logger = new \Log('migrations.log'); $logger->write($f3->scrub($message)); @@ -587,6 +596,10 @@ function serve($title, $info = null, $error = null, $success = null, $extra = nu ' . $title . '