diff options
Diffstat (limited to 'vendor/gipfl/db-migration')
-rw-r--r-- | vendor/gipfl/db-migration/composer.json | 16 | ||||
-rw-r--r-- | vendor/gipfl/db-migration/src/Migration.php | 73 | ||||
-rw-r--r-- | vendor/gipfl/db-migration/src/Migrations.php | 299 |
3 files changed, 388 insertions, 0 deletions
diff --git a/vendor/gipfl/db-migration/composer.json b/vendor/gipfl/db-migration/composer.json new file mode 100644 index 0000000..da2ae4a --- /dev/null +++ b/vendor/gipfl/db-migration/composer.json @@ -0,0 +1,16 @@ +{ + "name": "gipfl/db-migration", + "description": "Simple DB migration helper", + "type": "library", + "require": { + "php": ">=5.6" + }, + "config": { + "sort-packages": true + }, + "autoload": { + "psr-4": { + "gipfl\\DbMigration\\": "src" + } + } +} diff --git a/vendor/gipfl/db-migration/src/Migration.php b/vendor/gipfl/db-migration/src/Migration.php new file mode 100644 index 0000000..2e6c586 --- /dev/null +++ b/vendor/gipfl/db-migration/src/Migration.php @@ -0,0 +1,73 @@ +<?php + +namespace gipfl\DbMigration; + +use Exception; +use gipfl\ZfDb\Adapter\Pdo\PdoAdapter as Db; +use InvalidArgumentException; +use RuntimeException; +use Zend_Db_Adapter_Pdo_Abstract as ZfDb; + +class Migration +{ + /** + * @var string + */ + protected $sql; + + /** + * @var int + */ + protected $version; + + public function __construct($version, $sql) + { + $this->version = $version; + $this->sql = $sql; + } + + /** + * @param Db|ZfDb $db + * @return $this + */ + public function apply($db) + { + if (! ($db instanceof Db || $db instanceof ZfDb)) { + throw new InvalidArgumentException('$db must be an valid Zend_Db PDO adapter'); + } + // TODO: this is fragile and depends on accordingly written schema files: + $sql = preg_replace('/-- .*$/m', '', $this->sql); + $queries = preg_split( + '/[\n\s\t]*;[\n\s\t]+/s', + $sql, + -1, + PREG_SPLIT_NO_EMPTY + ); + + if (empty($queries)) { + throw new RuntimeException(sprintf( + 'Migration %d has no queries', + $this->version + )); + } + + try { + foreach ($queries as $query) { + if (preg_match('/^(?:OPTIMIZE|EXECUTE) /i', $query)) { + $db->query($query); + } else { + $db->exec($query); + } + } + } catch (Exception $e) { + throw new RuntimeException(sprintf( + 'Migration %d failed (%s) while running %s', + $this->version, + $e->getMessage(), + $query + )); + } + + return $this; + } +} 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' + ); + } +} |