Search code examples
phpsymfony-consolephinx

Customized Phinx Symfony command with multiple app bootstrap


I'm using Phinx to execute migrations across 100s of applications on multiple servers. Every application should execute same migrations.

In order to do this there is a instance of app on central server which is aware of all configs and other information needed to do bootstrap process (which is being done based on applicationId).

That central instance (let's call it adminapp) executes command and receives applicationIds through STDIN and then does a loop which bootstraps application and runs migration command.

<?php
namespace Command\Db;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use App\Command\AppCommand;

class MigrateBulkCommand extends AppCommand
{

    protected function configure()
    {
        $this
            ->setName('command:blah')
            ->setDescription('Executes SQL migrations accross multiple applications. Expects ApplicationIDs to be passed as new line delimited string on STDIN.')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $stdin = $this->getStdin();
        if ($stdin === false) {
             throw new \RuntimeException("Bulk migration command requires applicationIds to be passed to STDIN.");
        }
        $applicationIds = explode("\n", $stdin);

        foreach($applicationIds as $applicationId) {
            try {
                $this->bootstrap($applicationId);
            } catch (\Exception $e) {
                $output->writeln(sprintf("<error>Bootstrap process failed for applicationId `%s`</error>", $applicationId));
            }
            $command = new \Phinx\Console\Command\Migrate();
            $migrationInput = new \Symfony\Component\Console\Input\ArrayInput([

            ]);
            $returnCode = $command->run($migrationInput, $output);
            $output->writeln(sprinf("<info>Migrations for applicationId `%s` executed successfully.</info>", $applicationId));
        }
    }

}

Now Phinx expects it's configuration to be present in form of a config file. What I'm trying to do is reuse DB connection resource (PDO) and pass it to Phinx command Phinx\Console\Command\Migrate on the fly, together with db name.

I've seen in Phinx documentation that this is an option with PHP config file but I can't find a way to do this on the fly (during Phinx\Console\Command\Migrate class initialization).

Phinx doc suggests:

require 'app/init.php';

global $app;
$pdo = $app->getDatabase()->getPdo();

return array('environments' =>
         array(
           'default_database' => 'development',
           'development' => array(
             'name' => 'devdb',
             'connection' => $pdo
           )
         )
       );

Is there a way, without horrible hacking to pass PDO connection resource and db name to \Phinx\Console\Command\Migrate


Solution

  • I ended up extending Phinx Config class \Phinx\Config\Config and creating method fromArray.

    $command = new \Phinx\Console\Command\Migrate();
    $command->setConfig(\MyNamespace\Config::fromArray(
        [
            'paths' => [
                'migrations' => APPLICATION_PATH . "/../db/migrations",
                'seeds' => APPLICATION_PATH . "/../db/seeds"
            ],
            'environments' => [
                'default_database' => 'production',
                'production' => [
                    'name' => $db->get('dbname'),
                    'adapter' => 'mysql',
                    'host' => $db->get('host'),
                    'port' => $db->get('port'),
                    'user' => $db->get('username'),
                    'pass' => $db->get('password'),
                ]
            ]
        ]
    ));