|
<?php |
|
|
|
/** |
|
* Database Management |
|
*/ |
|
class MigrationManager |
|
{ |
|
public $version; |
|
public $maxMigrationVersion; |
|
|
|
protected $db; |
|
protected $config; |
|
protected $configSection; |
|
protected $env; |
|
protected $migrationsLocation; |
|
protected $migrations = array(); |
|
|
|
/** |
|
* Constructor |
|
* @param PDO $db DB Connection object |
|
* @param Config_Lite $config Configuration Object |
|
* @param string $migrationsLocation Path to migrations folder |
|
*/ |
|
public function __construct($db, $config, $migrationsLocation = __DIR__ . '/migrations') |
|
{ |
|
$this->db = $db; |
|
$this->config = $config; |
|
$this->env = $config->get(null, 'env'); |
|
$this->configSection = ($config->get(null, 'env') == 'development') ? 'db_development' : 'db_production'; |
|
$this->migrationsLocation = $migrationsLocation; |
|
$this->version = $this->readMigrationVersion(); |
|
|
|
$this->getMigrations(); |
|
} |
|
|
|
/** |
|
* Process migrations not executed |
|
* @return void |
|
*/ |
|
public function migrate() |
|
{ |
|
foreach ($this->migrations as $migration) { |
|
if ($migration['number'] <= $this->version) { |
|
continue; |
|
} |
|
require_once $this->migrationsLocation . '/' . $migration['filename']; |
|
$m = new $migration['class']( |
|
$this->db, // db object |
|
$this->config->get($this->configSection, 'database') // db name |
|
); |
|
$m->up(); |
|
$this->version = $migration['number']; |
|
} |
|
|
|
$this->writeMigrationVersion(); |
|
} |
|
|
|
/** |
|
* Reverse migrations |
|
* @return void |
|
*/ |
|
public function reset() |
|
{ |
|
// reverse |
|
arsort($this->migrations); |
|
foreach ($this->migrations as $migration) { |
|
$m = new $migration['class']; |
|
$m->down(); |
|
$this->version = $migration['number'] - 1; |
|
} |
|
// re-sort |
|
asort($this->migrations); |
|
$this->writeMigrationVersion(); |
|
} |
|
|
|
/** |
|
* Get migrations defined |
|
* @return void Sets instance variable $migrations |
|
*/ |
|
public function getMigrations() |
|
{ |
|
$dir = new DirectoryIterator($this->migrationsLocation); |
|
foreach ($dir as $fileinfo) { |
|
if (!$fileinfo->isDot()) { |
|
$parsedData = $this->parseMigrationFilename($fileinfo->getFilename()); |
|
if (!empty($parsedData)) { |
|
$this->migrations[$fileinfo->getFilename()] = $parsedData; |
|
} |
|
} |
|
} |
|
asort($this->migrations); |
|
$last = end($this->migrations); |
|
$this->maxMigrationVersion = $last['number']; |
|
} |
|
|
|
/** |
|
* Check if database exists |
|
* @return bool |
|
*/ |
|
public function databaseExists() |
|
{ |
|
$stmt = $this->db->query(" |
|
SELECT |
|
COUNT(*) |
|
FROM |
|
INFORMATION_SCHEMA.SCHEMATA |
|
WHERE |
|
SCHEMA_NAME = '" . $this->config->get($this->configSection, 'database') . "' |
|
"); |
|
return (bool) $stmt->fetchColumn(); |
|
} |
|
|
|
/** |
|
* Parse migration filename for number, class name |
|
* @param string $filename Migration filename |
|
* @return array Migration filenames, numbers, class names |
|
*/ |
|
private function parseMigrationFilename($filename) |
|
{ |
|
$return = array(); |
|
|
|
$regex = '/^(\d+)_(.*).(php)$/'; |
|
preg_match($regex, $filename, $data); |
|
|
|
if (!empty($data)) { |
|
$return = array( |
|
'filename' => $filename, |
|
'class' => $data[2], |
|
'number' => (integer) ltrim($data[1], '0'), // remove leading zeros |
|
); |
|
} |
|
|
|
return $return; |
|
} |
|
|
|
/** |
|
* Read migration version from .env.ini |
|
* @return integer |
|
*/ |
|
private function readMigrationVersion() |
|
{ |
|
return (integer) $this->config->get('internal', 'migration_ver'); |
|
} |
|
|
|
/** |
|
* Write migration version to .env.ini |
|
* @return void |
|
*/ |
|
private function writeMigrationVersion() |
|
{ |
|
$this->config->set('internal', 'migration_ver', $this->version); |
|
$this->config->save(); |
|
} |
|
} |