diff options
Diffstat (limited to 'vendor/gipfl/db-migration/src/Migrations.php')
-rw-r--r-- | vendor/gipfl/db-migration/src/Migrations.php | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/vendor/gipfl/db-migration/src/Migrations.php b/vendor/gipfl/db-migration/src/Migrations.php new file mode 100644 index 0000000..2f85aa4 --- /dev/null +++ b/vendor/gipfl/db-migration/src/Migrations.php @@ -0,0 +1,299 @@ +<?php + +namespace gipfl\DbMigration; + +use DirectoryIterator; +use Exception; +use gipfl\ZfDb\Adapter\Exception\AdapterException; +use gipfl\ZfDb\Adapter\Adapter as Db; +use gipfl\ZfDb\Adapter\Pdo\Mysql; +use gipfl\ZfDb\Adapter\Pdo\Pgsql; +use InvalidArgumentException; +use Zend_Db_Adapter_Pdo_Abstract as ZfDb; +use Zend_Db_Adapter_Pdo_Mysql as ZfMysql; +use Zend_Db_Adapter_Pdo_Pgsql as ZfPgsql; + +class Migrations +{ + const DB_TYPE_MYSQL = 'mysql'; + + const DB_TYPE_POSTGRESQL = 'pgsql'; + + /** @var Db */ + protected $db; + + /** @var string mysql or pgsql */ + protected $dbType; + + /** @var string */ + protected $schemaDirectory; + + /** @var string */ + protected $tableName; + + /** + * Migrations constructor. + * + * @param Db|ZfDb $db + * @param string $schemaDirectory + * @param string $tableName + */ + public function __construct($db, $schemaDirectory, $tableName = 'schema_migration') + { + if (! ($db instanceof Db || $db instanceof ZfDb)) { + throw new InvalidArgumentException('$db must be an valid Zend_Db PDO adapter'); + } + $this->db = $db; + if ($db instanceof Mysql || $db instanceof ZfMysql) { + $this->dbType = self::DB_TYPE_MYSQL; + } elseif ($db instanceof Pgsql || $db instanceof ZfPgsql) { + $this->dbType = self::DB_TYPE_POSTGRESQL; + } else { + throw new InvalidArgumentException(sprintf( + 'Migrations are currently supported for MySQL and PostgreSQL only, got %s', + get_class($db) + )); + } + $this->tableName = (string) $tableName; + $this->schemaDirectory = (string) $schemaDirectory; + } + + /** + * Still unused + * + * @throws AdapterException|\Zend_Db_Adapter_Exception + */ + protected function createMigrationsTable() + { + if ($this->dbType === self::DB_TYPE_POSTGRESQL) { + $create = /** @lang text */ + <<<SQL + +CREATE TABLE {$this->tableName} ( + schema_version SMALLINT NOT NULL, + migration_time TIMESTAMP WITH TIME ZONE NOT NULL, + PRIMARY KEY (schema_version) +); + +SQL; + } else { + $create = /** @lang text */ + <<<SQL +CREATE TABLE {$this->tableName} ( + schema_version SMALLINT UNSIGNED NOT NULL, + migration_time DATETIME NOT NULL, + PRIMARY KEY (schema_version) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_bin; +SQL; + } + $this->db->exec($create); + } + + /** + * @return int + */ + public function getLastMigrationNumber() + { + try { + $query = $this->db->select()->from( + ['m' => $this->getTableName()], + ['schema_version' => 'MAX(schema_version)'] + ); + + return (int) $this->db->fetchOne($query); + } catch (Exception $e) { + return 0; + } + } + + /** + * @return string + */ + protected function getTableName() + { + return $this->tableName; + } + + /** + * @return bool + */ + public function hasAnyTable() + { + return count($this->db->listTables()) > 0; + } + + /** + * @return bool + */ + public function hasTable($tableName) + { + return in_array($tableName, $this->db->listTables()); + } + + /** + * @return bool + */ + public function hasMigrationsTable() + { + return $this->hasTable($this->tableName); + } + + /** + * @return bool + */ + public function hasSchema() + { + return $this->listPendingMigrations() !== [0]; + } + + /** + * @return bool + */ + public function hasPendingMigrations() + { + return $this->countPendingMigrations() > 0; + } + + /** + * @return int + */ + public function countPendingMigrations() + { + return count($this->listPendingMigrations()); + } + + /** + * @return Migration[] + */ + public function getPendingMigrations() + { + $migrations = array(); + foreach ($this->listPendingMigrations() as $version) { + $migrations[] = new Migration( + $version, + $this->loadMigrationFile($version) + ); + } + + return $migrations; + } + + /** + * @return $this + */ + public function applyPendingMigrations() + { + foreach ($this->getPendingMigrations() as $migration) { + $migration->apply($this->db); + } + + return $this; + } + + /** + * @return int[] + */ + public function listPendingMigrations() + { + $lastMigration = $this->getLastMigrationNumber(); + if ($lastMigration === 0) { + return [0]; + } + + return $this->listMigrationsAfter($this->getLastMigrationNumber()); + } + + /** + * @return int[] + */ + public function listAllMigrations() + { + $dir = $this->getMigrationsDirectory(); + $versions = []; + + if (! is_readable($dir)) { + return $versions; + } + + foreach (new DirectoryIterator($dir) as $file) { + if ($file->isDot()) { + continue; + } + + $filename = $file->getFilename(); + if (preg_match('/^upgrade_(\d+)\.sql$/', $filename, $match)) { + $versions[] = (int) $match[1]; + } + } + + sort($versions); + + return $versions; + } + + /** + * @param $version + * @return false|string + */ + public function loadMigrationFile($version) + { + if ($version === 0) { + $filename = $this->getFullSchemaFile(); + } else { + $filename = sprintf( + '%s/upgrade_%d.sql', + $this->getMigrationsDirectory(), + $version + ); + } + + return file_get_contents($filename); + } + + /** + * @param $version + * @return int[] + */ + protected function listMigrationsAfter($version) + { + $filtered = []; + foreach ($this->listAllMigrations() as $available) { + if ($available > $version) { + $filtered[] = $available; + } + } + + return $filtered; + } + + /** + * @param ?string $subDirectory + * @return string + */ + public function getSchemaDirectory($subDirectory = null) + { + if ($subDirectory === null) { + return $this->schemaDirectory; + } else { + return $this->schemaDirectory . '/' . ltrim($subDirectory, '/'); + } + } + + /** + * @return string + */ + public function getMigrationsDirectory() + { + return $this->getSchemaDirectory($this->dbType . '-migrations'); + } + + /** + * @return string + */ + protected function getFullSchemaFile() + { + return $this->getSchemaDirectory( + $this->dbType. '.sql' + ); + } +} |