The start of something beautiful
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
branches: ["2.2.x", "3.0.x", "3.1.x", "3.2.x", "3.3.x", "3.4.x"]
|
||||
maintained_branches: ["2.2.x", "3.3.x", "3.4.x"]
|
||||
doc_dir: {"2.2.x": "Resources/doc/", "3.3.x": "Resources/doc/", "3.4.x": "docs/"}
|
||||
dev_branch: "3.4.x"
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MigrationsBundle\Collector;
|
||||
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\Migrations\DependencyFactory;
|
||||
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
use Throwable;
|
||||
|
||||
use function count;
|
||||
use function get_class;
|
||||
|
||||
class MigrationsCollector extends DataCollector
|
||||
{
|
||||
/** @var DependencyFactory */
|
||||
private $dependencyFactory;
|
||||
/** @var MigrationsFlattener */
|
||||
private $flattener;
|
||||
|
||||
public function __construct(DependencyFactory $dependencyFactory, MigrationsFlattener $migrationsFlattener)
|
||||
{
|
||||
$this->dependencyFactory = $dependencyFactory;
|
||||
$this->flattener = $migrationsFlattener;
|
||||
}
|
||||
|
||||
/** @return void */
|
||||
public function collect(Request $request, Response $response, ?Throwable $exception = null)
|
||||
{
|
||||
if (! empty($this->data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$metadataStorage = $this->dependencyFactory->getMetadataStorage();
|
||||
$planCalculator = $this->dependencyFactory->getMigrationPlanCalculator();
|
||||
|
||||
try {
|
||||
$executedMigrations = $metadataStorage->getExecutedMigrations();
|
||||
} catch (Exception $dbalException) {
|
||||
$this->dependencyFactory->getLogger()->error(
|
||||
'error while trying to collect executed migrations',
|
||||
['exception' => $dbalException]
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$availableMigrations = $planCalculator->getMigrations();
|
||||
|
||||
$this->data['available_migrations_count'] = count($availableMigrations);
|
||||
$unavailableMigrations = $executedMigrations->unavailableSubset($availableMigrations);
|
||||
$this->data['unavailable_migrations_count'] = count($unavailableMigrations);
|
||||
|
||||
$newMigrations = $availableMigrations->newSubset($executedMigrations);
|
||||
$this->data['new_migrations'] = $this->flattener->flattenAvailableMigrations($newMigrations);
|
||||
$this->data['executed_migrations'] = $this->flattener->flattenExecutedMigrations($executedMigrations, $availableMigrations);
|
||||
|
||||
$this->data['storage'] = get_class($metadataStorage);
|
||||
$configuration = $this->dependencyFactory->getConfiguration();
|
||||
$storage = $configuration->getMetadataStorageConfiguration();
|
||||
if ($storage instanceof TableMetadataStorageConfiguration) {
|
||||
$this->data['table'] = $storage->getTableName();
|
||||
$this->data['column'] = $storage->getVersionColumnName();
|
||||
}
|
||||
|
||||
$connection = $this->dependencyFactory->getConnection();
|
||||
$this->data['driver'] = get_class($connection->getDriver());
|
||||
$this->data['name'] = $connection->getDatabase();
|
||||
|
||||
$this->data['namespaces'] = $configuration->getMigrationDirectories();
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getName()
|
||||
{
|
||||
return 'doctrine_migrations';
|
||||
}
|
||||
|
||||
/** @return array<string, mixed>|Data */
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/** @return void */
|
||||
public function reset()
|
||||
{
|
||||
$this->data = [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MigrationsBundle\Collector;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Migrations\Metadata\AvailableMigration;
|
||||
use Doctrine\Migrations\Metadata\AvailableMigrationsList;
|
||||
use Doctrine\Migrations\Metadata\ExecutedMigration;
|
||||
use Doctrine\Migrations\Metadata\ExecutedMigrationsList;
|
||||
use ReflectionClass;
|
||||
|
||||
use function array_map;
|
||||
|
||||
class MigrationsFlattener
|
||||
{
|
||||
/**
|
||||
* @return array{
|
||||
* version: string,
|
||||
* is_new: true,
|
||||
* is_unavailable: bool,
|
||||
* description: string,
|
||||
* executed_at: null,
|
||||
* execution_time: null,
|
||||
* file: string|false,
|
||||
* }[]
|
||||
*/
|
||||
public function flattenAvailableMigrations(AvailableMigrationsList $migrationsList): array
|
||||
{
|
||||
return array_map(static function (AvailableMigration $migration) {
|
||||
return [
|
||||
'version' => (string) $migration->getVersion(),
|
||||
'is_new' => true,
|
||||
'is_unavailable' => false,
|
||||
'description' => $migration->getMigration()->getDescription(),
|
||||
'executed_at' => null,
|
||||
'execution_time' => null,
|
||||
'file' => (new ReflectionClass($migration->getMigration()))->getFileName(),
|
||||
];
|
||||
}, $migrationsList->getItems());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* version: string,
|
||||
* is_new: false,
|
||||
* is_unavailable: bool,
|
||||
* description: string|null,
|
||||
* executed_at: DateTimeImmutable|null,
|
||||
* execution_time: float|null,
|
||||
* file: string|false|null,
|
||||
* }[]
|
||||
*/
|
||||
public function flattenExecutedMigrations(ExecutedMigrationsList $migrationsList, AvailableMigrationsList $availableMigrations): array
|
||||
{
|
||||
return array_map(static function (ExecutedMigration $migration) use ($availableMigrations) {
|
||||
$availableMigration = $availableMigrations->hasMigration($migration->getVersion())
|
||||
? $availableMigrations->getMigration($migration->getVersion())->getMigration()
|
||||
: null;
|
||||
|
||||
return [
|
||||
'version' => (string) $migration->getVersion(),
|
||||
'is_new' => false,
|
||||
'is_unavailable' => ! $availableMigration,
|
||||
'description' => $availableMigration ? $availableMigration->getDescription() : null,
|
||||
'executed_at' => $migration->getExecutedAt(),
|
||||
'execution_time' => $migration->getExecutionTime(),
|
||||
'file' => $availableMigration ? (new ReflectionClass($availableMigration))->getFileName() : null,
|
||||
];
|
||||
}, $migrationsList->getItems());
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MigrationsBundle\DependencyInjection\CompilerPass;
|
||||
|
||||
use Doctrine\Migrations\DependencyFactory;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
use function array_keys;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function sprintf;
|
||||
|
||||
class ConfigureDependencyFactoryPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (! $container->has('doctrine')) {
|
||||
throw new RuntimeException('DoctrineMigrationsBundle requires DoctrineBundle to be enabled.');
|
||||
}
|
||||
|
||||
$diDefinition = $container->getDefinition('doctrine.migrations.dependency_factory');
|
||||
|
||||
$preferredConnection = $container->getParameter('doctrine.migrations.preferred_connection');
|
||||
assert(is_string($preferredConnection) || $preferredConnection === null);
|
||||
// explicitly use configured connection
|
||||
if ($preferredConnection !== null) {
|
||||
$this->validatePreferredConnection($container, $preferredConnection);
|
||||
|
||||
$loaderDefinition = $container->getDefinition('doctrine.migrations.connection_registry_loader');
|
||||
$loaderDefinition->setArgument(1, $preferredConnection);
|
||||
|
||||
$diDefinition->setFactory([DependencyFactory::class, 'fromConnection']);
|
||||
$diDefinition->setArgument(1, new Reference('doctrine.migrations.connection_registry_loader'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$preferredEm = $container->getParameter('doctrine.migrations.preferred_em');
|
||||
assert(is_string($preferredEm) || $preferredEm === null);
|
||||
// explicitly use configured entity manager
|
||||
if ($preferredEm !== null) {
|
||||
$this->validatePreferredEm($container, $preferredEm);
|
||||
|
||||
$loaderDefinition = $container->getDefinition('doctrine.migrations.entity_manager_registry_loader');
|
||||
$loaderDefinition->setArgument(1, $preferredEm);
|
||||
|
||||
$diDefinition->setFactory([DependencyFactory::class, 'fromEntityManager']);
|
||||
$diDefinition->setArgument(1, new Reference('doctrine.migrations.entity_manager_registry_loader'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// try to use any/default entity manager
|
||||
if (
|
||||
$container->hasParameter('doctrine.entity_managers')
|
||||
&& is_array($container->getParameter('doctrine.entity_managers'))
|
||||
&& count($container->getParameter('doctrine.entity_managers')) > 0
|
||||
) {
|
||||
$diDefinition->setFactory([DependencyFactory::class, 'fromEntityManager']);
|
||||
$diDefinition->setArgument(1, new Reference('doctrine.migrations.entity_manager_registry_loader'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// fallback on any/default connection
|
||||
$diDefinition->setFactory([DependencyFactory::class, 'fromConnection']);
|
||||
$diDefinition->setArgument(1, new Reference('doctrine.migrations.connection_registry_loader'));
|
||||
}
|
||||
|
||||
private function validatePreferredConnection(ContainerBuilder $container, string $preferredConnection): void
|
||||
{
|
||||
/** @var array<string, string> $allowedConnections */
|
||||
$allowedConnections = $container->getParameter('doctrine.connections');
|
||||
if (! isset($allowedConnections[$preferredConnection])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The "%s" connection is not defined. Did you mean one of the following: %s',
|
||||
$preferredConnection,
|
||||
implode(', ', array_keys($allowedConnections))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private function validatePreferredEm(ContainerBuilder $container, string $preferredEm): void
|
||||
{
|
||||
if (
|
||||
! $container->hasParameter('doctrine.entity_managers')
|
||||
|| ! is_array($container->getParameter('doctrine.entity_managers'))
|
||||
|| count($container->getParameter('doctrine.entity_managers')) === 0
|
||||
) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The "%s" entity manager is not defined. It seems that you do not have configured any entity manager in the DoctrineBundle.',
|
||||
$preferredEm
|
||||
));
|
||||
}
|
||||
|
||||
/** @var array<string, string> $allowedEms */
|
||||
$allowedEms = $container->getParameter('doctrine.entity_managers');
|
||||
if (! isset($allowedEms[$preferredEm])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The "%s" entity manager is not defined. Did you mean one of the following: %s',
|
||||
$preferredEm,
|
||||
implode(', ', array_keys($allowedEms))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MigrationsBundle\DependencyInjection;
|
||||
|
||||
use ReflectionClass;
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
use function array_filter;
|
||||
use function array_keys;
|
||||
use function constant;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* DoctrineMigrationsExtension configuration structure.
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* Generates the configuration tree.
|
||||
*
|
||||
* @return TreeBuilder The config tree builder
|
||||
*/
|
||||
public function getConfigTreeBuilder(): TreeBuilder
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('doctrine_migrations');
|
||||
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
|
||||
$organizeMigrationModes = $this->getOrganizeMigrationsModes();
|
||||
|
||||
$rootNode
|
||||
->fixXmlConfig('migration', 'migrations')
|
||||
->fixXmlConfig('migrations_path', 'migrations_paths')
|
||||
->children()
|
||||
->arrayNode('migrations_paths')
|
||||
->info('A list of namespace/path pairs where to look for migrations.')
|
||||
->defaultValue([])
|
||||
->useAttributeAsKey('namespace')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
|
||||
->arrayNode('services')
|
||||
->info('A set of services to pass to the underlying doctrine/migrations library, allowing to change its behaviour.')
|
||||
->useAttributeAsKey('service')
|
||||
->defaultValue([])
|
||||
->validate()
|
||||
->ifTrue(static function (array $v): bool {
|
||||
return count(array_filter(array_keys($v), static function (string $doctrineService): bool {
|
||||
return strpos($doctrineService, 'Doctrine\Migrations\\') !== 0;
|
||||
})) !== 0;
|
||||
})
|
||||
->thenInvalid('Valid services for the DoctrineMigrationsBundle must be in the "Doctrine\Migrations" namespace.')
|
||||
->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
|
||||
->arrayNode('factories')
|
||||
->info('A set of callables to pass to the underlying doctrine/migrations library as services, allowing to change its behaviour.')
|
||||
->useAttributeAsKey('factory')
|
||||
->defaultValue([])
|
||||
->validate()
|
||||
->ifTrue(static function (array $v): bool {
|
||||
return count(array_filter(array_keys($v), static function (string $doctrineService): bool {
|
||||
return strpos($doctrineService, 'Doctrine\Migrations\\') !== 0;
|
||||
})) !== 0;
|
||||
})
|
||||
->thenInvalid('Valid callables for the DoctrineMigrationsBundle must be in the "Doctrine\Migrations" namespace.')
|
||||
->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
|
||||
->arrayNode('storage')
|
||||
->addDefaultsIfNotSet()
|
||||
->info('Storage to use for migration status metadata.')
|
||||
->children()
|
||||
->arrayNode('table_storage')
|
||||
->addDefaultsIfNotSet()
|
||||
->info('The default metadata storage, implemented as a table in the database.')
|
||||
->children()
|
||||
->scalarNode('table_name')->defaultValue(null)->cannotBeEmpty()->end()
|
||||
->scalarNode('version_column_name')->defaultValue(null)->end()
|
||||
->scalarNode('version_column_length')->defaultValue(null)->end()
|
||||
->scalarNode('executed_at_column_name')->defaultValue(null)->end()
|
||||
->scalarNode('execution_time_column_name')->defaultValue(null)->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
||||
->arrayNode('migrations')
|
||||
->info('A list of migrations to load in addition to the one discovered via "migrations_paths".')
|
||||
->prototype('scalar')->end()
|
||||
->defaultValue([])
|
||||
->end()
|
||||
->scalarNode('connection')
|
||||
->info('Connection name to use for the migrations database.')
|
||||
->defaultValue(null)
|
||||
->end()
|
||||
->scalarNode('em')
|
||||
->info('Entity manager name to use for the migrations database (available when doctrine/orm is installed).')
|
||||
->defaultValue(null)
|
||||
->end()
|
||||
->scalarNode('all_or_nothing')
|
||||
->info('Run all migrations in a transaction.')
|
||||
->defaultValue(false)
|
||||
->end()
|
||||
->scalarNode('check_database_platform')
|
||||
->info('Adds an extra check in the generated migrations to allow execution only on the same platform as they were initially generated on.')
|
||||
->defaultValue(true)
|
||||
->end()
|
||||
->scalarNode('custom_template')
|
||||
->info('Custom template path for generated migration classes.')
|
||||
->defaultValue(null)
|
||||
->end()
|
||||
->scalarNode('organize_migrations')
|
||||
->defaultValue(false)
|
||||
->info('Organize migrations mode. Possible values are: "BY_YEAR", "BY_YEAR_AND_MONTH", false')
|
||||
->validate()
|
||||
->ifTrue(static function ($v) use ($organizeMigrationModes): bool {
|
||||
if ($v === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! is_string($v) || ! in_array(strtoupper($v), $organizeMigrationModes, true);
|
||||
})
|
||||
->thenInvalid('Invalid organize migrations mode value %s')
|
||||
->end()
|
||||
->validate()
|
||||
->ifString()
|
||||
->then(static function ($v) {
|
||||
return constant('Doctrine\Migrations\Configuration\Configuration::VERSIONS_ORGANIZATION_' . strtoupper($v));
|
||||
})
|
||||
->end()
|
||||
->end()
|
||||
->booleanNode('enable_profiler')
|
||||
->info('Whether or not to enable the profiler collector to calculate and visualize migration status. This adds some queries overhead.')
|
||||
->defaultFalse()
|
||||
->end()
|
||||
->booleanNode('transactional')
|
||||
->info('Whether or not to wrap migrations in a single transaction.')
|
||||
->defaultTrue()
|
||||
->end()
|
||||
->end();
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find organize migrations modes for their names
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function getOrganizeMigrationsModes(): array
|
||||
{
|
||||
$constPrefix = 'VERSIONS_ORGANIZATION_';
|
||||
$prefixLen = strlen($constPrefix);
|
||||
$refClass = new ReflectionClass('Doctrine\Migrations\Configuration\Configuration');
|
||||
$constsArray = array_keys($refClass->getConstants());
|
||||
$namesArray = [];
|
||||
|
||||
foreach ($constsArray as $constant) {
|
||||
if (strpos($constant, $constPrefix) !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$namesArray[] = substr($constant, $prefixLen);
|
||||
}
|
||||
|
||||
return $namesArray;
|
||||
}
|
||||
}
|
||||
Vendored
+201
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MigrationsBundle\DependencyInjection;
|
||||
|
||||
use Doctrine\Bundle\MigrationsBundle\Collector\MigrationsCollector;
|
||||
use Doctrine\Bundle\MigrationsBundle\Collector\MigrationsFlattener;
|
||||
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
|
||||
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
|
||||
use Doctrine\Migrations\Version\MigrationFactory;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
use function array_keys;
|
||||
use function assert;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function interface_exists;
|
||||
use function is_array;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
class DoctrineMigrationsExtension extends Extension
|
||||
{
|
||||
/**
|
||||
* Responds to the migrations configuration parameter.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$configuration = new Configuration();
|
||||
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$locator = new FileLocator(__DIR__ . '/../Resources/config/');
|
||||
$loader = new XmlFileLoader($container, $locator);
|
||||
|
||||
$loader->load('services.xml');
|
||||
|
||||
$configurationDefinition = $container->getDefinition('doctrine.migrations.configuration');
|
||||
|
||||
foreach ($config['migrations_paths'] as $ns => $path) {
|
||||
$path = $this->checkIfBundleRelativePath($path, $container);
|
||||
$configurationDefinition->addMethodCall('addMigrationsDirectory', [$ns, $path]);
|
||||
}
|
||||
|
||||
foreach ($config['migrations'] as $migrationClass) {
|
||||
$configurationDefinition->addMethodCall('addMigrationClass', [$migrationClass]);
|
||||
}
|
||||
|
||||
if ($config['organize_migrations'] !== false) {
|
||||
$configurationDefinition->addMethodCall('setMigrationOrganization', [$config['organize_migrations']]);
|
||||
}
|
||||
|
||||
if ($config['custom_template'] !== null) {
|
||||
$configurationDefinition->addMethodCall('setCustomTemplate', [$config['custom_template']]);
|
||||
}
|
||||
|
||||
$configurationDefinition->addMethodCall('setAllOrNothing', [$config['all_or_nothing']]);
|
||||
$configurationDefinition->addMethodCall('setCheckDatabasePlatform', [$config['check_database_platform']]);
|
||||
|
||||
if ($config['enable_profiler']) {
|
||||
$this->registerCollector($container);
|
||||
}
|
||||
|
||||
$configurationDefinition->addMethodCall('setTransactional', [$config['transactional']]);
|
||||
|
||||
$diDefinition = $container->getDefinition('doctrine.migrations.dependency_factory');
|
||||
|
||||
if (! isset($config['services'][MigrationFactory::class])) {
|
||||
$config['services'][MigrationFactory::class] = 'doctrine.migrations.migrations_factory';
|
||||
}
|
||||
|
||||
foreach ($config['services'] as $doctrineId => $symfonyId) {
|
||||
$diDefinition->addMethodCall('setDefinition', [$doctrineId, new ServiceClosureArgument(new Reference($symfonyId))]);
|
||||
}
|
||||
|
||||
foreach ($config['factories'] as $doctrineId => $symfonyId) {
|
||||
$diDefinition->addMethodCall('setDefinition', [$doctrineId, new Reference($symfonyId)]);
|
||||
}
|
||||
|
||||
if (! isset($config['services'][MetadataStorage::class])) {
|
||||
$storageConfiguration = $config['storage']['table_storage'];
|
||||
|
||||
$storageDefinition = new Definition(TableMetadataStorageConfiguration::class);
|
||||
$container->setDefinition('doctrine.migrations.storage.table_storage', $storageDefinition);
|
||||
$container->setAlias('doctrine.migrations.metadata_storage', 'doctrine.migrations.storage.table_storage');
|
||||
|
||||
if ($storageConfiguration['table_name'] !== null) {
|
||||
$storageDefinition->addMethodCall('setTableName', [$storageConfiguration['table_name']]);
|
||||
}
|
||||
|
||||
if ($storageConfiguration['version_column_name'] !== null) {
|
||||
$storageDefinition->addMethodCall('setVersionColumnName', [$storageConfiguration['version_column_name']]);
|
||||
}
|
||||
|
||||
if ($storageConfiguration['version_column_length'] !== null) {
|
||||
$storageDefinition->addMethodCall('setVersionColumnLength', [$storageConfiguration['version_column_length']]);
|
||||
}
|
||||
|
||||
if ($storageConfiguration['executed_at_column_name'] !== null) {
|
||||
$storageDefinition->addMethodCall('setExecutedAtColumnName', [$storageConfiguration['executed_at_column_name']]);
|
||||
}
|
||||
|
||||
if ($storageConfiguration['execution_time_column_name'] !== null) {
|
||||
$storageDefinition->addMethodCall('setExecutionTimeColumnName', [$storageConfiguration['execution_time_column_name']]);
|
||||
}
|
||||
|
||||
$configurationDefinition->addMethodCall('setMetadataStorageConfiguration', [new Reference('doctrine.migrations.storage.table_storage')]);
|
||||
}
|
||||
|
||||
if ($config['em'] !== null && $config['connection'] !== null) {
|
||||
throw new InvalidArgumentException(
|
||||
'You cannot specify both "connection" and "em" in the DoctrineMigrationsBundle configurations.'
|
||||
);
|
||||
}
|
||||
|
||||
$container->setParameter('doctrine.migrations.preferred_em', $config['em']);
|
||||
$container->setParameter('doctrine.migrations.preferred_connection', $config['connection']);
|
||||
|
||||
if (interface_exists(ContainerAwareInterface::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$container->removeDefinition('doctrine.migrations.container_aware_migrations_factory');
|
||||
}
|
||||
|
||||
private function checkIfBundleRelativePath(string $path, ContainerBuilder $container): string
|
||||
{
|
||||
if (isset($path[0]) && $path[0] === '@') {
|
||||
$pathParts = explode('/', $path);
|
||||
$bundleName = substr($pathParts[0], 1);
|
||||
|
||||
$bundlePath = $this->getBundlePath($bundleName, $container);
|
||||
|
||||
return $bundlePath . substr($path, strlen('@' . $bundleName));
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
private function getBundlePath(string $bundleName, ContainerBuilder $container): string
|
||||
{
|
||||
$bundleMetadata = $container->getParameter('kernel.bundles_metadata');
|
||||
assert(is_array($bundleMetadata));
|
||||
|
||||
if (! isset($bundleMetadata[$bundleName])) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'The bundle "%s" has not been registered, available bundles: %s',
|
||||
$bundleName,
|
||||
implode(', ', array_keys($bundleMetadata))
|
||||
));
|
||||
}
|
||||
|
||||
return $bundleMetadata[$bundleName]['path'];
|
||||
}
|
||||
|
||||
private function registerCollector(ContainerBuilder $container): void
|
||||
{
|
||||
$flattenerDefinition = new Definition(MigrationsFlattener::class);
|
||||
$container->setDefinition('doctrine_migrations.migrations_flattener', $flattenerDefinition);
|
||||
|
||||
$collectorDefinition = new Definition(MigrationsCollector::class, [
|
||||
new Reference('doctrine.migrations.dependency_factory'),
|
||||
new Reference('doctrine_migrations.migrations_flattener'),
|
||||
]);
|
||||
$collectorDefinition
|
||||
->addTag('data_collector', [
|
||||
'template' => '@DoctrineMigrations/Collector/migrations.html.twig',
|
||||
'id' => 'doctrine_migrations',
|
||||
'priority' => '249',
|
||||
]);
|
||||
$container->setDefinition('doctrine_migrations.migrations_collector', $collectorDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base path for the XSD files.
|
||||
*
|
||||
* @return string The XSD base path
|
||||
*/
|
||||
public function getXsdValidationBasePath(): string
|
||||
{
|
||||
return __DIR__ . '/../Resources/config/schema';
|
||||
}
|
||||
|
||||
public function getNamespace(): string
|
||||
{
|
||||
return 'http://symfony.com/schema/dic/doctrine/migrations/3.0';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MigrationsBundle;
|
||||
|
||||
use Doctrine\Bundle\MigrationsBundle\DependencyInjection\CompilerPass\ConfigureDependencyFactoryPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
/**
|
||||
* Bundle.
|
||||
*/
|
||||
class DoctrineMigrationsBundle extends Bundle
|
||||
{
|
||||
/** @return void */
|
||||
public function build(ContainerBuilder $container)
|
||||
{
|
||||
$container->addCompilerPass(new ConfigureDependencyFactoryPass());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2006-2013 Doctrine Project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MigrationsBundle\MigrationsFactory;
|
||||
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
use Doctrine\Migrations\Version\MigrationFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
use function trigger_deprecation;
|
||||
|
||||
/** @deprecated This class is not compatible with Symfony >= 7 */
|
||||
class ContainerAwareMigrationFactory implements MigrationFactory
|
||||
{
|
||||
/** @var ContainerInterface */
|
||||
private $container;
|
||||
|
||||
/** @var MigrationFactory */
|
||||
private $migrationFactory;
|
||||
|
||||
public function __construct(MigrationFactory $migrationFactory, ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->migrationFactory = $migrationFactory;
|
||||
}
|
||||
|
||||
public function createVersion(string $migrationClassName): AbstractMigration
|
||||
{
|
||||
$migration = $this->migrationFactory->createVersion($migrationClassName);
|
||||
|
||||
if ($migration instanceof ContainerAwareInterface) {
|
||||
trigger_deprecation('doctrine/doctrine-migrations-bundle', '3.3', 'Migration "%s" implements "%s" to gain access to the application\'s service container. This method is deprecated and won\'t work with Symfony 7.', $migrationClassName, ContainerAwareInterface::class);
|
||||
|
||||
$migration->setContainer($this->container);
|
||||
}
|
||||
|
||||
return $migration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
DoctrineMigrationsBundle
|
||||
========================
|
||||
|
||||
This bundle integrates the [Doctrine Migrations library](http://www.doctrine-project.org/projects/migrations.html)
|
||||
into Symfony applications. Database migrations help you version the changes in
|
||||
your database schema and apply them in a predictable way on every server running
|
||||
the application.
|
||||
|
||||
[Read the documentation of this bundle](https://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html).
|
||||
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<xsd:schema xmlns="http://symfony.com/schema/dic/doctrine/migrations/3.0"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://symfony.com/schema/dic/doctrine/migrations/3.0"
|
||||
elementFormDefault="qualified"
|
||||
>
|
||||
|
||||
<xsd:element name="config">
|
||||
<xsd:complexType>
|
||||
|
||||
<xsd:sequence>
|
||||
<xsd:element name="migrations-path" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="namespace" type="xsd:string"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="services" maxOccurs="unbounded" minOccurs="0">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="service" type="xsd:string"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
<xsd:element name="migration" type="xsd:string" maxOccurs="unbounded" minOccurs="0"/>
|
||||
|
||||
<xsd:element name="storage" minOccurs="0">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="table-storage" minOccurs="0">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="table-name" type="xsd:string"/>
|
||||
<xsd:attribute name="version-column-name" type="xsd:string"/>
|
||||
<xsd:attribute name="version-column-length" type="xsd:positiveInteger"/>
|
||||
<xsd:attribute name="executed-at-column-name" type="xsd:string"/>
|
||||
<xsd:attribute name="execution-time-column-name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="em" type="xsd:string"/>
|
||||
<xsd:attribute name="connection" type="xsd:string"/>
|
||||
<xsd:attribute name="sorter" type="xsd:string"/>
|
||||
<xsd:attribute name="all_or_nothing" type="xsd:boolean"/>
|
||||
<xsd:attribute name="check_database_platform" type="xsd:boolean"/>
|
||||
<xsd:attribute name="custom_template" type="xsd:string"/>
|
||||
<xsd:attribute name="organize-migrations">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="BY_YEAR"/>
|
||||
<xsd:enumeration value="BY_YEAR_AND_MONTH"/>
|
||||
<xsd:enumeration value="false"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
</xsd:schema>
|
||||
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
|
||||
<service id="doctrine.migrations.dependency_factory" class="Doctrine\Migrations\DependencyFactory" public="false">
|
||||
<factory></factory>
|
||||
<argument type="service" id="doctrine.migrations.configuration_loader"/>
|
||||
<argument></argument>
|
||||
<argument type="service" id="logger" on-invalid="null"></argument>
|
||||
</service>
|
||||
|
||||
<service id="doctrine.migrations.configuration_loader" class="Doctrine\Migrations\Configuration\Migration\ExistingConfiguration" public="false">
|
||||
<argument type="service" id="doctrine.migrations.configuration"/>
|
||||
</service>
|
||||
|
||||
<service id="doctrine.migrations.connection_loader" class="Doctrine\Migrations\Configuration\Connection\ExistingConnection" public="false">
|
||||
|
||||
</service>
|
||||
|
||||
<service id="doctrine.migrations.em_loader" class="Doctrine\Migrations\Configuration\EntityManager\ExistingEntityManager" public="false">
|
||||
|
||||
</service>
|
||||
|
||||
<service id="doctrine.migrations.entity_manager_registry_loader" class="Doctrine\Migrations\Configuration\EntityManager\ManagerRegistryEntityManager" public="false">
|
||||
<factory class="Doctrine\Migrations\Configuration\EntityManager\ManagerRegistryEntityManager" method="withSimpleDefault"/>
|
||||
<argument type="service" id="doctrine"/>
|
||||
</service>
|
||||
|
||||
<service id="doctrine.migrations.connection_registry_loader" class="Doctrine\Migrations\Configuration\Connection\ConnectionRegistryConnection" public="false">
|
||||
<factory class="Doctrine\Migrations\Configuration\Connection\ConnectionRegistryConnection" method="withSimpleDefault"/>
|
||||
<argument type="service" id="doctrine"/>
|
||||
</service>
|
||||
|
||||
<service id="doctrine.migrations.configuration" class="Doctrine\Migrations\Configuration\Configuration" public="false">
|
||||
</service>
|
||||
|
||||
<service id="doctrine.migrations.migrations_factory" class="Doctrine\Migrations\Version\MigrationFactory">
|
||||
<factory service="doctrine.migrations.dependency_factory" method="getMigrationFactory"/>
|
||||
</service>
|
||||
|
||||
<service id="doctrine.migrations.container_aware_migrations_factory"
|
||||
class="Doctrine\Bundle\MigrationsBundle\MigrationsFactory\ContainerAwareMigrationFactory"
|
||||
decorates="doctrine.migrations.migrations_factory"
|
||||
>
|
||||
<argument id="doctrine.migrations.container_aware_migrations_factory.inner" type="service"/>
|
||||
<argument id="service_container" type="service"/>
|
||||
</service>
|
||||
|
||||
<service id="doctrine_migrations.diff_command" class="Doctrine\Migrations\Tools\Console\Command\DiffCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:diff</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:diff" />
|
||||
</service>
|
||||
|
||||
<service id="doctrine_migrations.sync_metadata_command" class="Doctrine\Migrations\Tools\Console\Command\SyncMetadataCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:sync-metadata-storage</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:sync-metadata-storage" />
|
||||
</service>
|
||||
|
||||
<service id="doctrine_migrations.versions_command" class="Doctrine\Migrations\Tools\Console\Command\ListCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:versions</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:list" />
|
||||
</service>
|
||||
|
||||
<service id="doctrine_migrations.current_command" class="Doctrine\Migrations\Tools\Console\Command\CurrentCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:current</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:current"/>
|
||||
</service>
|
||||
|
||||
<service id="doctrine_migrations.dump_schema_command" class="Doctrine\Migrations\Tools\Console\Command\DumpSchemaCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:dump-schema</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:dump-schema"/>
|
||||
</service>
|
||||
<service id="doctrine_migrations.execute_command" class="Doctrine\Migrations\Tools\Console\Command\ExecuteCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:execute</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:execute"/>
|
||||
</service>
|
||||
<service id="doctrine_migrations.generate_command" class="Doctrine\Migrations\Tools\Console\Command\GenerateCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:generate</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:generate"/>
|
||||
</service>
|
||||
<service id="doctrine_migrations.latest_command" class="Doctrine\Migrations\Tools\Console\Command\LatestCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:latest</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:latest"/>
|
||||
</service>
|
||||
<service id="doctrine_migrations.migrate_command" class="Doctrine\Migrations\Tools\Console\Command\MigrateCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:migrate</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:migrate" />
|
||||
</service>
|
||||
<service id="doctrine_migrations.rollup_command" class="Doctrine\Migrations\Tools\Console\Command\RollupCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:rollup</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:rollup" />
|
||||
</service>
|
||||
<service id="doctrine_migrations.status_command" class="Doctrine\Migrations\Tools\Console\Command\StatusCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:status</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:status" />
|
||||
</service>
|
||||
<service id="doctrine_migrations.up_to_date_command" class="Doctrine\Migrations\Tools\Console\Command\UpToDateCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:up-to-date</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:up-to-date" />
|
||||
</service>
|
||||
<service id="doctrine_migrations.version_command" class="Doctrine\Migrations\Tools\Console\Command\VersionCommand">
|
||||
|
||||
<argument type="service" id="doctrine.migrations.dependency_factory"/>
|
||||
<argument>doctrine:migrations:version</argument>
|
||||
|
||||
<tag name="console.command" command="doctrine:migrations:version" />
|
||||
</service>
|
||||
|
||||
</services>
|
||||
|
||||
</container>
|
||||
@@ -0,0 +1,467 @@
|
||||
DoctrineMigrationsBundle
|
||||
========================
|
||||
|
||||
Database migrations are a way to safely update your database schema both locally
|
||||
and on production. Instead of running the ``doctrine:schema:update`` command or
|
||||
applying the database changes manually with SQL statements, migrations allow to
|
||||
replicate the changes in your database schema in a safe manner.
|
||||
|
||||
Migrations are available in Symfony applications via the `DoctrineMigrationsBundle`_,
|
||||
which uses the external `Doctrine Database Migrations`_ library. Read the
|
||||
`documentation`_ of that library if you need a general introduction about migrations.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Run this command in your terminal:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ composer require doctrine/doctrine-migrations-bundle "^3.0"
|
||||
|
||||
If you don't use `Symfony Flex`_, you must enable the bundle manually in the application:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// config/bundles.php
|
||||
// in older Symfony apps, enable the bundle in app/AppKernel.php
|
||||
return [
|
||||
// ...
|
||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||
];
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
If you use Symfony Flex, the ``doctrine_migrations.yaml`` config file is created
|
||||
automatically. Otherwise, create the following file and configure it for your
|
||||
application:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/doctrine_migrations.yaml
|
||||
|
||||
doctrine_migrations:
|
||||
# List of namespace/path pairs to search for migrations, at least one required
|
||||
migrations_paths:
|
||||
'App\Migrations': '%kernel.project_dir%/src/App'
|
||||
'AnotherApp\Migrations': '/path/to/other/migrations'
|
||||
'SomeBundle\Migrations': '@SomeBundle/Migrations'
|
||||
|
||||
# List of additional migration classes to be loaded, optional
|
||||
migrations:
|
||||
- 'App\Migrations\Version123'
|
||||
- 'App\Migrations\Version123'
|
||||
|
||||
# Connection to use for the migrations
|
||||
connection: default
|
||||
|
||||
# Entity manager to use for migrations. This overrides the "connection" setting.
|
||||
em: default
|
||||
|
||||
storage:
|
||||
# Default (SQL table) metadata storage configuration
|
||||
table_storage:
|
||||
table_name: 'doctrine_migration_versions'
|
||||
version_column_name: 'version'
|
||||
version_column_length: 192
|
||||
executed_at_column_name: 'executed_at'
|
||||
|
||||
# Possible values: "BY_YEAR", "BY_YEAR_AND_MONTH", false
|
||||
organize_migrations: false
|
||||
|
||||
# Path to your custom migrations template
|
||||
custom_template: ~
|
||||
|
||||
# Run all migrations in a transaction.
|
||||
all_or_nothing: false
|
||||
|
||||
# Adds an extra check in the generated migrations to ensure that is executed on the same database type.
|
||||
check_database_platform: true
|
||||
|
||||
# Whether or not to wrap migrations in a single transaction.
|
||||
transactional: true
|
||||
|
||||
# Whether or not to enable the profiler collector to calculate and visualize migration status. This adds some queries overhead.
|
||||
# enable_profiler: false
|
||||
|
||||
services:
|
||||
# Custom migration sorting service id
|
||||
'Doctrine\Migrations\Version\Comparator': ~
|
||||
|
||||
# Custom migration classes factory
|
||||
'Doctrine\Migrations\Version\MigrationFactory': ~
|
||||
|
||||
factories:
|
||||
# Custom migration sorting service id via callables (MyCallableFactory must be a callable)
|
||||
'Doctrine\Migrations\Version\Comparator': 'MyCallableFactory'
|
||||
|
||||
- The ``services`` node allows you to provide custom services to the underlying ``DependencyFactory`` part of ``doctrine/migrations``.
|
||||
- The node ``factories`` is similar to ``services``, with the difference that it accepts only callables.
|
||||
|
||||
The provided callable must return the service to be passed to the ``DependencyFactory``.
|
||||
The callable will receive as first argument the ``DependencyFactory`` itself,
|
||||
allowing you to fetch other dependencies from the factory while instantiating your custom dependencies.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
All of the migrations functionality is contained in a few console commands:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
doctrine
|
||||
doctrine:migrations:current [current] Outputs the current version.
|
||||
doctrine:migrations:diff [diff] Generate a migration by comparing your current database to your mapping information.
|
||||
doctrine:migrations:dump-schema [dump-schema] Dump the schema for your database to a migration.
|
||||
doctrine:migrations:execute [execute] Execute a single migration version up or down manually.
|
||||
doctrine:migrations:generate [generate] Generate a blank migration class.
|
||||
doctrine:migrations:latest [latest] Outputs the latest version number
|
||||
doctrine:migrations:migrate [migrate] Execute a migration to a specified version or the latest available version.
|
||||
doctrine:migrations:rollup [rollup] Roll migrations up by deleting all tracked versions and inserting the one version that exists.
|
||||
doctrine:migrations:status [status] View the status of a set of migrations.
|
||||
doctrine:migrations:up-to-date [up-to-date] Tells you if your schema is up-to-date.
|
||||
doctrine:migrations:version [version] Manually add and delete migration versions from the version table.
|
||||
doctrine:migrations:sync-metadata-storage [sync-metadata-storage] Ensures that the metadata storage is at the latest version.
|
||||
doctrine:migrations:list [list-migrations] Display a list of all available migrations and their status.
|
||||
|
||||
Start by getting the status of migrations in your application by running
|
||||
the ``status`` command:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ php bin/console doctrine:migrations:status
|
||||
|
||||
This command will show you generic information about the migration status, such as how many migrations have been
|
||||
already executed, which still need to run, and the database in use.
|
||||
|
||||
Now, you can start working with migrations by generating a new blank migration
|
||||
class. Later, you'll learn how Doctrine can generate migrations automatically
|
||||
for you.
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ php bin/console doctrine:migrations:generate
|
||||
|
||||
Have a look at the newly generated migration class and you will see something
|
||||
like the following:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20180605025653 extends AbstractMigration
|
||||
{
|
||||
public function getDescription() : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema) : void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
|
||||
}
|
||||
|
||||
public function down(Schema $schema) : void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
If you run the ``status`` command again it will now show that you have one new
|
||||
migration to execute:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ php bin/console doctrine:migrations:status
|
||||
|
||||
Now you can add some migration code to the ``up()`` and ``down()`` methods and
|
||||
finally migrate when you're ready:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ php bin/console doctrine:migrations:migrate 'DoctrineMigrations\Version20180605025653'
|
||||
|
||||
For more information on how to write the migrations themselves (i.e. how to
|
||||
fill in the ``up()`` and ``down()`` methods), see the official Doctrine Migrations
|
||||
`documentation`_.
|
||||
|
||||
Running Migrations during Deployment
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Of course, the end goal of writing migrations is to be able to use them to
|
||||
reliably update your database structure when you deploy your application.
|
||||
By running the migrations locally (or on a beta server), you can ensure that
|
||||
the migrations work as you expect.
|
||||
|
||||
When you do finally deploy your application, you just need to remember to run
|
||||
the ``doctrine:migrations:migrate`` command. Internally, Doctrine creates
|
||||
a ``migration_versions`` table inside your database and tracks which migrations
|
||||
have been executed there. So, no matter how many migrations you've created
|
||||
and executed locally, when you run the command during deployment, Doctrine
|
||||
will know exactly which migrations it hasn't run yet by looking at the ``migration_versions``
|
||||
table of your production database. Regardless of what server you're on, you
|
||||
can always safely run this command to execute only the migrations that haven't
|
||||
been run yet on *that* particular database.
|
||||
|
||||
Skipping Migrations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can skip single migrations by explicitly adding them to the ``migration_versions`` table:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ php bin/console doctrine:migrations:version 'App\Migrations\Version123' --add
|
||||
|
||||
.. tip::
|
||||
|
||||
Pay attention to the single quotes (``'``) used in the command above, without them
|
||||
or with the double quotes (``"``) the command will not work properly.
|
||||
|
||||
|
||||
Doctrine will then assume that this migration has already been run and will ignore it.
|
||||
|
||||
Migration Dependencies
|
||||
----------------------
|
||||
|
||||
Migrations can have dependencies on external services (such as geolocation, mailer, data processing services...) that
|
||||
can be used to have more powerful migrations. Those dependencies are not automatically injected into your migrations
|
||||
but need to be injected using custom migrations factories.
|
||||
|
||||
Here is an example on how to inject the service container into your migrations:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/doctrine_migrations.yaml
|
||||
doctrine_migrations:
|
||||
services:
|
||||
'Doctrine\Migrations\Version\MigrationFactory': 'App\Migrations\Factory\MigrationFactoryDecorator'
|
||||
|
||||
# config/services.yaml
|
||||
services:
|
||||
App\Migrations\Factory\MigrationFactoryDecorator:
|
||||
decorates: 'doctrine.migrations.migrations_factory'
|
||||
arguments: ['@.inner', '@service_container']
|
||||
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Migrations\Factory;
|
||||
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
use Doctrine\Migrations\Version\MigrationFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class MigrationFactoryDecorator implements MigrationFactory
|
||||
{
|
||||
private $migrationFactory;
|
||||
private $container;
|
||||
|
||||
public function __construct(MigrationFactory $migrationFactory, ContainerInterface $container)
|
||||
{
|
||||
$this->migrationFactory = $migrationFactory;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function createVersion(string $migrationClassName): AbstractMigration
|
||||
{
|
||||
$instance = $this->migrationFactory->createVersion($migrationClassName);
|
||||
|
||||
if ($instance instanceof ContainerAwareInterface) {
|
||||
$instance->setContainer($this->container);
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.. tip::
|
||||
|
||||
If your migration class implements the interface ``Symfony\Component\DependencyInjection\ContainerAwareInterface``
|
||||
this bundle will automatically inject the default symfony container into your migration class
|
||||
(this because the ``MigrationFactoryDecorator`` shown in this example is the default migration factory used by this bundle).
|
||||
|
||||
|
||||
Generating Migrations Automatically
|
||||
-----------------------------------
|
||||
|
||||
In reality, you should rarely need to write migrations manually, as the migrations
|
||||
library can generate migration classes automatically by comparing your Doctrine
|
||||
mapping information (i.e. what your database *should* look like) with your
|
||||
actual current database structure.
|
||||
|
||||
For example, suppose you create a new ``User`` entity and add mapping information
|
||||
for Doctrine's ORM:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php-annotations
|
||||
|
||||
// src/Entity/User.php
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="hello_user")
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $name;
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/doctrine/User.orm.yaml
|
||||
App\Entity\User:
|
||||
type: entity
|
||||
table: user
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
name:
|
||||
type: string
|
||||
length: 255
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/doctrine/User.orm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="App\Entity\User" table="user">
|
||||
<id name="id" type="integer" column="id">
|
||||
<generator strategy="AUTO"/>
|
||||
</id>
|
||||
<field name="name" column="name" type="string" length="255" />
|
||||
</entity>
|
||||
|
||||
</doctrine-mapping>
|
||||
|
||||
With this information, Doctrine is now ready to help you persist your new
|
||||
``User`` object to and from the ``user`` table. Of course, this table
|
||||
doesn't exist yet! Generate a new migration for this table automatically by
|
||||
running the following command:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ php bin/console doctrine:migrations:diff
|
||||
|
||||
You should see a message that a new migration class was generated based on
|
||||
the schema differences. If you open this file, you'll find that it has the
|
||||
SQL code needed to create the ``user`` table. Next, run the migration
|
||||
to add the table to your database:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ php bin/console doctrine:migrations:migrate
|
||||
|
||||
The moral of the story is this: after each change you make to your Doctrine
|
||||
mapping information, run the ``doctrine:migrations:diff`` command to automatically
|
||||
generate your migration classes.
|
||||
|
||||
If you do this from the very beginning of your project (i.e. so that even
|
||||
the first tables were loaded via a migration class), you'll always be able
|
||||
to create a fresh database and run your migrations in order to get your database
|
||||
schema fully up to date. In fact, this is an easy and dependable workflow
|
||||
for your project.
|
||||
|
||||
If you don't want to use this workflow and instead create your schema via
|
||||
``doctrine:schema:create``, you can tell Doctrine to skip all existing migrations:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ php bin/console doctrine:migrations:version --add --all
|
||||
|
||||
Otherwise Doctrine will try to run all migrations, which probably will not work.
|
||||
|
||||
Manual Tables
|
||||
-------------
|
||||
|
||||
It is a common use case, that in addition to your generated database structure
|
||||
based on your doctrine entities you might need custom tables. By default such
|
||||
tables will be removed by the ``doctrine:migrations:diff`` command.
|
||||
|
||||
If you follow a specific scheme you can configure doctrine/dbal to ignore those
|
||||
tables. Let's say all custom tables will be prefixed by ``t_``. In this case you
|
||||
just have to add the following configuration option to your doctrine configuration:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
doctrine:
|
||||
dbal:
|
||||
schema_filter: ~^(?!t_)~
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine:dbal schema-filter="~^(?!t_)~" />
|
||||
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$container->loadFromExtension('doctrine', array(
|
||||
'dbal' => array(
|
||||
'schema_filter' => '~^(?!t_)~',
|
||||
// ...
|
||||
),
|
||||
// ...
|
||||
));
|
||||
|
||||
This ignores the tables, and any named objects such as sequences, on the DBAL level and they will be ignored by the diff command.
|
||||
|
||||
Note that if you have multiple connections configured then the ``schema_filter`` configuration
|
||||
will need to be placed per-connection.
|
||||
|
||||
Troubleshooting out of sync metadata storage issue
|
||||
--------------------------------------------------
|
||||
``doctrine/migrations`` relies on a properly configured Database server version in the connection string to manage the table storing the
|
||||
migrations, also known as the metadata storage.
|
||||
|
||||
If you encounter the error ``The metadata storage is not up to date, please run the sync-metadata-storage command to fix this issue.``
|
||||
when running the command ``doctrine:migrations:migrate`` or the suggested command itself ``doctrine:migrations:sync-metadata-storage`` please
|
||||
check the database connection string, and make sure that the proper server version is defined. If you are running a MariaDB database,
|
||||
you should prefix the server version with ``mariadb-`` (ex: ``mariadb-10.2.12``). See the `configuring_database`_ section.
|
||||
|
||||
Example connection string for MariaDB:
|
||||
|
||||
.. code-block:: terminal
|
||||
DATABASE_URL=mysql://root:@127.0.0.1:3306/testtest?serverVersion=mariadb-10.4.11
|
||||
|
||||
.. _documentation: https://www.doctrine-project.org/projects/doctrine-migrations/en/current/index.html
|
||||
.. _configuring_database: https://symfony.com/doc/current/doctrine.html#configuring-the-database
|
||||
.. _DoctrineMigrationsBundle: https://github.com/doctrine/DoctrineMigrationsBundle
|
||||
.. _`Doctrine Database Migrations`: https://github.com/doctrine/migrations
|
||||
.. _`Symfony Flex`: https://symfony.com/doc/current/setup/flex.html
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" data-icon-name="icon-tabler-versions" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<rect x="10" y="5" width="10" height="14" rx="2"></rect>
|
||||
<line x1="7" y1="7" x2="7" y2="17"></line>
|
||||
<line x1="4" y1="8" x2="4" y2="16"></line>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 446 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<polygon fill="#AAA" points="0 0 24 0 24 7 17.5 7 16.5 3 15.5 7 11 7 12 3 3 3 4 7 0 7" />
|
||||
<polygon fill="#AAA" points="0 8.5 4.5 8.5 6 15.5 0 15.5" />
|
||||
<polygon fill="#AAA" points="10.5 8.5 15 8.5 13.5 15.5 9 15.5" />
|
||||
<polygon fill="#AAA" points="18 8.5 24 8.5 24 15.5 19.5 15.5" />
|
||||
<polygon fill="#AAA" points="0 17 6.5 17 7.5 21 8.5 17 13 17 12 21 21 21 20 17 24 17 24 24 0 24" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 493 B |
+252
@@ -0,0 +1,252 @@
|
||||
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
|
||||
|
||||
{% block toolbar %}
|
||||
{% if collector.data.unavailable_migrations_count is defined %}
|
||||
{% set unavailable_migrations = collector.data.unavailable_migrations_count %}
|
||||
{% set new_migrations = collector.data.new_migrations|length %}
|
||||
{% if unavailable_migrations > 0 or new_migrations > 0 %}
|
||||
{% set executed_migrations = collector.data.executed_migrations|length %}
|
||||
{% set available_migrations = collector.data.available_migrations_count %}
|
||||
{% set status_color = unavailable_migrations > 0 ? 'yellow' : '' %}
|
||||
{% set status_color = new_migrations > 0 ? 'red' : status_color %}
|
||||
|
||||
{% set icon %}
|
||||
{% if profiler_markup_version < 3 %}
|
||||
{{ include('@DoctrineMigrations/Collector/icon.svg') }}
|
||||
{% else %}
|
||||
{{ include('@DoctrineMigrations/Collector/icon-v3.svg') }}
|
||||
{% endif %}
|
||||
|
||||
<span class="sf-toolbar-value">{{ new_migrations + unavailable_migrations }}</span>
|
||||
{% endset %}
|
||||
|
||||
{% set text %}
|
||||
<div class="sf-toolbar-info-group">
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Current Migration</b>
|
||||
<span>{{ executed_migrations > 0 ? collector.data.executed_migrations|last.version|split('\\')|last : 'n/a' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sf-toolbar-info-group">
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<span class="sf-toolbar-header">
|
||||
<b>Database Migrations</b>
|
||||
</span>
|
||||
</div>
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Executed</b>
|
||||
<span class="sf-toolbar-status">{{ executed_migrations }}</span>
|
||||
</div>
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Unavailable</b>
|
||||
<span class="sf-toolbar-status {{ unavailable_migrations > 0 ? 'sf-toolbar-status-yellow' }}">{{ unavailable_migrations }}</span>
|
||||
</div>
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Available</b>
|
||||
<span class="sf-toolbar-status">{{ available_migrations }}</span>
|
||||
</div>
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>New</b>
|
||||
<span class="sf-toolbar-status {{ new_migrations > 0 ? 'sf-toolbar-status-red' }}">{{ new_migrations }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endset %}
|
||||
|
||||
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url, status: status_color }) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block menu %}
|
||||
{% if collector.data.unavailable_migrations_count is defined %}
|
||||
{% set unavailable_migrations = collector.data.unavailable_migrations_count %}
|
||||
{% set new_migrations = collector.data.new_migrations|length %}
|
||||
{% set label = unavailable_migrations > 0 ? 'label-status-warning' : '' %}
|
||||
{% set label = new_migrations > 0 ? 'label-status-error' : label %}
|
||||
<span class="label {{ label }}">
|
||||
<span class="icon">
|
||||
{% if profiler_markup_version < 3 %}
|
||||
{{ include('@DoctrineMigrations/Collector/icon.svg') }}
|
||||
{% else %}
|
||||
{{ include('@DoctrineMigrations/Collector/icon-v3.svg') }}
|
||||
{% endif %}
|
||||
</span>
|
||||
|
||||
<strong>Migrations</strong>
|
||||
{% if unavailable_migrations > 0 or new_migrations > 0 %}
|
||||
<span class="count">
|
||||
<span>{{ new_migrations + unavailable_migrations }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block panel %}
|
||||
{% set num_executed_migrations = collector.data.executed_migrations|length %}
|
||||
{% set num_unavailable_migrations = collector.data.unavailable_migrations_count %}
|
||||
{% set num_available_migrations = collector.data.available_migrations_count %}
|
||||
{% set num_new_migrations = collector.data.new_migrations|length %}
|
||||
|
||||
<h2>Doctrine Migrations</h2>
|
||||
<div class="metrics">
|
||||
<div class="metric">
|
||||
<span class="value">{{ num_executed_migrations }}</span>
|
||||
<span class="label">Executed</span>
|
||||
</div>
|
||||
|
||||
{% if profiler_markup_version >= 3 %}
|
||||
<div class="metric-group">
|
||||
{% endif %}
|
||||
|
||||
<div class="metric">
|
||||
<span class="value">{{ num_unavailable_migrations }}</span>
|
||||
<span class="label">Unavailable</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="value">{{ num_available_migrations }}</span>
|
||||
<span class="label">Available</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="value">{{ num_new_migrations }}</span>
|
||||
<span class="label">New</span>
|
||||
</div>
|
||||
|
||||
{% if profiler_markup_version >= 3 %}
|
||||
</div> {# closes the <div class="metric-group"> #}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="sf-tabs">
|
||||
<div class="tab">
|
||||
<h3 class="tab-title">
|
||||
Migrations
|
||||
<span class="badge {{ num_new_migrations > 0 ? 'status-error' : num_unavailable_migrations > 0 ? 'status-warning' }}">
|
||||
{{ num_new_migrations > 0 ? num_new_migrations : num_unavailable_migrations > 0 ? num_unavailable_migrations : num_executed_migrations }}
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<div class="tab-content">
|
||||
{{ _self.render_migration_details(collector, profiler_markup_version) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab">
|
||||
<h3 class="tab-title">Configuration</h3>
|
||||
|
||||
<div class="tab-content">
|
||||
{{ _self.render_configuration_details(collector, profiler_markup_version) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro render_migration_details(collector) %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="colored font-normal">Version</th>
|
||||
<th class="colored font-normal">Description</th>
|
||||
<th class="colored font-normal">Status</th>
|
||||
<th class="colored font-normal">Executed at</th>
|
||||
<th class="colored font-normal text-right">Execution time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for migration in collector.data.new_migrations %}
|
||||
{{ _self.render_migration(migration) }}
|
||||
{% endfor %}
|
||||
|
||||
{% for migration in collector.data.executed_migrations|reverse %}
|
||||
{{ _self.render_migration(migration) }}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_configuration_details(collector) %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2" class="colored font-normal">Storage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="font-normal">Type</td>
|
||||
<td class="font-normal">{{ collector.data.storage }}</td>
|
||||
</tr>
|
||||
{% if collector.data.table is defined %}
|
||||
<tr>
|
||||
<td class="font-normal">Table Name</td>
|
||||
<td class="font-normal">{{ collector.data.table }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if collector.data.column is defined %}
|
||||
<tr>
|
||||
<td class="font-normal">Column Name</td>
|
||||
<td class="font-normal">{{ collector.data.column }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2" class="colored font-normal">Database</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="font-normal">Driver</td>
|
||||
<td class="font-normal">{{ collector.data.driver }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-normal">Name</td>
|
||||
<td class="font-normal">{{ collector.data.name }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2" class="colored font-normal">Migration Namespaces</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for namespace, directory in collector.data.namespaces %}
|
||||
<tr>
|
||||
<td class="font-normal">{{ namespace }}</td>
|
||||
<td class="font-normal">{{ directory }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_migration(migration, profiler_markup_version) %}
|
||||
<tr>
|
||||
<td class="font-normal">
|
||||
{% if migration.file %}
|
||||
<a href="{{ migration.file|file_link(1) }}" title="{{ migration.file }}">{{ migration.version }}</a>
|
||||
{% else %}
|
||||
{{ migration.version }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="font-normal">{{ migration.description }}</td>
|
||||
<td class="font-normal align-right">
|
||||
{% if migration.is_new %}
|
||||
<span class="{{ profiler_markup_version >= 3 ? 'badge badge-error' : 'label status-error' }}">NOT EXECUTED</span>
|
||||
{% elseif migration.is_unavailable %}
|
||||
<span class="{{ profiler_markup_version >= 3 ? 'badge badge-warning' : 'label status-warning' }}">UNAVAILABLE</span>
|
||||
{% else %}
|
||||
<span class="{{ profiler_markup_version >= 3 ? 'badge badge-success' : 'label status-success' }}">EXECUTED</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="font-normal">{{ migration.executed_at ? migration.executed_at|date('M j, Y H:i') : 'n/a' }}</td>
|
||||
<td class="font-normal text-right">
|
||||
{% if migration.execution_time is null %}
|
||||
n/a
|
||||
{% elseif migration.execution_time < 1 %}
|
||||
{{ (migration.execution_time * 1000)|number_format(0) }} ms
|
||||
{% else %}
|
||||
{{ migration.execution_time|number_format(2) }} seconds
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endmacro %}
|
||||
@@ -0,0 +1,86 @@
|
||||
# Upgrade
|
||||
|
||||
## From 2.x to 3.0.0
|
||||
|
||||
- The configuration for the migration namespace and directory changed as follows:
|
||||
|
||||
Before
|
||||
|
||||
```yaml
|
||||
doctrine_migrations:
|
||||
dir_name: '%kernel.project_dir%/src/Migrations'
|
||||
namespace: DoctrineMigrations
|
||||
```
|
||||
|
||||
After
|
||||
|
||||
```yaml
|
||||
doctrine_migrations:
|
||||
migrations_paths:
|
||||
'DoctrineMigrations': '%kernel.project_dir%/src/Migrations'
|
||||
```
|
||||
|
||||
- The configuration for the metadata table definition changed as follows:
|
||||
|
||||
Before
|
||||
|
||||
```yaml
|
||||
doctrine_migrations:
|
||||
table_name: 'migration_versions'
|
||||
column_name: 'version'
|
||||
column_length: 14
|
||||
executed_at_column_name: 'executed_at'
|
||||
```
|
||||
|
||||
After
|
||||
|
||||
```yaml
|
||||
doctrine_migrations:
|
||||
storage:
|
||||
table_storage:
|
||||
table_name: 'migration_versions'
|
||||
version_column_name: 'version'
|
||||
version_column_length: 191
|
||||
executed_at_column_name: 'executed_at'
|
||||
```
|
||||
If your project did not originally specify its own table definition configuration, you will need to configure the table name after the upgrade:
|
||||
|
||||
```yaml
|
||||
doctrine_migrations:
|
||||
storage:
|
||||
table_storage:
|
||||
table_name: 'migration_versions'
|
||||
```
|
||||
and then run the `doctrine:migrations:sync-metadata-storage` command.
|
||||
- The migration name has been dropped:
|
||||
|
||||
Before
|
||||
|
||||
```yaml
|
||||
doctrine_migrations:
|
||||
name: 'Application Migrations'
|
||||
```
|
||||
|
||||
After
|
||||
|
||||
The parameter `name` has been dropped.
|
||||
|
||||
|
||||
- The default for `table_name` changed from `migration_versions` to `doctrine_migration_versions`. If you did not
|
||||
specify the `table_name` option, you now need to declare it explicitly to not lose migration data.
|
||||
|
||||
```yaml
|
||||
doctrine_migrations:
|
||||
storage:
|
||||
table_storage:
|
||||
table_name: 'migration_versions'
|
||||
```
|
||||
|
||||
### Underlying doctrine/migrations library
|
||||
|
||||
Upgrading this bundle to `3.0` will also update the `doctrine/migrations` library to the version `3.0`.
|
||||
Backward incompatible changes in `doctrine/migrations` 3.0
|
||||
are documented in the dedicated [UPGRADE](https://github.com/doctrine/migrations/blob/3.0.x/UPGRADE.md) document.
|
||||
|
||||
- The container is not automatically injected anymore when a migration implements `ContainerAwareInterface`. Custom
|
||||
migration factories should be used to inject additional dependencies into migrations.
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "doctrine/doctrine-migrations-bundle",
|
||||
"type": "symfony-bundle",
|
||||
"description": "Symfony DoctrineMigrationsBundle",
|
||||
"keywords": ["DBAL", "Migrations", "Schema"],
|
||||
"homepage": "https://www.doctrine-project.org",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Doctrine Project",
|
||||
"homepage": "https://www.doctrine-project.org"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.2|^8.0",
|
||||
"symfony/deprecation-contracts": "^2.1 || ^3",
|
||||
"symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0",
|
||||
"doctrine/doctrine-bundle": "^2.4",
|
||||
"doctrine/migrations": "^3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/semver": "^3.0",
|
||||
"phpunit/phpunit": "^8.5|^9.5",
|
||||
"doctrine/coding-standard": "^12",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan-deprecation-rules": "^1",
|
||||
"phpstan/phpstan-phpunit": "^1",
|
||||
"phpstan/phpstan-strict-rules": "^1.1",
|
||||
"phpstan/phpstan-symfony": "^1.3",
|
||||
"doctrine/orm": "^2.6 || ^3",
|
||||
"doctrine/persistence": "^2.0 || ^3 ",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"psalm/plugin-symfony": "^3 || ^5",
|
||||
"symfony/phpunit-bridge": "^6.3 || ^7",
|
||||
"symfony/var-exporter": "^5.4 || ^6 || ^7",
|
||||
"vimeo/psalm": "^4.30 || ^5.15"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Doctrine\\Bundle\\MigrationsBundle\\": "" },
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": { "Doctrine\\Bundle\\MigrationsBundle\\Tests\\": "Tests" }
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||
count: 1
|
||||
path: Collector/MigrationsCollector.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in a negated boolean, Doctrine\\\\Migrations\\\\AbstractMigration\\|null given\\.$#"
|
||||
count: 1
|
||||
path: Collector/MigrationsFlattener.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in a ternary operator condition, Doctrine\\\\Migrations\\\\AbstractMigration\\|null given\\.$#"
|
||||
count: 2
|
||||
path: Collector/MigrationsFlattener.php
|
||||
|
||||
-
|
||||
message: "#^Call to method setContainer\\(\\) on an unknown class Symfony\\\\Component\\\\DependencyInjection\\\\ContainerAwareInterface\\.$#"
|
||||
count: 1
|
||||
path: MigrationsFactory/ContainerAwareMigrationFactory.php
|
||||
|
||||
-
|
||||
message: "#^Class Symfony\\\\Component\\\\DependencyInjection\\\\ContainerAwareInterface not found\\.$#"
|
||||
count: 2
|
||||
path: MigrationsFactory/ContainerAwareMigrationFactory.php
|
||||
Reference in New Issue
Block a user