From cf481fcd3fed6863655dcae42f53b12f9999c05c Mon Sep 17 00:00:00 2001 From: HypeMC Date: Mon, 26 Feb 2024 02:41:34 +0100 Subject: [PATCH] Add service migrations --- config/services.xml | 40 ++++++++ .../CompilerPass/RegisterMigrationsPass.php | 44 +++++++++ .../DoctrineMigrationsExtension.php | 4 + src/DoctrineMigrationsBundle.php | 5 +- .../FilterServiceMigrationFinder.php | 46 +++++++++ .../ServiceMigrationsRepository.php | 95 +++++++++++++++++++ 6 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 src/DependencyInjection/CompilerPass/RegisterMigrationsPass.php create mode 100644 src/MigrationFinder/FilterServiceMigrationFinder.php create mode 100644 src/MigrationsRepository/ServiceMigrationsRepository.php diff --git a/config/services.xml b/config/services.xml index cb97871..b0e3154 100644 --- a/config/services.xml +++ b/config/services.xml @@ -11,6 +11,14 @@ + + Doctrine\Migrations\Finder\MigrationFinder + + + + Doctrine\Migrations\MigrationsRepository + + @@ -146,6 +154,38 @@ + + + + + + + + + + + + + + + migrations locator + + + + + + + + + migrations locator + + diff --git a/src/DependencyInjection/CompilerPass/RegisterMigrationsPass.php b/src/DependencyInjection/CompilerPass/RegisterMigrationsPass.php new file mode 100644 index 0000000..b4795b9 --- /dev/null +++ b/src/DependencyInjection/CompilerPass/RegisterMigrationsPass.php @@ -0,0 +1,44 @@ +findTaggedServiceIds('doctrine_migrations.migration', true) as $id => $attributes) { + $definition = $container->getDefinition($id); + $definition->setBindings([ + Connection::class => new BoundArgument(new Reference('doctrine.migrations.connection')), + LoggerInterface::class => new BoundArgument(new Reference('doctrine.migrations.logger')), + ]); + + $migrationRefs[$id] = new TypedReference($id, $definition->getClass()); + } + + if ($migrationRefs !== []) { + $container->getDefinition('doctrine.migrations.filter_service_migration_finder') + ->replaceArgument(1, new ServiceLocatorArgument($migrationRefs)); + $container->getDefinition('doctrine.migrations.service_migrations_repository') + ->replaceArgument(1, new ServiceLocatorArgument($migrationRefs)); + } else { + $container->removeDefinition('doctrine.migrations.connection'); + $container->removeDefinition('doctrine.migrations.logger'); + $container->removeDefinition('doctrine.migrations.filter_service_migration_finder'); + $container->removeDefinition('doctrine.migrations.service_migrations_repository'); + } + } +} diff --git a/src/DependencyInjection/DoctrineMigrationsExtension.php b/src/DependencyInjection/DoctrineMigrationsExtension.php index 0bdb905..75a8131 100644 --- a/src/DependencyInjection/DoctrineMigrationsExtension.php +++ b/src/DependencyInjection/DoctrineMigrationsExtension.php @@ -6,6 +6,7 @@ use Doctrine\Bundle\MigrationsBundle\Collector\MigrationsCollector; use Doctrine\Bundle\MigrationsBundle\Collector\MigrationsFlattener; +use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\Metadata\Storage\MetadataStorage; use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration; use Doctrine\Migrations\Version\MigrationFactory; @@ -48,6 +49,9 @@ public function load(array $configs, ContainerBuilder $container): void $loader->load('services.xml'); + $container->registerForAutoconfiguration(AbstractMigration::class) + ->addTag('doctrine_migrations.migration'); + $configurationDefinition = $container->getDefinition('doctrine.migrations.configuration'); foreach ($config['migrations_paths'] as $ns => $path) { diff --git a/src/DoctrineMigrationsBundle.php b/src/DoctrineMigrationsBundle.php index 6b3f22f..648bdb8 100644 --- a/src/DoctrineMigrationsBundle.php +++ b/src/DoctrineMigrationsBundle.php @@ -5,6 +5,7 @@ namespace Doctrine\Bundle\MigrationsBundle; use Doctrine\Bundle\MigrationsBundle\DependencyInjection\CompilerPass\ConfigureDependencyFactoryPass; +use Doctrine\Bundle\MigrationsBundle\DependencyInjection\CompilerPass\RegisterMigrationsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -12,10 +13,10 @@ class DoctrineMigrationsBundle extends Bundle { - /** @return void */ - public function build(ContainerBuilder $container) + public function build(ContainerBuilder $container): void { $container->addCompilerPass(new ConfigureDependencyFactoryPass()); + $container->addCompilerPass(new RegisterMigrationsPass()); } public function getPath(): string diff --git a/src/MigrationFinder/FilterServiceMigrationFinder.php b/src/MigrationFinder/FilterServiceMigrationFinder.php new file mode 100644 index 0000000..53860da --- /dev/null +++ b/src/MigrationFinder/FilterServiceMigrationFinder.php @@ -0,0 +1,46 @@ +migrationFinder = $migrationFinder; + $this->container = $container; + } + + /** + * {@inheritDoc} + */ + public function findMigrations(string $directory, ?string $namespace = null): array + { + $migrations = $this->migrationFinder->findMigrations( + $directory, + $namespace + ); + + foreach ($migrations as $i => $migration) { + if (! $this->container->has($migration)) { + continue; + } + + unset($migrations[$i]); + } + + return array_values($migrations); + } +} diff --git a/src/MigrationsRepository/ServiceMigrationsRepository.php b/src/MigrationsRepository/ServiceMigrationsRepository.php new file mode 100644 index 0000000..43ebf30 --- /dev/null +++ b/src/MigrationsRepository/ServiceMigrationsRepository.php @@ -0,0 +1,95 @@ + */ + private $container; + + /** @var AvailableMigration[] */ + private $migrations = []; + + /** @param ServiceProviderInterface $container */ + public function __construct( + MigrationsRepository $migrationRepository, + ServiceProviderInterface $container + ) { + $this->migrationRepository = $migrationRepository; + $this->container = $container; + } + + public function hasMigration(string $version): bool + { + return $this->container->has($version) || $this->migrationRepository->hasMigration($version); + } + + public function getMigration(Version $version): AvailableMigration + { + if (! isset($this->migrations[(string) $version]) && ! $this->loadMigrationFromContainer($version)) { + return $this->migrationRepository->getMigration($version); + } + + return $this->migrations[(string) $version]; + } + + /** + * Returns a non-sorted set of migrations. + */ + public function getMigrations(): AvailableMigrationsSet + { + $this->loadMigrationsFromContainer(); + + $migrations = $this->migrations; + foreach ($this->migrationRepository->getMigrations()->getItems() as $availableMigration) { + $version = $availableMigration->getVersion(); + + if (isset($migrations[(string) $version])) { + throw DuplicateMigrationVersion::new( + (string) $version, + (string) $version + ); + } + + $migrations[(string) $version] = $availableMigration; + } + + return new AvailableMigrationsSet($migrations); + } + + private function loadMigrationsFromContainer(): void + { + foreach ($this->container->getProvidedServices() as $id) { + if (isset($this->migrations[$id])) { + continue; + } + + $this->loadMigrationFromContainer(new Version($id)); + } + } + + private function loadMigrationFromContainer(Version $version): bool + { + if (! $this->container->has((string) $version)) { + return false; + } + + $migration = $this->container->get((string) $version); + $this->migrations[(string) $version] = new AvailableMigration($version, $migration); + + return true; + } +}