vendor/doctrine/migrations/lib/Doctrine/Migrations/DependencyFactory.php line 374

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\Migrations;
  4. use Doctrine\DBAL\Connection;
  5. use Doctrine\DBAL\Platforms\AbstractPlatform;
  6. use Doctrine\DBAL\Schema\AbstractSchemaManager;
  7. use Doctrine\Migrations\Configuration\Configuration;
  8. use Doctrine\Migrations\Configuration\Connection\ConnectionLoader;
  9. use Doctrine\Migrations\Configuration\EntityManager\EntityManagerLoader;
  10. use Doctrine\Migrations\Configuration\Migration\ConfigurationLoader;
  11. use Doctrine\Migrations\Exception\FrozenDependencies;
  12. use Doctrine\Migrations\Exception\MissingDependency;
  13. use Doctrine\Migrations\Finder\GlobFinder;
  14. use Doctrine\Migrations\Finder\MigrationFinder;
  15. use Doctrine\Migrations\Finder\RecursiveRegexFinder;
  16. use Doctrine\Migrations\Generator\ClassNameGenerator;
  17. use Doctrine\Migrations\Generator\ConcatenationFileBuilder;
  18. use Doctrine\Migrations\Generator\DiffGenerator;
  19. use Doctrine\Migrations\Generator\FileBuilder;
  20. use Doctrine\Migrations\Generator\Generator;
  21. use Doctrine\Migrations\Generator\SqlGenerator;
  22. use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
  23. use Doctrine\Migrations\Metadata\Storage\TableMetadataStorage;
  24. use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
  25. use Doctrine\Migrations\Provider\DBALSchemaDiffProvider;
  26. use Doctrine\Migrations\Provider\EmptySchemaProvider;
  27. use Doctrine\Migrations\Provider\LazySchemaDiffProvider;
  28. use Doctrine\Migrations\Provider\OrmSchemaProvider;
  29. use Doctrine\Migrations\Provider\SchemaDiffProvider;
  30. use Doctrine\Migrations\Provider\SchemaProvider;
  31. use Doctrine\Migrations\Tools\Console\ConsoleInputMigratorConfigurationFactory;
  32. use Doctrine\Migrations\Tools\Console\Helper\MigrationStatusInfosHelper;
  33. use Doctrine\Migrations\Tools\Console\MigratorConfigurationFactory;
  34. use Doctrine\Migrations\Version\AliasResolver;
  35. use Doctrine\Migrations\Version\AlphabeticalComparator;
  36. use Doctrine\Migrations\Version\Comparator;
  37. use Doctrine\Migrations\Version\CurrentMigrationStatusCalculator;
  38. use Doctrine\Migrations\Version\DbalExecutor;
  39. use Doctrine\Migrations\Version\DbalMigrationFactory;
  40. use Doctrine\Migrations\Version\DefaultAliasResolver;
  41. use Doctrine\Migrations\Version\Executor;
  42. use Doctrine\Migrations\Version\MigrationFactory;
  43. use Doctrine\Migrations\Version\MigrationPlanCalculator;
  44. use Doctrine\Migrations\Version\MigrationStatusCalculator;
  45. use Doctrine\Migrations\Version\SortedMigrationPlanCalculator;
  46. use Doctrine\ORM\EntityManagerInterface;
  47. use Psr\Log\LoggerInterface;
  48. use Psr\Log\NullLogger;
  49. use Symfony\Component\Stopwatch\Stopwatch;
  50. use function array_key_exists;
  51. use function call_user_func;
  52. use function method_exists;
  53. use function preg_quote;
  54. use function sprintf;
  55. /**
  56.  * The DependencyFactory is responsible for wiring up and managing internal class dependencies.
  57.  */
  58. class DependencyFactory
  59. {
  60.     /** @psalm-var array<string, bool> */
  61.     private $inResolution = [];
  62.     /** @var Configuration */
  63.     private $configuration;
  64.     /** @var object[]|callable[] */
  65.     private $dependencies = [];
  66.     /** @var Connection */
  67.     private $connection;
  68.     /** @var EntityManagerInterface|null */
  69.     private $em;
  70.     /** @var bool */
  71.     private $frozen false;
  72.     /** @var ConfigurationLoader */
  73.     private $configurationLoader;
  74.     /** @var ConnectionLoader */
  75.     private $connectionLoader;
  76.     /** @var EntityManagerLoader|null */
  77.     private $emLoader;
  78.     /** @var callable[] */
  79.     private $factories = [];
  80.     public static function fromConnection(
  81.         ConfigurationLoader $configurationLoader,
  82.         ConnectionLoader $connectionLoader,
  83.         ?LoggerInterface $logger null
  84.     ): self {
  85.         $dependencyFactory                      = new self($logger);
  86.         $dependencyFactory->configurationLoader $configurationLoader;
  87.         $dependencyFactory->connectionLoader    $connectionLoader;
  88.         return $dependencyFactory;
  89.     }
  90.     public static function fromEntityManager(
  91.         ConfigurationLoader $configurationLoader,
  92.         EntityManagerLoader $emLoader,
  93.         ?LoggerInterface $logger null
  94.     ): self {
  95.         $dependencyFactory                      = new self($logger);
  96.         $dependencyFactory->configurationLoader $configurationLoader;
  97.         $dependencyFactory->emLoader            $emLoader;
  98.         return $dependencyFactory;
  99.     }
  100.     private function __construct(?LoggerInterface $logger)
  101.     {
  102.         if ($logger === null) {
  103.             return;
  104.         }
  105.         $this->setDefinition(LoggerInterface::class, static function () use ($logger): LoggerInterface {
  106.             return $logger;
  107.         });
  108.     }
  109.     public function isFrozen(): bool
  110.     {
  111.         return $this->frozen;
  112.     }
  113.     public function freeze(): void
  114.     {
  115.         $this->frozen true;
  116.     }
  117.     private function assertNotFrozen(): void
  118.     {
  119.         if ($this->frozen) {
  120.             throw FrozenDependencies::new();
  121.         }
  122.     }
  123.     public function hasEntityManager(): bool
  124.     {
  125.         return $this->emLoader !== null;
  126.     }
  127.     public function setConfigurationLoader(ConfigurationLoader $configurationLoader): void
  128.     {
  129.         $this->assertNotFrozen();
  130.         $this->configurationLoader $configurationLoader;
  131.     }
  132.     public function getConfiguration(): Configuration
  133.     {
  134.         if ($this->configuration === null) {
  135.             $this->configuration $this->configurationLoader->getConfiguration();
  136.             $this->freeze();
  137.         }
  138.         return $this->configuration;
  139.     }
  140.     public function getConnection(): Connection
  141.     {
  142.         if ($this->connection === null) {
  143.             $this->connection $this->hasEntityManager()
  144.                 ? $this->getEntityManager()->getConnection()
  145.                 : $this->connectionLoader->getConnection($this->getConfiguration()->getConnectionName());
  146.             $this->freeze();
  147.         }
  148.         return $this->connection;
  149.     }
  150.     public function getEntityManager(): EntityManagerInterface
  151.     {
  152.         if ($this->em === null) {
  153.             if ($this->emLoader === null) {
  154.                 throw MissingDependency::noEntityManager();
  155.             }
  156.             $this->em $this->emLoader->getEntityManager($this->getConfiguration()->getEntityManagerName());
  157.             $this->freeze();
  158.         }
  159.         return $this->em;
  160.     }
  161.     public function getVersionComparator(): Comparator
  162.     {
  163.         return $this->getDependency(Comparator::class, static function (): AlphabeticalComparator {
  164.             return new AlphabeticalComparator();
  165.         });
  166.     }
  167.     public function getLogger(): LoggerInterface
  168.     {
  169.         return $this->getDependency(LoggerInterface::class, static function (): LoggerInterface {
  170.             return new NullLogger();
  171.         });
  172.     }
  173.     public function getEventDispatcher(): EventDispatcher
  174.     {
  175.         return $this->getDependency(EventDispatcher::class, function (): EventDispatcher {
  176.             return new EventDispatcher(
  177.                 $this->getConnection(),
  178.                 $this->getConnection()->getEventManager()
  179.             );
  180.         });
  181.     }
  182.     public function getClassNameGenerator(): ClassNameGenerator
  183.     {
  184.         return $this->getDependency(ClassNameGenerator::class, static function (): ClassNameGenerator {
  185.             return new ClassNameGenerator();
  186.         });
  187.     }
  188.     public function getSchemaDumper(): SchemaDumper
  189.     {
  190.         return $this->getDependency(SchemaDumper::class, function (): SchemaDumper {
  191.             $excludedTables = [];
  192.             $metadataConfig $this->getConfiguration()->getMetadataStorageConfiguration();
  193.             if ($metadataConfig instanceof TableMetadataStorageConfiguration) {
  194.                 $excludedTables[] = sprintf('/^%s$/'preg_quote($metadataConfig->getTableName(), '/'));
  195.             }
  196.             return new SchemaDumper(
  197.                 $this->getConnection()->getDatabasePlatform(),
  198.                 $this->getSchemaManager($this->getConnection()),
  199.                 $this->getMigrationGenerator(),
  200.                 $this->getMigrationSqlGenerator(),
  201.                 $excludedTables
  202.             );
  203.         });
  204.     }
  205.     /**
  206.      * @return AbstractSchemaManager<AbstractPlatform>
  207.      */
  208.     private function getSchemaManager(Connection $connection): AbstractSchemaManager
  209.     {
  210.         return method_exists($connection'createSchemaManager')
  211.             ? $connection->createSchemaManager()
  212.             : $connection->getSchemaManager();
  213.     }
  214.     private function getEmptySchemaProvider(): SchemaProvider
  215.     {
  216.         return $this->getDependency(EmptySchemaProvider::class, function (): SchemaProvider {
  217.             return new EmptySchemaProvider(
  218.                 $this->getSchemaManager($this->getConnection())
  219.             );
  220.         });
  221.     }
  222.     public function hasSchemaProvider(): bool
  223.     {
  224.         try {
  225.             $this->getSchemaProvider();
  226.         } catch (MissingDependency $exception) {
  227.             return false;
  228.         }
  229.         return true;
  230.     }
  231.     public function getSchemaProvider(): SchemaProvider
  232.     {
  233.         return $this->getDependency(SchemaProvider::class, function (): SchemaProvider {
  234.             if ($this->hasEntityManager()) {
  235.                 return new OrmSchemaProvider($this->getEntityManager());
  236.             }
  237.             throw MissingDependency::noSchemaProvider();
  238.         });
  239.     }
  240.     public function getDiffGenerator(): DiffGenerator
  241.     {
  242.         return $this->getDependency(DiffGenerator::class, function (): DiffGenerator {
  243.             return new DiffGenerator(
  244.                 $this->getConnection()->getConfiguration(),
  245.                 $this->getSchemaManager($this->getConnection()),
  246.                 $this->getSchemaProvider(),
  247.                 $this->getConnection()->getDatabasePlatform(),
  248.                 $this->getMigrationGenerator(),
  249.                 $this->getMigrationSqlGenerator(),
  250.                 $this->getEmptySchemaProvider()
  251.             );
  252.         });
  253.     }
  254.     public function getSchemaDiffProvider(): SchemaDiffProvider
  255.     {
  256.         return $this->getDependency(SchemaDiffProvider::class, function (): LazySchemaDiffProvider {
  257.             return LazySchemaDiffProvider::fromDefaultProxyFactoryConfiguration(
  258.                 new DBALSchemaDiffProvider(
  259.                     $this->getSchemaManager($this->getConnection()),
  260.                     $this->getConnection()->getDatabasePlatform()
  261.                 )
  262.             );
  263.         });
  264.     }
  265.     private function getFileBuilder(): FileBuilder
  266.     {
  267.         return $this->getDependency(FileBuilder::class, static function (): FileBuilder {
  268.             return new ConcatenationFileBuilder();
  269.         });
  270.     }
  271.     private function getParameterFormatter(): ParameterFormatter
  272.     {
  273.         return $this->getDependency(ParameterFormatter::class, function (): ParameterFormatter {
  274.             return new InlineParameterFormatter($this->getConnection());
  275.         });
  276.     }
  277.     public function getMigrationsFinder(): MigrationFinder
  278.     {
  279.         return $this->getDependency(MigrationFinder::class, function (): MigrationFinder {
  280.             $configs              $this->getConfiguration();
  281.             $needsRecursiveFinder $configs->areMigrationsOrganizedByYear() || $configs->areMigrationsOrganizedByYearAndMonth();
  282.             return $needsRecursiveFinder ? new RecursiveRegexFinder() : new GlobFinder();
  283.         });
  284.     }
  285.     public function getMigrationRepository(): MigrationsRepository
  286.     {
  287.         return $this->getDependency(MigrationsRepository::class, function (): MigrationsRepository {
  288.             return new FilesystemMigrationsRepository(
  289.                 $this->getConfiguration()->getMigrationClasses(),
  290.                 $this->getConfiguration()->getMigrationDirectories(),
  291.                 $this->getMigrationsFinder(),
  292.                 $this->getMigrationFactory()
  293.             );
  294.         });
  295.     }
  296.     public function getMigrationFactory(): MigrationFactory
  297.     {
  298.         return $this->getDependency(MigrationFactory::class, function (): MigrationFactory {
  299.             return new DbalMigrationFactory($this->getConnection(), $this->getLogger());
  300.         });
  301.     }
  302.     /**
  303.      * @param object|callable $service
  304.      */
  305.     public function setService(string $id$service): void
  306.     {
  307.         $this->assertNotFrozen();
  308.         $this->dependencies[$id] = $service;
  309.     }
  310.     public function getMetadataStorage(): MetadataStorage
  311.     {
  312.         return $this->getDependency(MetadataStorage::class, function (): MetadataStorage {
  313.             return new TableMetadataStorage(
  314.                 $this->getConnection(),
  315.                 $this->getVersionComparator(),
  316.                 $this->getConfiguration()->getMetadataStorageConfiguration(),
  317.                 $this->getMigrationRepository()
  318.             );
  319.         });
  320.     }
  321.     private function getVersionExecutor(): Executor
  322.     {
  323.         return $this->getDependency(Executor::class, function (): Executor {
  324.             return new DbalExecutor(
  325.                 $this->getMetadataStorage(),
  326.                 $this->getEventDispatcher(),
  327.                 $this->getConnection(),
  328.                 $this->getSchemaDiffProvider(),
  329.                 $this->getLogger(),
  330.                 $this->getParameterFormatter(),
  331.                 $this->getStopwatch()
  332.             );
  333.         });
  334.     }
  335.     public function getQueryWriter(): QueryWriter
  336.     {
  337.         return $this->getDependency(QueryWriter::class, function (): QueryWriter {
  338.             return new FileQueryWriter(
  339.                 $this->getFileBuilder(),
  340.                 $this->getLogger()
  341.             );
  342.         });
  343.     }
  344.     public function getVersionAliasResolver(): AliasResolver
  345.     {
  346.         return $this->getDependency(AliasResolver::class, function (): AliasResolver {
  347.             return new DefaultAliasResolver(
  348.                 $this->getMigrationPlanCalculator(),
  349.                 $this->getMetadataStorage(),
  350.                 $this->getMigrationStatusCalculator()
  351.             );
  352.         });
  353.     }
  354.     public function getMigrationStatusCalculator(): MigrationStatusCalculator
  355.     {
  356.         return $this->getDependency(MigrationStatusCalculator::class, function (): MigrationStatusCalculator {
  357.             return new CurrentMigrationStatusCalculator(
  358.                 $this->getMigrationPlanCalculator(),
  359.                 $this->getMetadataStorage()
  360.             );
  361.         });
  362.     }
  363.     public function getMigrationPlanCalculator(): MigrationPlanCalculator
  364.     {
  365.         return $this->getDependency(MigrationPlanCalculator::class, function (): MigrationPlanCalculator {
  366.             return new SortedMigrationPlanCalculator(
  367.                 $this->getMigrationRepository(),
  368.                 $this->getMetadataStorage(),
  369.                 $this->getVersionComparator()
  370.             );
  371.         });
  372.     }
  373.     public function getMigrationGenerator(): Generator
  374.     {
  375.         return $this->getDependency(Generator::class, function (): Generator {
  376.             return new Generator($this->getConfiguration());
  377.         });
  378.     }
  379.     public function getMigrationSqlGenerator(): SqlGenerator
  380.     {
  381.         return $this->getDependency(SqlGenerator::class, function (): SqlGenerator {
  382.             return new SqlGenerator(
  383.                 $this->getConfiguration(),
  384.                 $this->getConnection()->getDatabasePlatform()
  385.             );
  386.         });
  387.     }
  388.     public function getConsoleInputMigratorConfigurationFactory(): MigratorConfigurationFactory
  389.     {
  390.         return $this->getDependency(MigratorConfigurationFactory::class, function (): MigratorConfigurationFactory {
  391.             return new ConsoleInputMigratorConfigurationFactory(
  392.                 $this->getConfiguration()
  393.             );
  394.         });
  395.     }
  396.     public function getMigrationStatusInfosHelper(): MigrationStatusInfosHelper
  397.     {
  398.         return $this->getDependency(MigrationStatusInfosHelper::class, function (): MigrationStatusInfosHelper {
  399.             return new MigrationStatusInfosHelper(
  400.                 $this->getConfiguration(),
  401.                 $this->getConnection(),
  402.                 $this->getVersionAliasResolver(),
  403.                 $this->getMigrationPlanCalculator(),
  404.                 $this->getMigrationStatusCalculator(),
  405.                 $this->getMetadataStorage()
  406.             );
  407.         });
  408.     }
  409.     public function getMigrator(): Migrator
  410.     {
  411.         return $this->getDependency(Migrator::class, function (): Migrator {
  412.             return new DbalMigrator(
  413.                 $this->getConnection(),
  414.                 $this->getEventDispatcher(),
  415.                 $this->getVersionExecutor(),
  416.                 $this->getLogger(),
  417.                 $this->getStopwatch()
  418.             );
  419.         });
  420.     }
  421.     public function getStopwatch(): Stopwatch
  422.     {
  423.         return $this->getDependency(Stopwatch::class, static function (): Stopwatch {
  424.             return new Stopwatch(true);
  425.         });
  426.     }
  427.     public function getRollup(): Rollup
  428.     {
  429.         return $this->getDependency(Rollup::class, function (): Rollup {
  430.             return new Rollup(
  431.                 $this->getMetadataStorage(),
  432.                 $this->getMigrationRepository()
  433.             );
  434.         });
  435.     }
  436.     /**
  437.      * @return mixed
  438.      */
  439.     private function getDependency(string $id, callable $callback)
  440.     {
  441.         if (! isset($this->inResolution[$id]) && array_key_exists($id$this->factories) && ! array_key_exists($id$this->dependencies)) {
  442.             $this->inResolution[$id] = true;
  443.             $this->dependencies[$id] = call_user_func($this->factories[$id], $this);
  444.             unset($this->inResolution);
  445.         }
  446.         if (! array_key_exists($id$this->dependencies)) {
  447.             $this->dependencies[$id] = $callback();
  448.         }
  449.         return $this->dependencies[$id];
  450.     }
  451.     public function setDefinition(string $id, callable $service): void
  452.     {
  453.         $this->assertNotFrozen();
  454.         $this->factories[$id] = $service;
  455.     }
  456. }