DoctrineMigrationsExtension.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\Bundle\MigrationsBundle\DependencyInjection;
  4. use Doctrine\Bundle\MigrationsBundle\Collector\MigrationsCollector;
  5. use Doctrine\Bundle\MigrationsBundle\Collector\MigrationsFlattener;
  6. use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
  7. use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
  8. use Doctrine\Migrations\Version\MigrationFactory;
  9. use InvalidArgumentException;
  10. use RuntimeException;
  11. use Symfony\Component\Config\FileLocator;
  12. use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  13. use Symfony\Component\DependencyInjection\ContainerBuilder;
  14. use Symfony\Component\DependencyInjection\Definition;
  15. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  16. use Symfony\Component\DependencyInjection\Reference;
  17. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  18. use function array_keys;
  19. use function assert;
  20. use function explode;
  21. use function implode;
  22. use function is_array;
  23. use function sprintf;
  24. use function strlen;
  25. use function substr;
  26. /**
  27. * DoctrineMigrationsExtension.
  28. */
  29. class DoctrineMigrationsExtension extends Extension
  30. {
  31. /**
  32. * Responds to the migrations configuration parameter.
  33. *
  34. * @param mixed[][] $configs
  35. *
  36. * @psalm-param array<string, array<string, array<string, string>|string>>> $configs
  37. */
  38. public function load(array $configs, ContainerBuilder $container): void
  39. {
  40. $configuration = new Configuration();
  41. $config = $this->processConfiguration($configuration, $configs);
  42. $locator = new FileLocator(__DIR__ . '/../Resources/config/');
  43. $loader = new XmlFileLoader($container, $locator);
  44. $loader->load('services.xml');
  45. $configurationDefinition = $container->getDefinition('doctrine.migrations.configuration');
  46. foreach ($config['migrations_paths'] as $ns => $path) {
  47. $path = $this->checkIfBundleRelativePath($path, $container);
  48. $configurationDefinition->addMethodCall('addMigrationsDirectory', [$ns, $path]);
  49. }
  50. foreach ($config['migrations'] as $migrationClass) {
  51. $configurationDefinition->addMethodCall('addMigrationClass', [$migrationClass]);
  52. }
  53. if ($config['organize_migrations'] !== false) {
  54. $configurationDefinition->addMethodCall('setMigrationOrganization', [$config['organize_migrations']]);
  55. }
  56. if ($config['custom_template'] !== null) {
  57. $configurationDefinition->addMethodCall('setCustomTemplate', [$config['custom_template']]);
  58. }
  59. $configurationDefinition->addMethodCall('setAllOrNothing', [$config['all_or_nothing']]);
  60. $configurationDefinition->addMethodCall('setCheckDatabasePlatform', [$config['check_database_platform']]);
  61. if ($config['enable_profiler']) {
  62. $this->registerCollector($container);
  63. }
  64. $diDefinition = $container->getDefinition('doctrine.migrations.dependency_factory');
  65. if (! isset($config['services'][MigrationFactory::class])) {
  66. $config['services'][MigrationFactory::class] = 'doctrine.migrations.migrations_factory';
  67. }
  68. foreach ($config['services'] as $doctrineId => $symfonyId) {
  69. $diDefinition->addMethodCall('setDefinition', [$doctrineId, new ServiceClosureArgument(new Reference($symfonyId))]);
  70. }
  71. foreach ($config['factories'] as $doctrineId => $symfonyId) {
  72. $diDefinition->addMethodCall('setDefinition', [$doctrineId, new Reference($symfonyId)]);
  73. }
  74. if (! isset($config['services'][MetadataStorage::class])) {
  75. $storageConfiguration = $config['storage']['table_storage'];
  76. $storageDefinition = new Definition(TableMetadataStorageConfiguration::class);
  77. $container->setDefinition('doctrine.migrations.storage.table_storage', $storageDefinition);
  78. $container->setAlias('doctrine.migrations.metadata_storage', 'doctrine.migrations.storage.table_storage');
  79. if ($storageConfiguration['table_name'] !== null) {
  80. $storageDefinition->addMethodCall('setTableName', [$storageConfiguration['table_name']]);
  81. }
  82. if ($storageConfiguration['version_column_name'] !== null) {
  83. $storageDefinition->addMethodCall('setVersionColumnName', [$storageConfiguration['version_column_name']]);
  84. }
  85. if ($storageConfiguration['version_column_length'] !== null) {
  86. $storageDefinition->addMethodCall('setVersionColumnLength', [$storageConfiguration['version_column_length']]);
  87. }
  88. if ($storageConfiguration['executed_at_column_name'] !== null) {
  89. $storageDefinition->addMethodCall('setExecutedAtColumnName', [$storageConfiguration['executed_at_column_name']]);
  90. }
  91. if ($storageConfiguration['execution_time_column_name'] !== null) {
  92. $storageDefinition->addMethodCall('setExecutionTimeColumnName', [$storageConfiguration['execution_time_column_name']]);
  93. }
  94. $configurationDefinition->addMethodCall('setMetadataStorageConfiguration', [new Reference('doctrine.migrations.storage.table_storage')]);
  95. }
  96. if ($config['em'] !== null && $config['connection'] !== null) {
  97. throw new InvalidArgumentException(
  98. 'You cannot specify both "connection" and "em" in the DoctrineMigrationsBundle configurations.'
  99. );
  100. }
  101. $container->setParameter('doctrine.migrations.preferred_em', $config['em']);
  102. $container->setParameter('doctrine.migrations.preferred_connection', $config['connection']);
  103. }
  104. private function checkIfBundleRelativePath(string $path, ContainerBuilder $container): string
  105. {
  106. if (isset($path[0]) && $path[0] === '@') {
  107. $pathParts = explode('/', $path);
  108. $bundleName = substr($pathParts[0], 1);
  109. $bundlePath = $this->getBundlePath($bundleName, $container);
  110. return $bundlePath . substr($path, strlen('@' . $bundleName));
  111. }
  112. return $path;
  113. }
  114. private function getBundlePath(string $bundleName, ContainerBuilder $container): string
  115. {
  116. $bundleMetadata = $container->getParameter('kernel.bundles_metadata');
  117. assert(is_array($bundleMetadata));
  118. if (! isset($bundleMetadata[$bundleName])) {
  119. throw new RuntimeException(sprintf(
  120. 'The bundle "%s" has not been registered, available bundles: %s',
  121. $bundleName,
  122. implode(', ', array_keys($bundleMetadata))
  123. ));
  124. }
  125. return $bundleMetadata[$bundleName]['path'];
  126. }
  127. private function registerCollector(ContainerBuilder $container): void
  128. {
  129. $flattenerDefinition = new Definition(MigrationsFlattener::class);
  130. $container->setDefinition('doctrine_migrations.migrations_flattener', $flattenerDefinition);
  131. $collectorDefinition = new Definition(MigrationsCollector::class, [
  132. new Reference('doctrine.migrations.dependency_factory'),
  133. new Reference('doctrine_migrations.migrations_flattener'),
  134. ]);
  135. $collectorDefinition
  136. ->addTag('data_collector', [
  137. 'template' => '@DoctrineMigrations/Collector/migrations.html.twig',
  138. 'id' => 'doctrine_migrations',
  139. 'priority' => '249',
  140. ]);
  141. $container->setDefinition('doctrine_migrations.migrations_collector', $collectorDefinition);
  142. }
  143. /**
  144. * Returns the base path for the XSD files.
  145. *
  146. * @return string The XSD base path
  147. */
  148. public function getXsdValidationBasePath(): string
  149. {
  150. return __DIR__ . '/../Resources/config/schema';
  151. }
  152. public function getNamespace(): string
  153. {
  154. return 'http://symfony.com/schema/dic/doctrine/migrations/3.0';
  155. }
  156. }