Skip to content

Commit d2f8cb8

Browse files
committed
Add service migrations
1 parent bc599a5 commit d2f8cb8

File tree

6 files changed

+234
-2
lines changed

6 files changed

+234
-2
lines changed

config/services.xml

+40
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
<argument type="service" id="doctrine.migrations.configuration_loader"/>
1212
<argument></argument>
1313
<argument type="service" id="logger" on-invalid="null"></argument>
14+
<call method="setDefinition">
15+
<argument>Doctrine\Migrations\Finder\MigrationFinder</argument>
16+
<argument type="service_closure" id="doctrine.migrations.migration_finder" />
17+
</call>
18+
<call method="setDefinition">
19+
<argument>Doctrine\Migrations\MigrationsRepository</argument>
20+
<argument type="service_closure" id="doctrine.migrations.migrations_repository" />
21+
</call>
1422
</service>
1523

1624
<service id="doctrine.migrations.configuration_loader" class="Doctrine\Migrations\Configuration\Migration\ExistingConfiguration" public="false">
@@ -146,6 +154,38 @@
146154
<tag name="console.command" command="doctrine:migrations:version" />
147155
</service>
148156

157+
<service id="doctrine.migrations.connection" class="Doctrine\DBAL\Connection">
158+
<factory service="doctrine.migrations.dependency_factory" method="getConnection" />
159+
</service>
160+
161+
<service id="doctrine.migrations.logger" class="Psr\Log\LoggerInterface">
162+
<factory service="doctrine.migrations.dependency_factory" method="getLogger" />
163+
</service>
164+
165+
<service id="doctrine.migrations.migration_finder" class="Doctrine\Migrations\Finder\MigrationFinder">
166+
<factory service="doctrine.migrations.dependency_factory" method="getMigrationsFinder" />
167+
</service>
168+
169+
<service id="doctrine.migrations.filter_service_migration_finder"
170+
class="Doctrine\Bundle\MigrationsBundle\MigrationFinder\FilterServiceMigrationFinder"
171+
decorates="doctrine.migrations.migration_finder"
172+
>
173+
<argument id="doctrine.migrations.filter_service_migration_finder.inner" type="service" />
174+
<argument type="abstract">migrations locator</argument>
175+
</service>
176+
177+
<service id="doctrine.migrations.migrations_repository" class="Doctrine\Migrations\MigrationsRepository">
178+
<factory service="doctrine.migrations.dependency_factory" method="getMigrationRepository" />
179+
</service>
180+
181+
<service id="doctrine.migrations.service_migrations_repository"
182+
class="Doctrine\Bundle\MigrationsBundle\MigrationsRepository\ServiceMigrationsRepository"
183+
decorates="doctrine.migrations.migrations_repository"
184+
>
185+
<argument id="doctrine.migrations.service_migrations_repository.inner" type="service" />
186+
<argument type="abstract">migrations locator</argument>
187+
</service>
188+
149189
</services>
150190

151191
</container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Bundle\MigrationsBundle\DependencyInjection\CompilerPass;
6+
7+
use Doctrine\DBAL\Connection;
8+
use Psr\Log\LoggerInterface;
9+
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
10+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
11+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
12+
use Symfony\Component\DependencyInjection\ContainerBuilder;
13+
use Symfony\Component\DependencyInjection\Reference;
14+
use Symfony\Component\DependencyInjection\TypedReference;
15+
16+
class RegisterMigrationsPass implements CompilerPassInterface
17+
{
18+
public function process(ContainerBuilder $container): void
19+
{
20+
$migrationRefs = [];
21+
22+
foreach ($container->findTaggedServiceIds('doctrine_migrations.migration', true) as $id => $attributes) {
23+
$definition = $container->getDefinition($id);
24+
$definition->setBindings([
25+
Connection::class => new BoundArgument(new Reference('doctrine.migrations.connection')),
26+
LoggerInterface::class => new BoundArgument(new Reference('doctrine.migrations.logger')),
27+
]);
28+
29+
$migrationRefs[$id] = new TypedReference($id, $definition->getClass());
30+
}
31+
32+
if ($migrationRefs !== []) {
33+
$container->getDefinition('doctrine.migrations.filter_service_migration_finder')
34+
->replaceArgument(1, new ServiceLocatorArgument($migrationRefs));
35+
$container->getDefinition('doctrine.migrations.service_migrations_repository')
36+
->replaceArgument(1, new ServiceLocatorArgument($migrationRefs));
37+
} else {
38+
$container->removeDefinition('doctrine.migrations.connection');
39+
$container->removeDefinition('doctrine.migrations.logger');
40+
$container->removeDefinition('doctrine.migrations.filter_service_migration_finder');
41+
$container->removeDefinition('doctrine.migrations.service_migrations_repository');
42+
}
43+
}
44+
}

src/DependencyInjection/DoctrineMigrationsExtension.php

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Doctrine\Bundle\MigrationsBundle\Collector\MigrationsCollector;
88
use Doctrine\Bundle\MigrationsBundle\Collector\MigrationsFlattener;
9+
use Doctrine\Migrations\AbstractMigration;
910
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
1011
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
1112
use Doctrine\Migrations\Version\MigrationFactory;
@@ -48,6 +49,9 @@ public function load(array $configs, ContainerBuilder $container): void
4849

4950
$loader->load('services.xml');
5051

52+
$container->registerForAutoconfiguration(AbstractMigration::class)
53+
->addTag('doctrine_migrations.migration');
54+
5155
$configurationDefinition = $container->getDefinition('doctrine.migrations.configuration');
5256

5357
foreach ($config['migrations_paths'] as $ns => $path) {

src/DoctrineMigrationsBundle.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
namespace Doctrine\Bundle\MigrationsBundle;
66

77
use Doctrine\Bundle\MigrationsBundle\DependencyInjection\CompilerPass\ConfigureDependencyFactoryPass;
8+
use Doctrine\Bundle\MigrationsBundle\DependencyInjection\CompilerPass\RegisterMigrationsPass;
89
use Symfony\Component\DependencyInjection\ContainerBuilder;
910
use Symfony\Component\HttpKernel\Bundle\Bundle;
1011

1112
use function dirname;
1213

1314
class DoctrineMigrationsBundle extends Bundle
1415
{
15-
/** @return void */
16-
public function build(ContainerBuilder $container)
16+
public function build(ContainerBuilder $container): void
1717
{
1818
$container->addCompilerPass(new ConfigureDependencyFactoryPass());
19+
$container->addCompilerPass(new RegisterMigrationsPass());
1920
}
2021

2122
public function getPath(): string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Bundle\MigrationsBundle\MigrationFinder;
6+
7+
use Doctrine\Migrations\Finder\MigrationFinder;
8+
use Psr\Container\ContainerInterface;
9+
10+
use function array_values;
11+
12+
final class FilterServiceMigrationFinder implements MigrationFinder
13+
{
14+
/** @var MigrationFinder */
15+
private $migrationFinder;
16+
17+
/** @var ContainerInterface */
18+
private $container;
19+
20+
public function __construct(MigrationFinder $migrationFinder, ContainerInterface $container)
21+
{
22+
$this->migrationFinder = $migrationFinder;
23+
$this->container = $container;
24+
}
25+
26+
/**
27+
* {@inheritDoc}
28+
*/
29+
public function findMigrations(string $directory, ?string $namespace = null): array
30+
{
31+
$migrations = $this->migrationFinder->findMigrations(
32+
$directory,
33+
$namespace
34+
);
35+
36+
foreach ($migrations as $i => $migration) {
37+
if (! $this->container->has($migration)) {
38+
continue;
39+
}
40+
41+
unset($migrations[$i]);
42+
}
43+
44+
return array_values($migrations);
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Bundle\MigrationsBundle\MigrationsRepository;
6+
7+
use Doctrine\Migrations\AbstractMigration;
8+
use Doctrine\Migrations\Exception\DuplicateMigrationVersion;
9+
use Doctrine\Migrations\Metadata\AvailableMigration;
10+
use Doctrine\Migrations\Metadata\AvailableMigrationsSet;
11+
use Doctrine\Migrations\MigrationsRepository;
12+
use Doctrine\Migrations\Version\Version;
13+
use Symfony\Contracts\Service\ServiceProviderInterface;
14+
15+
use function assert;
16+
17+
class ServiceMigrationsRepository implements MigrationsRepository
18+
{
19+
/** @var MigrationsRepository */
20+
private $migrationRepository;
21+
22+
/** @var ServiceProviderInterface<AbstractMigration> */
23+
private $container;
24+
25+
/** @var AvailableMigration[] */
26+
private $migrations = [];
27+
28+
/** @param ServiceProviderInterface<AbstractMigration> $container */
29+
public function __construct(
30+
MigrationsRepository $migrationRepository,
31+
ServiceProviderInterface $container
32+
) {
33+
$this->migrationRepository = $migrationRepository;
34+
$this->container = $container;
35+
}
36+
37+
public function hasMigration(string $version): bool
38+
{
39+
return $this->container->has($version) || $this->migrationRepository->hasMigration($version);
40+
}
41+
42+
public function getMigration(Version $version): AvailableMigration
43+
{
44+
if (! isset($this->migrations[(string) $version]) && ! $this->loadMigrationFromContainer($version)) {
45+
return $this->migrationRepository->getMigration($version);
46+
}
47+
48+
return $this->migrations[(string) $version];
49+
}
50+
51+
/**
52+
* Returns a non-sorted set of migrations.
53+
*/
54+
public function getMigrations(): AvailableMigrationsSet
55+
{
56+
$this->loadMigrationsFromContainer();
57+
58+
$migrations = $this->migrations;
59+
foreach ($this->migrationRepository->getMigrations()->getItems() as $availableMigration) {
60+
$version = $availableMigration->getVersion();
61+
62+
if (isset($migrations[(string) $version])) {
63+
throw DuplicateMigrationVersion::new(
64+
(string) $version,
65+
(string) $version
66+
);
67+
}
68+
69+
$migrations[(string) $version] = $availableMigration;
70+
}
71+
72+
return new AvailableMigrationsSet($migrations);
73+
}
74+
75+
private function loadMigrationsFromContainer(): void
76+
{
77+
foreach ($this->container->getProvidedServices() as $id) {
78+
if (isset($this->migrations[$id])) {
79+
continue;
80+
}
81+
82+
$this->loadMigrationFromContainer(new Version($id));
83+
}
84+
}
85+
86+
private function loadMigrationFromContainer(Version $version): bool
87+
{
88+
if (! $this->container->has((string) $version)) {
89+
return false;
90+
}
91+
92+
$migration = $this->container->get((string) $version);
93+
$this->migrations[(string) $version] = new AvailableMigration($version, $migration);
94+
95+
return true;
96+
}
97+
}

0 commit comments

Comments
 (0)