DASPRiD / container-interop-doctrine

Doctrine factories for container-interop
107 stars 25 forks source link

Doctrine Migrations CLI #22

Closed diogodomanski closed 7 years ago

diogodomanski commented 7 years ago

I added doctrine-migrations to my Zend Expressive 2 application and created the following cli-config.php:

<?php
/** 
 * config/cli-config.php
 * For more details @see \DoctrineORMModule\Module
 *
 * Run next commands for Migrations work
 * $ composer require doctrine/doctrine-orm-module
 * $ composer require doctrine/migrations
 */

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

$container = require 'container.php';

/* @var $em \Doctrine\ORM\EntityManager */
$em = $container->get(EntityManager::class);
$configuration = new \Doctrine\DBAL\Migrations\Configuration\ArrayConfiguration($em->getConnection());

return new \Symfony\Component\Console\Helper\HelperSet([
    'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em),
    'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
    'configuration' => new \Doctrine\DBAL\Migrations\Tools\Console\Helper\ConfigurationHelper($em->getConnection(),, $configuration)
]);

When I run ./vendor/bin/doctrine-migrations migrations:generate it works fine, except that the generated file is created in the project's root folder.

I would like to set the migrations directory to /data/Migrations (as I have in another ZF2 application). In that ZF2 application, I have the following migrations_configuration section in doctrine configuration file:

return [
    'doctrine' => [
        'connection' => [
            'orm_default' => [
                // ...
            ],
                ],

        // migrations configuration
        'migrations_configuration' => [
            'orm_default' => [
                'directory' => 'data/Migrations',
                'name'      => 'Doctrine Database Migrations',
                'namespace' => 'Migrations',
                'table'     => 'migrations',
                'column'    => 'version',
            ],
        ],

        'configuration' => [
            'orm_default' => [
                // ...
            ],
        ],
);

How can I configure Doctrine Migrations CLI in Zend Expressive 2 (using DASPRiD/container-interop-doctrine) so I can make use of migrations_configuration section in doctrine configurations?

tobias-trozowski commented 7 years ago

the migrations configuration is not specific to the container-interop-doctrine package. if i got it right you trying to configure doctrine/migrations within your configuration. AFAIK this will not work as the migration commands searching for a config file (see: https://github.com/doctrine/migrations/blob/master/lib/Doctrine/DBAL/Migrations/Tools/Console/Helper/ConfigurationHelper.php#L87).

You need to create factories for the migration commands where the configuration got injected. e.g.

config:

use Foo\Bar\Baz\Factory\MigrationCommandFactory;
use Foo\Bar\Baz\Factory\ApplicationFactory;
use Doctrine\DBAL\Migrations\Tools\Console\Command;
use Symfony\Component\Console\Application;
array(
    'dependencies' => array(
            'factories' => array(
                Application::class             => ApplicationFactory::class,
                Command\ExecuteCommand::class  => MigrationCommandFactory::class,
                Command\GenerateCommand::class => MigrationCommandFactory::class,
                Command\LatestCommand::class   => MigrationCommandFactory::class,
                Command\MigrateCommand::class  => MigrationCommandFactory::class,
                Command\StatusCommand::class   => MigrationCommandFactory::class,
                Command\VersionCommand::class  => MigrationCommandFactory::class,
                Command\UpToDateCommand::class => MigrationCommandFactory::class,
                Command\DiffCommand::class     => MigrationCommandFactory::class,
            ),
        )
);

ApplicationFactory:

use Doctrine\DBAL\Migrations\Tools\Console\Command;
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
use Doctrine\ODM;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
use Interop\Container\ContainerInterface;
use Symfony\Component\Console;
use Zend\ServiceManager\Factory\FactoryInterface;

class ApplicationFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $cli = new Console\Application('Your Custom Migrations Console');
        $cli->setCatchExceptions(true);
        $helperSet = $cli->getHelperSet();
        $entityManager = $container->get(EntityManager::class);
        $helperSet->set(new ConnectionHelper($entityManager->getConnection()), 'db');
        $helperSet->set(new EntityManagerHelper($entityManager), 'em');

        $commands = [
            Command\DiffCommand::class,
            Command\ExecuteCommand::class,
            Command\GenerateCommand::class,
            Command\LatestCommand::class,
            Command\MigrateCommand::class,
            Command\StatusCommand::class,
            Command\UpToDateCommand::class,
            Command\VersionCommand::class,
        ];

        foreach ($commands as $commandClass) {
            if ($container->has($commandClass)) {
                $command = $container->get($commandClass);
                $cli->add($command);
            }
        }
        return $cli;
    }
}

MigrationCommandFactory

use Doctrine\DBAL\Migrations\Configuration\ArrayConfiguration;
use Doctrine\ORM\EntityManager;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;

class MigrationCommandFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $config = $container->get('config')['doctrine']['migrations_configuration']['orm_default'];
        $em = $container->get(EntityManager::class);
        $configuration = new ArrayConfiguration($em->getConnection());

        $configuration->setName($config['name']);
        $configuration->setMigrationsDirectory($config['directory']);
        $configuration->setMigrationsNamespace($config['namespace']);
        $configuration->setMigrationsTableName($config['table']);

        /** @var \Doctrine\DBAL\Migrations\Tools\Console\Command\AbstractCommand $instance */
        $instance = new $requestedName();
        $instance->setMigrationConfiguration($configuration);

        return $instance;
    }
}
diogodomanski commented 7 years ago

Hi @tobias-trozowski,

Your answer was very helpful and showed me how easy it was to solve my problem, the only thing I had to do was to call the ArrayConfiguration's "set" methods. Then, the final cli-config.php is:

<?php
/** 
 * config/cli-config.php
 * For more details @see \DoctrineORMModule\Module
 *
 * Run next commands for Migrations work
 * $ composer require doctrine/doctrine-orm-module
 * $ composer require doctrine/migrations
 */

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

$container = require 'container.php';

/* @var $em \Doctrine\ORM\EntityManager */
$em = $container->get(EntityManager::class);
$configuration = new \Doctrine\DBAL\Migrations\Configuration\ArrayConfiguration($em->getConnection());
$config = $container->get('config')['doctrine']['migrations_configuration']['orm_default'];

$configuration->setName($config['name']);
$configuration->setMigrationsDirectory($config['directory']);
$configuration->setMigrationsNamespace($config['namespace']);
$configuration->setMigrationsTableName($config['table']);
$configuration->setMigrationsColumnName($config['column']);

return new \Symfony\Component\Console\Helper\HelperSet([
    'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em),
    'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
    'configuration' => new \Doctrine\DBAL\Migrations\Tools\Console\Helper\ConfigurationHelper($em->getConnection(), $configuration)
]);

The next step will be to replace the lines that create and configure the ArrayConfiguration object by a factory call (that will validate the ['doctrine']['migrations_configuration'] attributes).

Thank you so much