506 lines
17 KiB
PHP
506 lines
17 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Doctrine\Migrations;
|
|
|
|
use Doctrine\DBAL\Connection;
|
|
use Doctrine\Migrations\Configuration\Configuration;
|
|
use Doctrine\Migrations\Configuration\Connection\ConnectionLoader;
|
|
use Doctrine\Migrations\Configuration\EntityManager\EntityManagerLoader;
|
|
use Doctrine\Migrations\Configuration\Migration\ConfigurationLoader;
|
|
use Doctrine\Migrations\Exception\FrozenDependencies;
|
|
use Doctrine\Migrations\Exception\MissingDependency;
|
|
use Doctrine\Migrations\Finder\GlobFinder;
|
|
use Doctrine\Migrations\Finder\MigrationFinder;
|
|
use Doctrine\Migrations\Finder\RecursiveRegexFinder;
|
|
use Doctrine\Migrations\Generator\ClassNameGenerator;
|
|
use Doctrine\Migrations\Generator\ConcatenationFileBuilder;
|
|
use Doctrine\Migrations\Generator\DiffGenerator;
|
|
use Doctrine\Migrations\Generator\FileBuilder;
|
|
use Doctrine\Migrations\Generator\Generator;
|
|
use Doctrine\Migrations\Generator\SqlGenerator;
|
|
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
|
|
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorage;
|
|
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
|
|
use Doctrine\Migrations\Provider\DBALSchemaDiffProvider;
|
|
use Doctrine\Migrations\Provider\EmptySchemaProvider;
|
|
use Doctrine\Migrations\Provider\LazySchemaDiffProvider;
|
|
use Doctrine\Migrations\Provider\OrmSchemaProvider;
|
|
use Doctrine\Migrations\Provider\SchemaDiffProvider;
|
|
use Doctrine\Migrations\Provider\SchemaProvider;
|
|
use Doctrine\Migrations\Tools\Console\ConsoleInputMigratorConfigurationFactory;
|
|
use Doctrine\Migrations\Tools\Console\Helper\MigrationStatusInfosHelper;
|
|
use Doctrine\Migrations\Tools\Console\MigratorConfigurationFactory;
|
|
use Doctrine\Migrations\Version\AliasResolver;
|
|
use Doctrine\Migrations\Version\AlphabeticalComparator;
|
|
use Doctrine\Migrations\Version\Comparator;
|
|
use Doctrine\Migrations\Version\CurrentMigrationStatusCalculator;
|
|
use Doctrine\Migrations\Version\DbalExecutor;
|
|
use Doctrine\Migrations\Version\DbalMigrationFactory;
|
|
use Doctrine\Migrations\Version\DefaultAliasResolver;
|
|
use Doctrine\Migrations\Version\Executor;
|
|
use Doctrine\Migrations\Version\MigrationFactory;
|
|
use Doctrine\Migrations\Version\MigrationPlanCalculator;
|
|
use Doctrine\Migrations\Version\MigrationStatusCalculator;
|
|
use Doctrine\Migrations\Version\SortedMigrationPlanCalculator;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use Psr\Log\NullLogger;
|
|
use Symfony\Component\Stopwatch\Stopwatch;
|
|
|
|
use function array_key_exists;
|
|
use function call_user_func;
|
|
use function preg_quote;
|
|
use function sprintf;
|
|
|
|
/**
|
|
* The DependencyFactory is responsible for wiring up and managing internal class dependencies.
|
|
*/
|
|
class DependencyFactory
|
|
{
|
|
/** @psalm-var array<string, bool> */
|
|
private $inResolution = [];
|
|
|
|
private ?Configuration $configuration = null;
|
|
|
|
/** @var object[]|callable[] */
|
|
private array $dependencies = [];
|
|
|
|
private ?Connection $connection = null;
|
|
|
|
private ?EntityManagerInterface $em = null;
|
|
|
|
private bool $frozen = false;
|
|
|
|
private ConfigurationLoader $configurationLoader;
|
|
|
|
private ConnectionLoader $connectionLoader;
|
|
|
|
private ?EntityManagerLoader $emLoader = null;
|
|
|
|
/** @var callable[] */
|
|
private array $factories = [];
|
|
|
|
public static function fromConnection(
|
|
ConfigurationLoader $configurationLoader,
|
|
ConnectionLoader $connectionLoader,
|
|
?LoggerInterface $logger = null
|
|
): self {
|
|
$dependencyFactory = new self($logger);
|
|
$dependencyFactory->configurationLoader = $configurationLoader;
|
|
$dependencyFactory->connectionLoader = $connectionLoader;
|
|
|
|
return $dependencyFactory;
|
|
}
|
|
|
|
public static function fromEntityManager(
|
|
ConfigurationLoader $configurationLoader,
|
|
EntityManagerLoader $emLoader,
|
|
?LoggerInterface $logger = null
|
|
): self {
|
|
$dependencyFactory = new self($logger);
|
|
$dependencyFactory->configurationLoader = $configurationLoader;
|
|
$dependencyFactory->emLoader = $emLoader;
|
|
|
|
return $dependencyFactory;
|
|
}
|
|
|
|
private function __construct(?LoggerInterface $logger)
|
|
{
|
|
if ($logger === null) {
|
|
return;
|
|
}
|
|
|
|
$this->setDefinition(LoggerInterface::class, static function () use ($logger): LoggerInterface {
|
|
return $logger;
|
|
});
|
|
}
|
|
|
|
public function isFrozen(): bool
|
|
{
|
|
return $this->frozen;
|
|
}
|
|
|
|
public function freeze(): void
|
|
{
|
|
$this->frozen = true;
|
|
}
|
|
|
|
private function assertNotFrozen(): void
|
|
{
|
|
if ($this->frozen) {
|
|
throw FrozenDependencies::new();
|
|
}
|
|
}
|
|
|
|
public function hasEntityManager(): bool
|
|
{
|
|
return $this->emLoader !== null;
|
|
}
|
|
|
|
public function setConfigurationLoader(ConfigurationLoader $configurationLoader): void
|
|
{
|
|
$this->assertNotFrozen();
|
|
$this->configurationLoader = $configurationLoader;
|
|
}
|
|
|
|
public function getConfiguration(): Configuration
|
|
{
|
|
if ($this->configuration === null) {
|
|
$this->configuration = $this->configurationLoader->getConfiguration();
|
|
$this->freeze();
|
|
}
|
|
|
|
return $this->configuration;
|
|
}
|
|
|
|
public function getConnection(): Connection
|
|
{
|
|
if ($this->connection === null) {
|
|
$this->connection = $this->hasEntityManager()
|
|
? $this->getEntityManager()->getConnection()
|
|
: $this->connectionLoader->getConnection($this->getConfiguration()->getConnectionName());
|
|
$this->freeze();
|
|
}
|
|
|
|
return $this->connection;
|
|
}
|
|
|
|
public function getEntityManager(): EntityManagerInterface
|
|
{
|
|
if ($this->em === null) {
|
|
if ($this->emLoader === null) {
|
|
throw MissingDependency::noEntityManager();
|
|
}
|
|
|
|
$this->em = $this->emLoader->getEntityManager($this->getConfiguration()->getEntityManagerName());
|
|
$this->freeze();
|
|
}
|
|
|
|
return $this->em;
|
|
}
|
|
|
|
public function getVersionComparator(): Comparator
|
|
{
|
|
return $this->getDependency(Comparator::class, static function (): AlphabeticalComparator {
|
|
return new AlphabeticalComparator();
|
|
});
|
|
}
|
|
|
|
public function getLogger(): LoggerInterface
|
|
{
|
|
return $this->getDependency(LoggerInterface::class, static function (): LoggerInterface {
|
|
return new NullLogger();
|
|
});
|
|
}
|
|
|
|
public function getEventDispatcher(): EventDispatcher
|
|
{
|
|
return $this->getDependency(EventDispatcher::class, function (): EventDispatcher {
|
|
return new EventDispatcher(
|
|
$this->getConnection(),
|
|
$this->getConnection()->getEventManager()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getClassNameGenerator(): ClassNameGenerator
|
|
{
|
|
return $this->getDependency(ClassNameGenerator::class, static function (): ClassNameGenerator {
|
|
return new ClassNameGenerator();
|
|
});
|
|
}
|
|
|
|
public function getSchemaDumper(): SchemaDumper
|
|
{
|
|
return $this->getDependency(SchemaDumper::class, function (): SchemaDumper {
|
|
$excludedTables = [];
|
|
|
|
$metadataConfig = $this->getConfiguration()->getMetadataStorageConfiguration();
|
|
if ($metadataConfig instanceof TableMetadataStorageConfiguration) {
|
|
$excludedTables[] = sprintf('/^%s$/', preg_quote($metadataConfig->getTableName(), '/'));
|
|
}
|
|
|
|
return new SchemaDumper(
|
|
$this->getConnection()->getDatabasePlatform(),
|
|
$this->getConnection()->createSchemaManager(),
|
|
$this->getMigrationGenerator(),
|
|
$this->getMigrationSqlGenerator(),
|
|
$excludedTables
|
|
);
|
|
});
|
|
}
|
|
|
|
private function getEmptySchemaProvider(): SchemaProvider
|
|
{
|
|
return $this->getDependency(EmptySchemaProvider::class, function (): SchemaProvider {
|
|
return new EmptySchemaProvider($this->connection->createSchemaManager());
|
|
});
|
|
}
|
|
|
|
public function hasSchemaProvider(): bool
|
|
{
|
|
try {
|
|
$this->getSchemaProvider();
|
|
} catch (MissingDependency $exception) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function getSchemaProvider(): SchemaProvider
|
|
{
|
|
return $this->getDependency(SchemaProvider::class, function (): SchemaProvider {
|
|
if ($this->hasEntityManager()) {
|
|
return new OrmSchemaProvider($this->getEntityManager());
|
|
}
|
|
|
|
throw MissingDependency::noSchemaProvider();
|
|
});
|
|
}
|
|
|
|
public function getDiffGenerator(): DiffGenerator
|
|
{
|
|
return $this->getDependency(DiffGenerator::class, function (): DiffGenerator {
|
|
return new DiffGenerator(
|
|
$this->getConnection()->getConfiguration(),
|
|
$this->getConnection()->createSchemaManager(),
|
|
$this->getSchemaProvider(),
|
|
$this->getConnection()->getDatabasePlatform(),
|
|
$this->getMigrationGenerator(),
|
|
$this->getMigrationSqlGenerator(),
|
|
$this->getEmptySchemaProvider()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getSchemaDiffProvider(): SchemaDiffProvider
|
|
{
|
|
return $this->getDependency(SchemaDiffProvider::class, function (): LazySchemaDiffProvider {
|
|
return LazySchemaDiffProvider::fromDefaultProxyFactoryConfiguration(
|
|
new DBALSchemaDiffProvider(
|
|
$this->getConnection()->createSchemaManager(),
|
|
$this->getConnection()->getDatabasePlatform()
|
|
)
|
|
);
|
|
});
|
|
}
|
|
|
|
private function getFileBuilder(): FileBuilder
|
|
{
|
|
return $this->getDependency(FileBuilder::class, static function (): FileBuilder {
|
|
return new ConcatenationFileBuilder();
|
|
});
|
|
}
|
|
|
|
private function getParameterFormatter(): ParameterFormatter
|
|
{
|
|
return $this->getDependency(ParameterFormatter::class, function (): ParameterFormatter {
|
|
return new InlineParameterFormatter($this->getConnection());
|
|
});
|
|
}
|
|
|
|
public function getMigrationsFinder(): MigrationFinder
|
|
{
|
|
return $this->getDependency(MigrationFinder::class, function (): MigrationFinder {
|
|
$configs = $this->getConfiguration();
|
|
$needsRecursiveFinder = $configs->areMigrationsOrganizedByYear() || $configs->areMigrationsOrganizedByYearAndMonth();
|
|
|
|
return $needsRecursiveFinder ? new RecursiveRegexFinder() : new GlobFinder();
|
|
});
|
|
}
|
|
|
|
public function getMigrationRepository(): MigrationsRepository
|
|
{
|
|
return $this->getDependency(MigrationsRepository::class, function (): MigrationsRepository {
|
|
return new FilesystemMigrationsRepository(
|
|
$this->getConfiguration()->getMigrationClasses(),
|
|
$this->getConfiguration()->getMigrationDirectories(),
|
|
$this->getMigrationsFinder(),
|
|
$this->getMigrationFactory()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getMigrationFactory(): MigrationFactory
|
|
{
|
|
return $this->getDependency(MigrationFactory::class, function (): MigrationFactory {
|
|
return new DbalMigrationFactory($this->getConnection(), $this->getLogger());
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param object|callable $service
|
|
*/
|
|
public function setService(string $id, $service): void
|
|
{
|
|
$this->assertNotFrozen();
|
|
$this->dependencies[$id] = $service;
|
|
}
|
|
|
|
public function getMetadataStorage(): MetadataStorage
|
|
{
|
|
return $this->getDependency(MetadataStorage::class, function (): MetadataStorage {
|
|
return new TableMetadataStorage(
|
|
$this->getConnection(),
|
|
$this->getVersionComparator(),
|
|
$this->getConfiguration()->getMetadataStorageConfiguration(),
|
|
$this->getMigrationRepository()
|
|
);
|
|
});
|
|
}
|
|
|
|
private function getVersionExecutor(): Executor
|
|
{
|
|
return $this->getDependency(Executor::class, function (): Executor {
|
|
return new DbalExecutor(
|
|
$this->getMetadataStorage(),
|
|
$this->getEventDispatcher(),
|
|
$this->getConnection(),
|
|
$this->getSchemaDiffProvider(),
|
|
$this->getLogger(),
|
|
$this->getParameterFormatter(),
|
|
$this->getStopwatch()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getQueryWriter(): QueryWriter
|
|
{
|
|
return $this->getDependency(QueryWriter::class, function (): QueryWriter {
|
|
return new FileQueryWriter(
|
|
$this->getFileBuilder(),
|
|
$this->getLogger()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getVersionAliasResolver(): AliasResolver
|
|
{
|
|
return $this->getDependency(AliasResolver::class, function (): AliasResolver {
|
|
return new DefaultAliasResolver(
|
|
$this->getMigrationPlanCalculator(),
|
|
$this->getMetadataStorage(),
|
|
$this->getMigrationStatusCalculator()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getMigrationStatusCalculator(): MigrationStatusCalculator
|
|
{
|
|
return $this->getDependency(MigrationStatusCalculator::class, function (): MigrationStatusCalculator {
|
|
return new CurrentMigrationStatusCalculator(
|
|
$this->getMigrationPlanCalculator(),
|
|
$this->getMetadataStorage()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getMigrationPlanCalculator(): MigrationPlanCalculator
|
|
{
|
|
return $this->getDependency(MigrationPlanCalculator::class, function (): MigrationPlanCalculator {
|
|
return new SortedMigrationPlanCalculator(
|
|
$this->getMigrationRepository(),
|
|
$this->getMetadataStorage(),
|
|
$this->getVersionComparator()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getMigrationGenerator(): Generator
|
|
{
|
|
return $this->getDependency(Generator::class, function (): Generator {
|
|
return new Generator($this->getConfiguration());
|
|
});
|
|
}
|
|
|
|
public function getMigrationSqlGenerator(): SqlGenerator
|
|
{
|
|
return $this->getDependency(SqlGenerator::class, function (): SqlGenerator {
|
|
return new SqlGenerator(
|
|
$this->getConfiguration(),
|
|
$this->getConnection()->getDatabasePlatform()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getConsoleInputMigratorConfigurationFactory(): MigratorConfigurationFactory
|
|
{
|
|
return $this->getDependency(MigratorConfigurationFactory::class, function (): MigratorConfigurationFactory {
|
|
return new ConsoleInputMigratorConfigurationFactory(
|
|
$this->getConfiguration()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getMigrationStatusInfosHelper(): MigrationStatusInfosHelper
|
|
{
|
|
return $this->getDependency(MigrationStatusInfosHelper::class, function (): MigrationStatusInfosHelper {
|
|
return new MigrationStatusInfosHelper(
|
|
$this->getConfiguration(),
|
|
$this->getConnection(),
|
|
$this->getVersionAliasResolver(),
|
|
$this->getMigrationPlanCalculator(),
|
|
$this->getMigrationStatusCalculator(),
|
|
$this->getMetadataStorage()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getMigrator(): Migrator
|
|
{
|
|
return $this->getDependency(Migrator::class, function (): Migrator {
|
|
return new DbalMigrator(
|
|
$this->getConnection(),
|
|
$this->getEventDispatcher(),
|
|
$this->getVersionExecutor(),
|
|
$this->getLogger(),
|
|
$this->getStopwatch()
|
|
);
|
|
});
|
|
}
|
|
|
|
public function getStopwatch(): Stopwatch
|
|
{
|
|
return $this->getDependency(Stopwatch::class, static function (): Stopwatch {
|
|
return new Stopwatch(true);
|
|
});
|
|
}
|
|
|
|
public function getRollup(): Rollup
|
|
{
|
|
return $this->getDependency(Rollup::class, function (): Rollup {
|
|
return new Rollup(
|
|
$this->getMetadataStorage(),
|
|
$this->getMigrationRepository()
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @return mixed
|
|
*/
|
|
private function getDependency(string $id, callable $callback)
|
|
{
|
|
if (! isset($this->inResolution[$id]) && array_key_exists($id, $this->factories) && ! array_key_exists($id, $this->dependencies)) {
|
|
$this->inResolution[$id] = true;
|
|
$this->dependencies[$id] = call_user_func($this->factories[$id], $this);
|
|
unset($this->inResolution);
|
|
}
|
|
|
|
if (! array_key_exists($id, $this->dependencies)) {
|
|
$this->dependencies[$id] = $callback();
|
|
}
|
|
|
|
return $this->dependencies[$id];
|
|
}
|
|
|
|
public function setDefinition(string $id, callable $service): void
|
|
{
|
|
$this->assertNotFrozen();
|
|
$this->factories[$id] = $service;
|
|
}
|
|
}
|