Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to run two migration execute commands together within a single console command

For development we have a single Symfony console command that executes other console commands in order to rebuild db, run fixtures etc.

As part of the process I need to run a few cherry-picked doctrine migration commands, but for some reason I'm unable to run multiple execute commands within the same process.

To confirm, I can run these tasks without issue manually, and can run one of either command within the console execute and then the other manually without issue.

          $this->getApplication()->run(new ArrayInput(array(
            'command' => 'doctrine:migrations:execute',
            'version' => '20140310162336',
              '--no-interaction' => true
                )), $output);

          $this->getApplication()->run(new ArrayInput(array(
            'command' => 'doctrine:migrations:execute',
            'version' => '20140310170437',
              '--no-interaction' => true
                )), $output);

The error returned is:

[Doctrine\DBAL\Migrations\MigrationException]
Migration version 20140310162334 already registered with class Doctrine\DBAL\Migrations\Version

The version being the first version file that exists, can confirm that one is not in the migration_versions table, nor is it wanted in this scenario. Suggesting it is just loaded into the migrations object.

Can anyone offer input if I'm doing something wrong of if this is perhaps a bug somewhere.

Running Symfony 2.2.* and migrations bundle using dev-master.

like image 550
MadManMonty Avatar asked Mar 19 '14 13:03

MadManMonty


2 Answers

I had the same problem on symfony 2.6 and the solution described by Alexei Tenitski didn't work althought it seemed a valid one. This is the solution that worked for me.

/**
 * Loop thorugh the config and path config for migrations 
 * and execute migrations for each connection
 */
foreach (array_keys($this->migrationsConfig) as $configEm) {
    if (
        (empty($ems) || in_array($configEm, $ems))
        && !in_array($configEm, $ignoreEms)
    ) {
        try {
            // new instance of the command you want to run 
            // to force reload MigrationsConfig
            $command = new MigrateSingleCommand($this->migrationsConfig);
            $command->setApplication($this->getApplication());
            $arguments = [
                'command' => $commandString,
                '--em' => $configEm,
            ];
            $input = new ArrayInput($arguments);

            $command->run($input, $output);

        } catch (\Exception $e) {
            $output->writeln(sprintf("<error>Error: %s</error>", $e->getMessage()));
        }
    }
}

if you use $this->getApplication()->run() it will take the command from $this->application->commands where the commands are initialized only once and (when the command calling is initialized) so the MigrationsConfig will stay the same on all iterations.

like image 100
HKristjan Avatar answered Nov 15 '22 07:11

HKristjan


The problem is that application uses same instance of command for each call and Doctrine migrate commands are not designed to work in such environment. One way to work around it is to clone command and work with its instance directly:

$commandName = 'doctrine:migrations:execute';

$prototypeCommand = $this->getApplication()->get($commandName);

// This is required to avoid merging of application definition for each cloned command
$prototypeCommand->mergeApplicationDefinition();

// Create a clone for a particular run
$command1 = clone $prototypeCommand;

// Run the command with specific params
$command1->run($input1, $output)

// Create another clone
$command2 = clone $prototypeCommand;

// Run the command with another set of params
$command2->run($input2, $output)
like image 20
Alexei Tenitski Avatar answered Nov 15 '22 07:11

Alexei Tenitski