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

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