doctrine / migrations

Doctrine Database Migrations Library
https://www.doctrine-project.org/projects/migrations.html
MIT License
4.68k stars 385 forks source link

cli-config.php compatibility with DBAL #8327 #1070

Open PowerKiKi opened 3 years ago

PowerKiKi commented 3 years ago

Feature Request

Q A
New Feature yes
RFC no
BC Break no

Summary

Since DBAL 2.11.0 and https://github.com/doctrine/dbal/pull/3956, it is now deprecated to use HelperSet in cli-config.php. This will become impossible in DBAL 3, following https://github.com/doctrine/dbal/pull/4059.

This means that, in order to keep sharing a single config file for both packages, this package should also accept the new \Doctrine\DBAL\Tools\Console\ConnectionProvider. It could actually be a new interface along the lines of:

namespace \Doctrine\Migrations\Tools\Console\;

interface ConfigurationProvider extends \Doctrine\DBAL\Tools\Console\ConnectionProvider {

    public function getMigrationConfig() : Configuration;

}

I suppose the support of HelperSet could be drop entirely in the next major version too.

See related https://github.com/doctrine/orm/issues/8327

goetas commented 3 years ago

Migration 3.x should be able to support that in a relatively easy way. Here is the place where the magic happens.

It should be possible to consume the ConnectionProvider interface by creating a class that implements \Doctrine\Migrations\Configuration\Connection\ConnectionLoader::getConnection() (that has more or less the same functionalities)

PowerKiKi commented 3 years ago

I am not entirely sure what you meant with the ConnectionProvider, but I'd rather not implement classes to configure things if possible. So I ended up with a cli-config.php that looks like:

<?php

declare(strict_types=1);

use Doctrine\Migrations\DependencyFactory;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Console\ConsoleRunner;

$container = require 'config/container.php';

// For Doctrine Migration return something custom
global $argv;
if (preg_match('~doctrine-migrations~', $argv[0])) {
    return $container->get(DependencyFactory::class);
}

$entityManager = $container->get(EntityManager::class);

return ConsoleRunner::createHelperSet($entityManager);

It relies on roave/psr-container-doctrine factories to create a DependencyFactory and returns that to doctrine/migrations. While it does work, it is not awesome clean since we must rely on parsing the CLI command to conditionally return one thing for Migration and another thing for DBAL and ORM.

Because this feel more like a workaround, than a proper official solution, I keep the issue open, even though I probably won't investigate any further myself.

cuongngoz commented 2 years ago

HI @PowerKiKi @goetas Btw, how to add migration commands to helperSet, I can do like this with doctrine/migration v2.2.1, but now cannot on v3 because lib/Doctrine/Migrations/Tools/Console/Helper/MigrationsConfigurationHelper.php no longer existed from this https://github.com/doctrine/migrations/commit/7425e17210fb608b6850bcd626b16d028ca42af8

<?php

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Helper\QuestionHelper;
use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\OutputWriter;
use Doctrine\Migrations\Tools\Console\Helper\ConfigurationHelper;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Doctrine\ORM\EntityManager;

$em = $container->get('doctrine.entity_manager.orm_default');
$connection = $em->getConnection();
$appConfig = $container->get('config');
$migrationsConfig = $appConfig['doctrine']['migrations_configuration'];
$output = new ConsoleOutput();
$writer = new OutputWriter(function ($message) use ($output) {
    $output->writeln($message);
});
$configuration = new Configuration($connection, $writer);
$configuration->setMigrationsDirectory($migrationsConfig['directory']);
$configuration->setMigrationsNamespace($migrationsConfig['namespace']);
$configuration->setMigrationsTableName($migrationsConfig['table']);

$helperSet = ConsoleRunner::createHelperSet($em);
$helperSet->set(new ConfigurationHelper($connection, $configuration));  <<<<< this one
$helperSet->set(new QuestionHelper(), 'dialog');

$application = ConsoleRunner::createApplication($helperSet);
Doctrine\Migrations\Tools\Console\ConsoleRunner::addCommands($application);
$application->addCommands(getCustomCommands($appConfig, $container));

$application->run();
cuongngoz commented 2 years ago

Or is this a proper way to do it on v3.3.2?

$configuration = new Configuration();
$configuration->addMigrationsDirectory($migrationsConfig['namespace'], $migrationsConfig['directory']);
$tableMetadataStorageConfiguration = new TableMetadataStorageConfiguration();
$tableMetadataStorageConfiguration->setTableName($migrationsConfig['table']);
$configuration->setMetadataStorageConfiguration($tableMetadataStorageConfiguration);

$dependencyFactory =
    DependencyFactory::fromConnection(new ExistingConfiguration($configuration), new ExistingConnection($connection));

$helperSet = ConsoleRunner::createHelperSet($em);
$helperSet->set(new QuestionHelper(), 'dialog');

$application = ConsoleRunner::createApplication($helperSet);
Doctrine\Migrations\Tools\Console\ConsoleRunner::addCommands($application);
$application->addCommands(getCustomCommands($appConfig, $container));
$application->addCommands(new \Doctrine\Migrations\Tools\Console\Command\MigrateCommand($dependencyFactory));
$application->addCommands(new \Doctrine\Migrations\Tools\Console\Command\DiffCommand($dependencyFactory));

$application->run();