diff --git a/lib/Doctrine/Migrations/Configuration/AbstractFileConfiguration.php b/lib/Doctrine/Migrations/Configuration/AbstractFileConfiguration.php deleted file mode 100644 index 465997e97b..0000000000 --- a/lib/Doctrine/Migrations/Configuration/AbstractFileConfiguration.php +++ /dev/null @@ -1,156 +0,0 @@ - 'setMigrationsNamespace', - 'table_name' => 'setMigrationsTableName', - 'column_name' => 'setMigrationsColumnName', - 'column_length' => 'setMigrationsColumnLength', - 'executed_at_column_name' => 'setMigrationsExecutedAtColumnName', - 'organize_migrations' => 'setMigrationOrganization', - 'name' => 'setName', - 'migrations_directory' => 'loadMigrationsFromDirectory', - 'migrations' => 'loadMigrations', - 'custom_template' => 'setCustomTemplate', - 'all_or_nothing' => 'setAllOrNothing', - 'check_database_platform' => 'setCheckDatabasePlatform', - ]; - - /** @var string */ - private $file; - - /** @var bool */ - private $loaded = false; - - /** - * @throws FileNotFound - */ - public function load(string $file) : void - { - if ($this->loaded) { - throw FileAlreadyLoaded::new(); - } - - $path = getcwd() . '/' . $file; - - if (file_exists($path)) { - $file = $path; - } - - $this->file = $file; - - if (! file_exists($file)) { - throw FileNotFound::new(); - } - - $this->doLoad($file); - $this->loaded = true; - } - - public function getFile() : string - { - return $this->file; - } - - /** - * @param mixed[] $config - */ - protected function setConfiguration(array $config) : void - { - foreach ($config as $configurationKey => $configurationValue) { - if (! in_array($configurationKey, self::ALLOWED_CONFIGURATION_KEYS, true)) { - throw InvalidConfigurationKey::new($configurationKey); - } - } - - if (isset($config['migrations_paths'])) { - foreach ($config['migrations_paths'] ?? [] as $namespace => $path) { - $this->addMigrationsDirectory($namespace, $path); - } - } -// foreach (self::CONFIGURATION_METHOD_MAP as $key => $method) { -// if (! isset($config[$key])) { -// continue; -// } -// -// $this->$method($config[$key]); -// } - } - - protected function getDirectoryRelativeToFile(string $file, string $input) : string - { - $path = realpath(dirname($file) . '/' . $input); - - return $path !== false ? $path : $input; - } - - /** - * Abstract method that each file configuration driver must implement to - * load the given configuration file whether it be xml, yaml, etc. or something - * else. - */ - abstract protected function doLoad(string $file) : void; - - private function loadMigrationsFromDirectory(string $migrationsDirectory) : void - { - $this->setMigrationsDirectory($migrationsDirectory); - $this->registerMigrationsFromDirectory($migrationsDirectory); - } - - /** @param string[][] $migrations */ - private function loadMigrations(array $migrations) : void - { - foreach ($migrations as $migration) { - $this->registerMigration( - $migration['version'], - $migration['class'] - ); - } - } - - private function setMigrationOrganization(string $migrationOrganization) : void - { - if (strcasecmp($migrationOrganization, self::VERSIONS_ORGANIZATION_BY_YEAR) === 0) { - $this->setMigrationsAreOrganizedByYear(); - } elseif (strcasecmp($migrationOrganization, self::VERSIONS_ORGANIZATION_BY_YEAR_AND_MONTH) === 0) { - $this->setMigrationsAreOrganizedByYearAndMonth(); - } else { - throw UnknownConfigurationValue::new('organize_migrations', $migrationOrganization); - } - } -} diff --git a/lib/Doctrine/Migrations/Configuration/ArrayConfiguration.php b/lib/Doctrine/Migrations/Configuration/ArrayConfiguration.php deleted file mode 100644 index 95a2cbf15f..0000000000 --- a/lib/Doctrine/Migrations/Configuration/ArrayConfiguration.php +++ /dev/null @@ -1,28 +0,0 @@ -getDirectoryRelativeToFile( - $file, - $config['migrations_directory'] - ); - } - - $this->setConfiguration($config); - } -} diff --git a/lib/Doctrine/Migrations/Configuration/Configuration.php b/lib/Doctrine/Migrations/Configuration/Configuration.php index 5ff9102117..f5b8167063 100644 --- a/lib/Doctrine/Migrations/Configuration/Configuration.php +++ b/lib/Doctrine/Migrations/Configuration/Configuration.php @@ -8,11 +8,9 @@ use DateTimeInterface; use DateTimeZone; use Doctrine\Migrations\Configuration\Exception\MigrationsNamespaceRequired; -use Doctrine\Migrations\Configuration\Exception\ParameterIncompatibleWithFinder; -use Doctrine\Migrations\DependencyFactory; +use Doctrine\Migrations\Configuration\Exception\UnknownConfigurationValue; use Doctrine\Migrations\Exception\MigrationException; -use Doctrine\Migrations\Finder\MigrationDeepFinder; -use Doctrine\Migrations\Finder\MigrationFinder; +use Doctrine\Migrations\Metadata\Storage\MetadataStorageConfigration; /** * The Configuration class is responsible for defining migration configuration information. @@ -20,27 +18,13 @@ class Configuration { public const VERSIONS_ORGANIZATION_BY_YEAR = 'year'; - public const VERSIONS_ORGANIZATION_BY_YEAR_AND_MONTH = 'year_and_month'; - public const VERSION_FORMAT = 'YmdHis'; /** @var string|null */ private $name; - /** @var string */ - private $migrationsTableName = 'doctrine_migration_versions'; - - /** @var string */ - private $migrationsColumnName = 'version'; - - /** @var int */ - private $migrationsColumnLength; - - /** @var string */ - private $migrationsExecutedAtColumnName = 'executed_at'; - - /** @var string[][] */ + /** @var array */ private $migrationsDirectories = []; /** @var bool */ @@ -58,83 +42,53 @@ class Configuration /** @var bool */ private $allOrNothing = false; - /** @var DependencyFactory|null */ - private $dependencyFactory; - /** @var bool */ private $checkDbPlatform = true; - public function addMigrationsDirectory(string $namespace, string $path) : void - { - $this->migrationsDirectories[$namespace] = $path; - } - - public function getMigrationDirectories() : array - { - return $this->migrationsDirectories; - } - - public function setName(string $name) : void - { - $this->name = $name; - } + /** @var MetadataStorageConfigration */ + private $metadataStorageConfiguration = true; - public function getName() : ?string + public function setMetadataStorageConfiguration(MetadataStorageConfigration $metadataStorageConfiguration) { - return $this->name; + $this->metadataStorageConfiguration = $metadataStorageConfiguration; } - public function setMigrationsTableName(string $tableName) : void + public function getMetadataStorageConfiguration(): MetadataStorageConfigration { - $this->migrationsTableName = $tableName; + return $this->metadataStorageConfiguration; } - public function getMigrationsTableName() : string + public function addMigrationsDirectory(string $namespace, string $path): void { - return $this->migrationsTableName; - } - - public function setMigrationsColumnName(string $columnName) : void - { - $this->migrationsColumnName = $columnName; - } - - public function getMigrationsColumnName() : string - { - return $this->migrationsColumnName; - } - - public function setMigrationsColumnLength(int $columnLength) : void - { - $this->migrationsColumnLength = $columnLength; + $this->migrationsDirectories[$namespace] = $path; } - public function getMigrationsColumnLength() : int + public function getMigrationDirectories(): array { - return $this->migrationsColumnLength; + return $this->migrationsDirectories; } - public function setMigrationsExecutedAtColumnName(string $migrationsExecutedAtColumnName) : void + public function setName(string $name): void { - $this->migrationsExecutedAtColumnName = $migrationsExecutedAtColumnName; + $this->name = $name; } - public function getMigrationsExecutedAtColumnName() : string + public function getName(): ?string { - return $this->migrationsExecutedAtColumnName; + return $this->name; } - public function setCustomTemplate(?string $customTemplate) : void + public function setCustomTemplate(?string $customTemplate): void { $this->customTemplate = $customTemplate; } - public function getCustomTemplate() : ?string + public function getCustomTemplate(): ?string { return $this->customTemplate; } - public function areMigrationsOrganizedByYear() : bool + public function areMigrationsOrganizedByYear(): bool { return $this->migrationsAreOrganizedByYear; } @@ -144,9 +98,7 @@ public function areMigrationsOrganizedByYear() : bool */ public function setMigrationsAreOrganizedByYear( bool $migrationsAreOrganizedByYear = true - ) : void { - $this->ensureOrganizeMigrationsIsCompatibleWithFinder(); - + ): void { $this->migrationsAreOrganizedByYear = $migrationsAreOrganizedByYear; } @@ -155,115 +107,74 @@ public function setMigrationsAreOrganizedByYear( */ public function setMigrationsAreOrganizedByYearAndMonth( bool $migrationsAreOrganizedByYearAndMonth = true - ) : void { - $this->ensureOrganizeMigrationsIsCompatibleWithFinder(); - - $this->migrationsAreOrganizedByYear = $migrationsAreOrganizedByYearAndMonth; + ): void { + $this->migrationsAreOrganizedByYear = $migrationsAreOrganizedByYearAndMonth; $this->migrationsAreOrganizedByYearAndMonth = $migrationsAreOrganizedByYearAndMonth; } - public function areMigrationsOrganizedByYearAndMonth() : bool + public function areMigrationsOrganizedByYearAndMonth(): bool { return $this->migrationsAreOrganizedByYearAndMonth; } /** @throws MigrationException */ - public function setMigrationsFinder(MigrationFinder $migrationFinder) : void - { - if (($this->migrationsAreOrganizedByYear || $this->migrationsAreOrganizedByYearAndMonth) - && ! ($migrationFinder instanceof MigrationDeepFinder)) { - throw ParameterIncompatibleWithFinder::new( - 'organize-migrations', - $migrationFinder - ); - } - - $this->migrationFinder = $migrationFinder; - } - - /** @throws MigrationException */ - public function validate() : void + public function validate(): void { if (empty($this->migrationsDirectories)) { throw MigrationsNamespaceRequired::new(); } } -// public function resolveVersionAlias(string $alias) : ?string -// { -// return $this->getDependencyFactory()->getVersionAliasResolver()->resolveVersionAlias($alias); -// } - - public function setIsDryRun(bool $isDryRun) : void + public function setIsDryRun(bool $isDryRun): void { $this->isDryRun = $isDryRun; } - public function isDryRun() : bool + public function isDryRun(): bool { return $this->isDryRun; } - public function setAllOrNothing(bool $allOrNothing) : void + public function setAllOrNothing(bool $allOrNothing): void { $this->allOrNothing = $allOrNothing; } - public function isAllOrNothing() : bool + public function isAllOrNothing(): bool { return $this->allOrNothing; } - public function setCheckDatabasePlatform(bool $checkDbPlatform) : void + public function setCheckDatabasePlatform(bool $checkDbPlatform): void { $this->checkDbPlatform = $checkDbPlatform; } - public function isDatabasePlatformChecked() : bool + public function isDatabasePlatformChecked(): bool { return $this->checkDbPlatform; } - public function generateVersionNumber(?DateTimeInterface $now = null) : string + public function generateVersionNumber(?DateTimeInterface $now = null): string { $now = $now ?: $this->createDateTime(); return $now->format(self::VERSION_FORMAT); } -// public function dispatchEvent(string $eventName, ?EventArgs $args = null) : void -// { -// $this->getDependencyFactory()->getEventDispatcher()->dispatchEvent( -// $eventName, -// $args -// ); -// } - - -// public function getDependencyFactory() : DependencyFactory -// { -// if ($this->dependencyFactory === null) { -// $this->dependencyFactory = new DependencyFactory($this); -// } -// -// return $this->dependencyFactory; -// } - - /** - * @throws MigrationException - */ - private function ensureOrganizeMigrationsIsCompatibleWithFinder() : void + private function createDateTime(): DateTimeImmutable { - if (! ($this->getMigrationsFinder() instanceof MigrationDeepFinder)) { - throw ParameterIncompatibleWithFinder::new( - 'organize-migrations', - $this->getMigrationsFinder() - ); - } + return new DateTimeImmutable('now', new DateTimeZone('UTC')); } - private function createDateTime() : DateTimeImmutable + public function setMigrationOrganization(string $migrationOrganization): void { - return new DateTimeImmutable('now', new DateTimeZone('UTC')); + if (strcasecmp($migrationOrganization, self::VERSIONS_ORGANIZATION_BY_YEAR) === 0) { + $this->setMigrationsAreOrganizedByYear(); + } elseif (strcasecmp($migrationOrganization, self::VERSIONS_ORGANIZATION_BY_YEAR_AND_MONTH) === 0) { + $this->setMigrationsAreOrganizedByYearAndMonth(); + } else { + throw UnknownConfigurationValue::new('organize_migrations', $migrationOrganization); + } } } diff --git a/lib/Doctrine/Migrations/Configuration/JsonConfiguration.php b/lib/Doctrine/Migrations/Configuration/JsonConfiguration.php deleted file mode 100644 index a1afbc38bf..0000000000 --- a/lib/Doctrine/Migrations/Configuration/JsonConfiguration.php +++ /dev/null @@ -1,43 +0,0 @@ -getDirectoryRelativeToFile( - $file, - $config['migrations_directory'] - ); - } - - $this->setConfiguration($config); - } -} diff --git a/lib/Doctrine/Migrations/Configuration/Loader/AbstractFileLoader.php b/lib/Doctrine/Migrations/Configuration/Loader/AbstractFileLoader.php new file mode 100644 index 0000000000..f40daae3e3 --- /dev/null +++ b/lib/Doctrine/Migrations/Configuration/Loader/AbstractFileLoader.php @@ -0,0 +1,28 @@ + $dir){ + $path = realpath(dirname($file) . '/' . $dir); + + $input[$ns] = $path !== false ? $path : $dir; + } + return $input; + + } +} diff --git a/lib/Doctrine/Migrations/Configuration/Loader/ArrayLoader.php b/lib/Doctrine/Migrations/Configuration/Loader/ArrayLoader.php new file mode 100644 index 0000000000..309bde6a93 --- /dev/null +++ b/lib/Doctrine/Migrations/Configuration/Loader/ArrayLoader.php @@ -0,0 +1,72 @@ + function ($paths, Configuration $configuration) { + foreach ($paths as $namespace => $path) { + $configuration->addMigrationsDirectory($namespace, $path); + } + }, + 'table_storage' => [ + 'table_name' => 'setTableName', + 'version_column_name' => 'setVersionColumnName', + 'version_column_length' => 'setVersionColumnLength', + 'executed_at_column_name' => 'setExecutedAtColumnName', + 'execution_time_column_name' => 'setExecutionTimeColumnName', + ], + + 'organize_migrations' => 'setMigrationOrganization', + 'name' => 'setName', + 'custom_template' => 'setCustomTemplate', + 'all_or_nothing' => 'setAllOrNothing', + 'check_database_platform' => 'setCheckDatabasePlatform', + ]; + + $object = new Configuration(); + self::applyConfigs($configMap, $object, $array); + return $object; + } + + private static function applyConfigs (array $configMap, $object, $data) + { + foreach ($data as $configurationKey => $configurationValue) { + if (!isset($configMap[$configurationKey])) { + throw InvalidConfigurationKey::new($configurationKey); + } + + if (is_array($configMap[$configurationKey])) { + if ($configurationKey === 'table_storage') { + $storageConfig = new TableMetadataStorageConfiguration(); + $object->setMetadataStorageConfiguration($storageConfig); + self::applyConfigs($configMap[$configurationKey], $storageConfig, $configurationValue); + } + } else { + call_user_func( + $configMap[$configurationKey] instanceof \Closure ? $configMap[$configurationKey] : [$object, $configMap[$configurationKey]], + $configurationValue, + $object, + $data + ); + } + } + } + +} diff --git a/lib/Doctrine/Migrations/Configuration/Loader/JsonFileLoader.php b/lib/Doctrine/Migrations/Configuration/Loader/JsonFileLoader.php new file mode 100644 index 0000000000..22e213a47c --- /dev/null +++ b/lib/Doctrine/Migrations/Configuration/Loader/JsonFileLoader.php @@ -0,0 +1,50 @@ +arrayLoader = $arrayLoader ?: new ArrayLoader(); + } + + public function load($file) : Configuration + { + $contents = file_get_contents($file); + + assert($contents !== false); + + $config = json_decode($contents, true); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw JsonNotValid::new(); + } + + if (isset($config['migrations_paths'])) { + $config['migrations_paths'] = $this->getDirectoryRelativeToFile( + $file, + $config['migrations_paths'] + ); + } + + return $this->arrayLoader->load($config); + } +} diff --git a/lib/Doctrine/Migrations/Configuration/Loader/Loader.php b/lib/Doctrine/Migrations/Configuration/Loader/Loader.php new file mode 100644 index 0000000000..8b36240b6f --- /dev/null +++ b/lib/Doctrine/Migrations/Configuration/Loader/Loader.php @@ -0,0 +1,12 @@ +arrayLoader = $arrayLoader ?: new ArrayLoader(); + } + + public function load($file) : Configuration + { + $config = require $file; + if ($config instanceof Configuration){ + return $config; + } + + assert(is_array($config)); + if (isset($config['migrations_paths'])) { + $config['migrations_paths'] = $this->getDirectoryRelativeToFile( + $file, + $config['migrations_paths'] + ); + } + + return $this->arrayLoader->load($config); + } +} diff --git a/lib/Doctrine/Migrations/Configuration/Loader/XmlFileLoader.php b/lib/Doctrine/Migrations/Configuration/Loader/XmlFileLoader.php new file mode 100644 index 0000000000..9143ca9fec --- /dev/null +++ b/lib/Doctrine/Migrations/Configuration/Loader/XmlFileLoader.php @@ -0,0 +1,91 @@ +children() : $root->attributes() as $node) { + $nodeName = strtr($node->getName(), "-", "_"); + if ($nodeName === "migrations_paths") { + $config["migrations_paths"] = []; + foreach ($node->{"path"} as $pathNode) { + $config["migrations_paths"][(string)$pathNode['namespace']] = (string)$pathNode; + } + } elseif ($nodeName === "storage" && $node->{"table-storage"} instanceof \SimpleXMLElement) { + $config["table_storage"] = $this->extractParameters($node->{"table-storage"}, false); + } else { + $config[$nodeName] = (string)$node; + } + } + return $config; + } + + public function __construct(ArrayLoader $arrayLoader = null) + { + $this->arrayLoader = $arrayLoader ?: new ArrayLoader(); + } + + public function load($file) : Configuration + { + libxml_use_internal_errors(true); + + $xml = new \DOMDocument(); + + if ($xml->load($file) === false) { + throw XmlNotValid::malformed(); + } + + $xsdPath = __DIR__ . DIRECTORY_SEPARATOR . 'XML' . DIRECTORY_SEPARATOR . 'configuration.xsd'; + +// if (! $xml->schemaValidate($xsdPath)) { +// libxml_clear_errors(); +// +// throw XmlNotValid::failedValidation(); +// } + + $rawXML = file_get_contents($file); + assert($rawXML !== false); + + $root = simplexml_load_string($rawXML, \SimpleXMLElement::class, LIBXML_NOCDATA); + assert($xml !== false); + + $config = $this->extractParameters($root); + + if (isset($config['all_or_nothing'])) { + $config['all_or_nothing'] = BooleanStringFormatter::toBoolean( + $config['all_or_nothing'], + false + ); + } + if (isset($config['migrations_paths'])) { + $config['migrations_paths'] = $this->getDirectoryRelativeToFile( + $file, + $config['migrations_paths'] + ); + } + + return $this->arrayLoader->load($config); + } +} diff --git a/lib/Doctrine/Migrations/Configuration/YamlConfiguration.php b/lib/Doctrine/Migrations/Configuration/Loader/YamlFileLoader.php similarity index 54% rename from lib/Doctrine/Migrations/Configuration/YamlConfiguration.php rename to lib/Doctrine/Migrations/Configuration/Loader/YamlFileLoader.php index 17c86c7bee..9aa8136663 100644 --- a/lib/Doctrine/Migrations/Configuration/YamlConfiguration.php +++ b/lib/Doctrine/Migrations/Configuration/Loader/YamlFileLoader.php @@ -2,28 +2,27 @@ declare(strict_types=1); -namespace Doctrine\Migrations\Configuration; +namespace Doctrine\Migrations\Configuration\Loader; +use Doctrine\Migrations\Configuration\Configuration; use Doctrine\Migrations\Configuration\Exception\YamlNotAvailable; use Doctrine\Migrations\Configuration\Exception\YamlNotValid; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Yaml; -use function assert; -use function class_exists; -use function file_get_contents; -use function is_array; - -/** - * The YamlConfiguration class is responsible for loading migration configuration information from a YAML file. - * - * @internal - */ -class YamlConfiguration extends AbstractFileConfiguration + +class YamlFileLoader extends AbstractFileLoader { /** - * @inheritdoc + * @var ArrayLoader */ - protected function doLoad(string $file) : void + private $arrayLoader; + + public function __construct(ArrayLoader $arrayLoader = null) + { + $this->arrayLoader = $arrayLoader ?: new ArrayLoader(); + } + + public function load($file) : Configuration { if (! class_exists(Yaml::class)) { throw YamlNotAvailable::new(); @@ -43,13 +42,13 @@ protected function doLoad(string $file) : void throw YamlNotValid::invalid(); } - if (isset($config['migrations_directory'])) { - $config['migrations_directory'] = $this->getDirectoryRelativeToFile( + if (isset($config['migrations_paths'])) { + $config['migrations_paths'] = $this->getDirectoryRelativeToFile( $file, - $config['migrations_directory'] + $config['migrations_paths'] ); } - $this->setConfiguration($config); + return $this->arrayLoader->load($config); } } diff --git a/lib/Doctrine/Migrations/Configuration/XmlConfiguration.php b/lib/Doctrine/Migrations/Configuration/XmlConfiguration.php deleted file mode 100644 index 0c074828db..0000000000 --- a/lib/Doctrine/Migrations/Configuration/XmlConfiguration.php +++ /dev/null @@ -1,119 +0,0 @@ -load($file) === false) { - throw XmlNotValid::malformed(); - } - - $xsdPath = __DIR__ . DIRECTORY_SEPARATOR . 'XML' . DIRECTORY_SEPARATOR . 'configuration.xsd'; - - if (! $xml->schemaValidate($xsdPath)) { - libxml_clear_errors(); - - throw XmlNotValid::failedValidation(); - } - - $rawXML = file_get_contents($file); - assert($rawXML !== false); - - $xml = simplexml_load_string($rawXML, SimpleXMLElement::class, LIBXML_NOCDATA); - assert($xml !== false); - - $config = []; - - if (isset($xml->name)) { - $config['name'] = (string) $xml->name; - } - - if (isset($xml->{'custom-template'})) { - $config['custom_template'] = (string) $xml->{'custom-template'}; - } - - if (isset($xml->table['name'])) { - $config['table_name'] = (string) $xml->table['name']; - } - - if (isset($xml->table['column'])) { - $config['column_name'] = (string) $xml->table['column']; - } - - if (isset($xml->table['column_length'])) { - $config['column_length'] = (int) $xml->table['column_length']; - } - - if (isset($xml->table['executed_at_column'])) { - $config['executed_at_column_name'] = (string) $xml->table['executed_at_column']; - } - - if (isset($xml->{'migrations-namespace'})) { - $config['migrations_namespace'] = (string) $xml->{'migrations-namespace'}; - } - - if (isset($xml->{'organize-migrations'})) { - $config['organize_migrations'] = (string) $xml->{'organize-migrations'}; - } - - if (isset($xml->{'migrations-directory'})) { - $config['migrations_directory'] = $this->getDirectoryRelativeToFile( - $file, - (string) $xml->{'migrations-directory'} - ); - } - - if (isset($xml->{'all-or-nothing'})) { - $config['all_or_nothing'] = BooleanStringFormatter::toBoolean( - (string) $xml->{'all-or-nothing'}, - false - ); - } - - if (isset($xml->migrations->migration)) { - $migrations = []; - - foreach ($xml->migrations->migration as $migration) { - $attributes = $migration->attributes(); - - $version = (string) $attributes['version']; - $class = (string) $attributes['class']; - - $migrations[] = [ - 'version' => $version, - 'class' => $class, - ]; - } - - $config['migrations'] = $migrations; - } - - $this->setConfiguration($config); - } -} diff --git a/lib/Doctrine/Migrations/DependencyFactory.php b/lib/Doctrine/Migrations/DependencyFactory.php index dd1e0ea460..24529b28b4 100644 --- a/lib/Doctrine/Migrations/DependencyFactory.php +++ b/lib/Doctrine/Migrations/DependencyFactory.php @@ -6,14 +6,16 @@ use Doctrine\DBAL\Connection; use Doctrine\Migrations\Configuration\Configuration; +use Doctrine\Migrations\Configuration\Exception\ParameterIncompatibleWithFinder; use Doctrine\Migrations\Finder\GlobFinder; +use Doctrine\Migrations\Finder\MigrationDeepFinder; use Doctrine\Migrations\Finder\MigrationFinder; use Doctrine\Migrations\Finder\RecursiveRegexFinder; use Doctrine\Migrations\Generator\FileBuilder; use Doctrine\Migrations\Generator\Generator; use Doctrine\Migrations\Generator\SqlGenerator; -use Doctrine\Migrations\Metadata\MetadataStorage; -use Doctrine\Migrations\Metadata\TableMetadataStorage; +use Doctrine\Migrations\Metadata\Storage\MetadataStorage; +use Doctrine\Migrations\Metadata\Storage\TableMetadataStorage; use Doctrine\Migrations\Provider\LazySchemaDiffProvider; use Doctrine\Migrations\Provider\SchemaDiffProvider; use Doctrine\Migrations\Provider\SchemaDiffProviderInterface; @@ -118,9 +120,19 @@ public function getParameterFormatter() : ParameterFormatterInterface public function getMigrationsFinder() : MigrationFinder { - return $this->getDependency(GlobFinder::class, static function () : MigrationFinder { + $finder = $this->getDependency(GlobFinder::class, static function () : MigrationFinder { return new GlobFinder(); }); + + // todo move this to DI + + if (!($finder instanceof MigrationDeepFinder) && ($this->configuration->areMigrationsOrganizedByYear() || $this->configuration->areMigrationsOrganizedByYearAndMonth())) { + throw ParameterIncompatibleWithFinder::new( + 'organize-migrations', + $finder + ); + } + return $finder; } public function setSorter(callable $sorter) : void diff --git a/lib/Doctrine/Migrations/Generator/FileBuilder.php b/lib/Doctrine/Migrations/Generator/FileBuilder.php index 3a67b85334..d59ed125ad 100644 --- a/lib/Doctrine/Migrations/Generator/FileBuilder.php +++ b/lib/Doctrine/Migrations/Generator/FileBuilder.php @@ -6,7 +6,7 @@ use DateTimeInterface; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\Migrations\Metadata\MetadataStorage; +use Doctrine\Migrations\Metadata\Storage\MetadataStorage; use Doctrine\Migrations\Version\Direction; use function sprintf; diff --git a/lib/Doctrine/Migrations/Metadata/ExecutedMigration.php b/lib/Doctrine/Migrations/Metadata/ExecutedMigration.php index ac221ece05..edf812eeb6 100644 --- a/lib/Doctrine/Migrations/Metadata/ExecutedMigration.php +++ b/lib/Doctrine/Migrations/Metadata/ExecutedMigration.php @@ -13,7 +13,7 @@ class ExecutedMigration private $version; /** @var DateTime */ - private $executedOn; + private $executedAt; /** * Milliseconds @@ -22,10 +22,10 @@ class ExecutedMigration */ public $executionTime; - public function __construct(Version $version, ?DateTime $executedOn, ?int $executionTime) + public function __construct(Version $version, ?DateTime $executedAt, ?int $executionTime) { $this->version = $version; - $this->executedOn = $executedOn; + $this->executedAt = $executedAt; $this->executionTime = $executionTime; } @@ -34,9 +34,9 @@ public function getExecutionTime() : ?int return $this->executionTime; } - public function getExecutedOn() : ?DateTime + public function getExecutedAt() : ?DateTime { - return $this->executedOn; + return $this->executedAt; } public function getVersion() diff --git a/lib/Doctrine/Migrations/Metadata/MetadataStorage.php b/lib/Doctrine/Migrations/Metadata/Storage/MetadataStorage.php similarity index 70% rename from lib/Doctrine/Migrations/Metadata/MetadataStorage.php rename to lib/Doctrine/Migrations/Metadata/Storage/MetadataStorage.php index b82ab0f290..075fa30d5d 100644 --- a/lib/Doctrine/Migrations/Metadata/MetadataStorage.php +++ b/lib/Doctrine/Migrations/Metadata/Storage/MetadataStorage.php @@ -2,8 +2,9 @@ declare(strict_types=1); -namespace Doctrine\Migrations\Metadata; +namespace Doctrine\Migrations\Metadata\Storage; +use Doctrine\Migrations\Metadata\ExecutedMigrationsSet; use Doctrine\Migrations\Version\ExecutionResult; interface MetadataStorage diff --git a/lib/Doctrine/Migrations/Metadata/Storage/MetadataStorageConfigration.php b/lib/Doctrine/Migrations/Metadata/Storage/MetadataStorageConfigration.php new file mode 100644 index 0000000000..65c139a35b --- /dev/null +++ b/lib/Doctrine/Migrations/Metadata/Storage/MetadataStorageConfigration.php @@ -0,0 +1,9 @@ +connection = $connection; + $this->schemaManager = $connection->getSchemaManager(); + $this->platform = $connection->getDatabasePlatform(); + $this->configuration = $configuration ?: new TableMetadataStorageConfiguration(); + } + + private function isInitialized(): bool + { + if ($this->connection instanceof MasterSlaveConnection) { + $this->connection->connect('master'); + } + + return $this->schemaManager->tablesExist([$this->configuration->getTableName()]); + } + + private function initialize(): void + { + $schemaChangelog = new Table($this->configuration->getTableName()); + + $schemaChangelog->addColumn($this->configuration->getVersionColumnName(), 'string', ['notnull' => true, 'length' => $this->configuration->getVersionColumnName()]); + $schemaChangelog->addColumn($this->configuration->getExecutedAtColumnName(), 'datetime', ['notnull' => false]); + $schemaChangelog->addColumn($this->configuration->getExecutionTimeColumnName(), 'integer', ['notnull' => false]); + + $schemaChangelog->setPrimaryKey([$this->configuration->getVersionColumnName()]); + + $this->schemaManager->createTable($schemaChangelog); + } + + public function getExecutedMigrations(): ExecutedMigrationsSet + { + if (!$this->isInitialized()) { + $this->initialize(); + } + + $rows = $this->connection->fetchAll(sprintf('SELECT * FROM %s', $this->configuration->getTableName())); + + $migrations = []; + foreach ($rows as $row) { + $row = array_change_key_case($row, CASE_LOWER); + + $version = new Version($row[$this->configuration->getVersionColumnName()]); + + $executedAt = DateTime::createFromFormat( + $this->platform->getDateTimeFormatString(), + $row[$this->configuration->getExecutedAtColumnName()] + ); + + $migration = new ExecutedMigration( + $version, + $executedAt, + $row[$this->configuration->getExecutionTimeColumnName()] ? intval($row[$this->configuration->getExecutionTimeColumnName()]) : null + ); + + $migrations[(string)$version] = $migration; + } + + return new ExecutedMigrationsSet($migrations); + } + + public function complete(ExecutionResult $result): void + { + if ($result->getDirection() === Direction::DOWN) { + $this->connection->delete($this->configuration->getTableName(), [ + $this->configuration->getVersionColumnName() => (string)$result->getVersion(), + ]); + } else { + $this->connection->insert($this->configuration->getTableName(), [ + $this->configuration->getVersionColumnName() => (string)$result->getVersion(), + $this->configuration->getExecutedAtColumnName() => $result->getExecutedAt()->format($this->platform->getDateTimeFormatString()), + $this->configuration->getExecutionTimeColumnName() => $result->getTime(), + ]); + } + } +} diff --git a/lib/Doctrine/Migrations/Metadata/Storage/TableMetadataStorageConfiguration.php b/lib/Doctrine/Migrations/Metadata/Storage/TableMetadataStorageConfiguration.php new file mode 100644 index 0000000000..efc5f80dd6 --- /dev/null +++ b/lib/Doctrine/Migrations/Metadata/Storage/TableMetadataStorageConfiguration.php @@ -0,0 +1,99 @@ +tableName; + } + + /** + * @param string $tableName + */ + public function setTableName(string $tableName): void + { + $this->tableName = $tableName; + } + + /** + * @return string + */ + public function getVersionColumnName(): string + { + return $this->versionColumnName; + } + + /** + * @param string $versionColumnName + */ + public function setVersionColumnName(string $versionColumnName): void + { + $this->versionColumnName = $versionColumnName; + } + + /** + * @return int + */ + public function getVersionColumnLength(): int + { + return $this->versionColumnLength; + } + + /** + * @param int $versionColumnLength + */ + public function setVersionColumnLength(int $versionColumnLength): void + { + $this->versionColumnLength = $versionColumnLength; + } + + /** + * @return string + */ + public function getExecutedAtColumnName(): string + { + return $this->executedAtColumnName; + } + + /** + * @param string $executedAtColumnName + */ + public function setExecutedAtColumnName(string $executedAtColumnName): void + { + $this->executedAtColumnName = $executedAtColumnName; + } + + /** + * @return string + */ + public function getExecutionTimeColumnName(): string + { + return $this->executionTimeColumnName; + } + + /** + * @param string $executionTimeColumnName + */ + public function setExecutionTimeColumnName(string $executionTimeColumnName): void + { + $this->executionTimeColumnName = $executionTimeColumnName; + } + +} diff --git a/lib/Doctrine/Migrations/Metadata/TableMetadataStorage.php b/lib/Doctrine/Migrations/Metadata/TableMetadataStorage.php deleted file mode 100644 index f7a4381cd9..0000000000 --- a/lib/Doctrine/Migrations/Metadata/TableMetadataStorage.php +++ /dev/null @@ -1,100 +0,0 @@ -connection = $connection; - $this->schemaManager = $connection->getSchemaManager(); - $this->platform = $connection->getDatabasePlatform(); - } - - private function isInitialized() : bool - { - if ($this->connection instanceof MasterSlaveConnection) { - $this->connection->connect('master'); - } - - return $this->schemaManager->tablesExist(['schema_changelog']); - } - - private function initialize() : void - { - $schemaChangelog = new Table('schema_changelog'); - - $schemaChangelog->addColumn('version', 'string', ['notnull' => true]); - $schemaChangelog->addColumn('executed_on', 'datetime', ['notnull' => false]); - $schemaChangelog->addColumn('execution_time', 'integer', ['notnull' => false]); - - $schemaChangelog->setPrimaryKey(['version']); - - $this->schemaManager->createTable($schemaChangelog); - } - - public function getExecutedMigrations() : ExecutedMigrationsSet - { - if (! $this->isInitialized()) { - $this->initialize(); - } - - $rows = $this->connection->fetchAll('SELECT * FROM schema_changelog'); - - $migrations = []; - foreach ($rows as $row) { - $row = array_change_key_case($row, CASE_LOWER); - - $version = new Version($row['version']); - - $executedOn = DateTime::createFromFormat( - $this->platform->getDateTimeFormatString(), - $row['executed_on'] - ); - $migration = new ExecutedMigration($version, $executedOn, $row['execution_time']? intval($row['execution_time']) : null); - - $migrations[(string) $version] = $migration; - } - - return new ExecutedMigrationsSet($migrations); - } - - public function complete(ExecutionResult $result) : void - { - if ($result->getDirection() === Direction::DOWN) { - $this->connection->delete('schema_changelog', [ - 'version' => (string) $result->getVersion(), - ]); - } else { - $this->connection->insert('schema_changelog', [ - 'version' => (string) $result->getVersion(), - 'executed_on' => $result->getExecutedOn()->format($this->platform->getDateTimeFormatString()), - 'execution_time' => $result->getTime(), - ]); - } - } -} diff --git a/lib/Doctrine/Migrations/MigrationPlanCalculator.php b/lib/Doctrine/Migrations/MigrationPlanCalculator.php index f703d7a632..6c109707c5 100644 --- a/lib/Doctrine/Migrations/MigrationPlanCalculator.php +++ b/lib/Doctrine/Migrations/MigrationPlanCalculator.php @@ -5,7 +5,7 @@ namespace Doctrine\Migrations; use Doctrine\Migrations\Metadata\AvailableMigration; -use Doctrine\Migrations\Metadata\MetadataStorage; +use Doctrine\Migrations\Metadata\Storage\MetadataStorage; use Doctrine\Migrations\Metadata\MigrationPlan; use Doctrine\Migrations\Metadata\MigrationPlanList; use Doctrine\Migrations\Version\Direction; diff --git a/lib/Doctrine/Migrations/Tools/Console/Command/StatusCommand.php b/lib/Doctrine/Migrations/Tools/Console/Command/StatusCommand.php index 3f265f6f6e..a9bf51a421 100644 --- a/lib/Doctrine/Migrations/Tools/Console/Command/StatusCommand.php +++ b/lib/Doctrine/Migrations/Tools/Console/Command/StatusCommand.php @@ -136,8 +136,8 @@ private function showVersions( $status = $executedMigration ? 'migrated' : 'not migrated'; - $executedAtStatus = $executedMigration && $executedMigration->getExecutedOn() instanceof DateTimeImmutable - ? sprintf(' (executed at %s)', $executedMigration->getExecutedOn()->format('Y-m-d H:i:s')) + $executedAtStatus = $executedMigration && $executedMigration->getExecutedAt() instanceof DateTimeImmutable + ? sprintf(' (executed at %s)', $executedMigration->getExecutedAt()->format('Y-m-d H:i:s')) : ''; $description = $availableMigration->getMigration()->getDescription(); diff --git a/lib/Doctrine/Migrations/Tools/Console/Helper/ConfigurationHelper.php b/lib/Doctrine/Migrations/Tools/Console/Helper/ConfigurationHelper.php index 5d27a8b226..417b7f1c9b 100644 --- a/lib/Doctrine/Migrations/Tools/Console/Helper/ConfigurationHelper.php +++ b/lib/Doctrine/Migrations/Tools/Console/Helper/ConfigurationHelper.php @@ -4,9 +4,13 @@ namespace Doctrine\Migrations\Tools\Console\Helper; -use Doctrine\Migrations\Configuration\ArrayConfiguration; +use Doctrine\Migrations\Configuration\ArrayLoader; use Doctrine\Migrations\Configuration\Configuration; use Doctrine\Migrations\Configuration\JsonConfiguration; +use Doctrine\Migrations\Configuration\Loader\JsonFileLoader; +use Doctrine\Migrations\Configuration\Loader\PHPFileLoader; +use Doctrine\Migrations\Configuration\Loader\XmlFileLoader; +use Doctrine\Migrations\Configuration\Loader\YamlFileLoader; use Doctrine\Migrations\Configuration\XmlConfiguration; use Doctrine\Migrations\Configuration\YamlConfiguration; use Doctrine\Migrations\Tools\Console\Exception\FileTypeNotSupported; @@ -80,11 +84,11 @@ private function configExists(string $config) : bool private function loadConfig(string $config) : Configuration { $map = [ - 'xml' => XmlConfiguration::class, - 'yaml' => YamlConfiguration::class, - 'yml' => YamlConfiguration::class, - 'php' => ArrayConfiguration::class, - 'json' => JsonConfiguration::class, + 'xml' => new XmlFileLoader(), + 'yaml' => new YamlFileLoader(), + 'yml' => new YamlFileLoader(), + 'php' => new PHPFileLoader(), + 'json' => new JsonFileLoader(), ]; $info = pathinfo($config); @@ -94,11 +98,8 @@ private function loadConfig(string $config) : Configuration throw FileTypeNotSupported::new(); } - $class = $map[$info['extension']]; - $configuration = new $class(); - $configuration->load($config); - - return $configuration; + $loader = $map[$info['extension']]; + return $loader->load($config); } /** diff --git a/lib/Doctrine/Migrations/Tools/Console/Helper/MigrationStatusInfosHelper.php b/lib/Doctrine/Migrations/Tools/Console/Helper/MigrationStatusInfosHelper.php index 68c0826fcb..0d18fb0079 100644 --- a/lib/Doctrine/Migrations/Tools/Console/Helper/MigrationStatusInfosHelper.php +++ b/lib/Doctrine/Migrations/Tools/Console/Helper/MigrationStatusInfosHelper.php @@ -9,7 +9,7 @@ use Doctrine\Migrations\Configuration\Configuration; use Doctrine\Migrations\Metadata\AvailableMigrationsList; use Doctrine\Migrations\Metadata\ExecutedMigrationsSet; -use Doctrine\Migrations\Metadata\MetadataStorage; +use Doctrine\Migrations\Metadata\Storage\MetadataStorage; use Doctrine\Migrations\MigrationRepository; use Doctrine\Migrations\Version\AliasResolver; use function count; diff --git a/lib/Doctrine/Migrations/Version/AliasResolver.php b/lib/Doctrine/Migrations/Version/AliasResolver.php index e7fbdf7ed7..45ca0105b3 100644 --- a/lib/Doctrine/Migrations/Version/AliasResolver.php +++ b/lib/Doctrine/Migrations/Version/AliasResolver.php @@ -4,7 +4,7 @@ namespace Doctrine\Migrations\Version; -use Doctrine\Migrations\Metadata\MetadataStorage; +use Doctrine\Migrations\Metadata\Storage\MetadataStorage; use Doctrine\Migrations\MigrationRepository; use function substr; diff --git a/lib/Doctrine/Migrations/Version/ExecutionResult.php b/lib/Doctrine/Migrations/Version/ExecutionResult.php index 814e729618..60d5768adb 100644 --- a/lib/Doctrine/Migrations/Version/ExecutionResult.php +++ b/lib/Doctrine/Migrations/Version/ExecutionResult.php @@ -42,7 +42,7 @@ class ExecutionResult private $exception; /** @var DateTime */ - private $executedOn; + private $executedAt; /** @var int */ private $state; @@ -61,9 +61,9 @@ class ExecutionResult * @param mixed[] $params * @param mixed[] $types */ - public function __construct(Version $version, string $direction, ?DateTime $executedOn = null) + public function __construct(Version $version, string $direction, ?DateTime $executedAt = null) { - $this->executedOn = $executedOn ?: new DateTime(); + $this->executedAt = $executedAt ?: new DateTime(); $this->version = $version; $this->direction = $direction; } @@ -73,14 +73,14 @@ public function getDirection() : string return $this->direction; } - public function getExecutedOn() : DateTime + public function getExecutedAt() : DateTime { - return $this->executedOn; + return $this->executedAt; } - public function setExecutedOn(DateTime $executedOn) : void + public function setExecutedAt(DateTime $executedAt) : void { - $this->executedOn = $executedOn; + $this->executedAt = $executedAt; } public function getVersion() : Version diff --git a/lib/Doctrine/Migrations/Version/Executor.php b/lib/Doctrine/Migrations/Version/Executor.php index 878af0fda5..7db3fec6ff 100644 --- a/lib/Doctrine/Migrations/Version/Executor.php +++ b/lib/Doctrine/Migrations/Version/Executor.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\EventDispatcher; use Doctrine\Migrations\Events; use Doctrine\Migrations\Exception\SkipMigration; -use Doctrine\Migrations\Metadata\MetadataStorage; +use Doctrine\Migrations\Metadata\Storage\MetadataStorage; use Doctrine\Migrations\Metadata\MigrationPlan; use Doctrine\Migrations\MigratorConfiguration; use Doctrine\Migrations\ParameterFormatterInterface;