diff --git a/src/Phinx/Config/Config.php b/src/Phinx/Config/Config.php index 01ac25ba4..543663060 100644 --- a/src/Phinx/Config/Config.php +++ b/src/Phinx/Config/Config.php @@ -175,6 +175,36 @@ public function getEnvironment($name) return null; } + /** + * {@inheritdoc} + */ + public function getStorageConfigs(array $envOptions) + { + + $configs = []; + + if (isset($envOptions['default_database'])) { + unset($envOptions['default_database']); + } + + if (isset($envOptions['default_migration_table'])) { + unset($envOptions['default_migration_table']); + } + + if (count($envOptions) > 0) { + foreach ($envOptions as $dbRef => $adapterOptions) { + if (!is_array($adapterOptions)) { + $configs [$dbRef]= $envOptions; + break; + } else { + $configs [$dbRef]= array_merge($adapterOptions, ['dbRef' => $dbRef]); + } + } + } + + return $configs; + } + /** * {@inheritdoc} */ @@ -243,16 +273,59 @@ public function getConfigFilePath() /** * {@inheritdoc} */ - public function getMigrationPaths() + public function getMigrationPaths($environment = null, $dbReference = null) { + $paths = []; + if (!isset($this->values['paths']['migrations'])) { - throw new \UnexpectedValueException('Migrations path missing from config file'); + throw new \UnexpectedValueException('Default migrations path missing from config file'); } if (is_string($this->values['paths']['migrations'])) { $this->values['paths']['migrations'] = [$this->values['paths']['migrations']]; } + if ($environment !== null && $dbReference !== null) { + $environment = $this->getEnvironment($environment); + if (isset($environment[$dbReference]['paths']['migrations'])) { + if (!is_array($environment[$dbReference]['paths']['migrations'])) { + return [$environment[$dbReference]['paths']['migrations']]; + } else { + foreach ($environment[$dbReference]['paths']['migrations'] as $namespace => $migrationPath) { + $paths[$namespace]= $migrationPath; + } + if (count($paths) > 0) { + $this->values['paths']['migrations']= $paths; + } + } + } + } elseif (is_null($environment) && is_null($dbReference)) { + if (isset($this->values['environments']) && is_array($this->values['environments'])) { + $environments = array_keys($this->values['environments']); + + foreach ($environments as $env) { + if (is_array($this->values['environments'][$env])) { + foreach ($this->values['environments'][$env] as $dbReference => $properties) { + if (!is_array($properties)) { + continue; + } + + if (!is_array($this->values['environments'][$env][$dbReference]['paths']['migrations'])) { + $paths []= $this->values['environments'][$env][$dbReference]['paths']['migrations']; + } else { + foreach ($this->values['environments'][$env][$dbReference]['paths']['migrations'] as $namespace => $migrationPath) { + $paths[$namespace]= $migrationPath; + } + } + } + } + } + if (count($paths) > 0) { + $this->values['paths']['migrations']= $paths; + } + } + } + return $this->values['paths']['migrations']; } @@ -272,8 +345,11 @@ public function getMigrationBaseClassName($dropNamespace = true) /** * {@inheritdoc} */ - public function getSeedPaths() + public function getSeedPaths($environment = null, $dbReference = null) { + + $paths = []; + if (!isset($this->values['paths']['seeds'])) { throw new \UnexpectedValueException('Seeds path missing from config file'); } @@ -282,6 +358,46 @@ public function getSeedPaths() $this->values['paths']['seeds'] = [$this->values['paths']['seeds']]; } + if ($environment !== null && $dbReference !== null) { + $environment = $this->getEnvironment($environment); + if (isset($environment[$dbReference]['paths']['seeds'])) { + if (!is_array($environment[$dbReference]['paths']['seeds'])) { + return [$environment[$dbReference]['paths']['seeds']]; + } else { + foreach ($environment[$dbReference]['paths']['seeds'] as $namespace => $seedPath) { + $paths[$namespace]= $seedPath; + } + if (count($paths) > 0) { + $this->values['paths']['seeds']= $paths; + } + } + } + } elseif (is_null($environment) && is_null($dbReference)) { + if (isset($this->values['environments']) && is_array($this->values['environments'])) { + $environments = array_keys($this->values['environments']); + foreach ($environments as $env) { + if (is_array($this->values['environments'][$env])) { + foreach ($this->values['environments'][$env] as $dbReference => $properties) { + if (!is_array($properties)) { + continue; + } + + if (!is_array($this->values['environments'][$env][$dbReference]['paths']['seeds'])) { + $paths []= $this->values['environments'][$env][$dbReference]['paths']['seeds']; + } else { + foreach ($this->values['environments'][$env][$dbReference]['paths']['seeds'] as $namespace => $migrationPath) { + $paths[$namespace]= $migrationPath; + } + } + } + } + } + } + if (count($paths) > 0) { + $this->values['paths']['seeds']= $paths; + } + } + return $this->values['paths']['seeds']; } diff --git a/src/Phinx/Config/ConfigInterface.php b/src/Phinx/Config/ConfigInterface.php index 1bdae2ed3..6ef5ab57a 100644 --- a/src/Phinx/Config/ConfigInterface.php +++ b/src/Phinx/Config/ConfigInterface.php @@ -56,6 +56,14 @@ public function getEnvironments(); */ public function getEnvironment($name); + /** + * Takes combined envOptions and flattens + * + * @param array $envOptions + * @return array + */ + public function getStorageConfigs(array $envOptions); + /** * Does the specified environment exist in the configuration file? * @@ -91,16 +99,18 @@ public function getConfigFilePath(); /** * Gets the paths to search for migration files. * + * @param string $environment + * @param string $dbReference * @return string[] */ - public function getMigrationPaths(); + public function getMigrationPaths($environment = null, $dbReference = null); /** * Gets the paths to search for seed files. * * @return string[] */ - public function getSeedPaths(); + public function getSeedPaths($environment = null, $dbReference = null); /** * Get the template file name. diff --git a/src/Phinx/Console/Command/AbstractCommand.php b/src/Phinx/Console/Command/AbstractCommand.php index 49f89585b..57f32457b 100644 --- a/src/Phinx/Console/Command/AbstractCommand.php +++ b/src/Phinx/Console/Command/AbstractCommand.php @@ -343,6 +343,44 @@ protected function verifySeedDirectory($path) } } + /** + * Output the database information + * + * @param array $info + * @param OutputInterface $output + * @return null|int + */ + public function outputEnvironmentInfo(array $info, OutputInterface $output) + { + + if (isset($info['adapter'])) { + $output->writeln('using adapter ' . $info['adapter']); + } + + if (isset($info['wrapper'])) { + $output->writeln('using wrapper ' . $info['wrapper']); + } + + if (isset($info['id'])) { + $output->writeln('using name ' . $info['id']); + } + + if (isset($info['name'])) { + $output->writeln('using database ' . $info['name']); + } else { + $output->writeln('Could not determine database name! Please specify a database name in your config file.'); + + return 1; + } + + if (isset($info['table_prefix'])) { + $output->writeln('using table prefix ' . $info['table_prefix']); + } + if (isset($info['table_suffix'])) { + $output->writeln('using table suffix ' . $info['table_suffix']); + } + } + /** * Returns the migration template filename. * diff --git a/src/Phinx/Console/Command/Migrate.php b/src/Phinx/Console/Command/Migrate.php index 25640661c..a2a907131 100644 --- a/src/Phinx/Console/Command/Migrate.php +++ b/src/Phinx/Console/Command/Migrate.php @@ -70,6 +70,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { + $this->bootstrap($input, $output); $version = $input->getOption('target'); @@ -84,38 +85,27 @@ protected function execute(InputInterface $input, OutputInterface $output) } $envOptions = $this->getConfig()->getEnvironment($environment); - if (isset($envOptions['adapter'])) { - $output->writeln('using adapter ' . $envOptions['adapter']); - } + $databases = $this->getConfig()->getStorageConfigs($envOptions); - if (isset($envOptions['wrapper'])) { - $output->writeln('using wrapper ' . $envOptions['wrapper']); - } + // run the migrations + $start = microtime(true); + foreach ($databases as $adapterOptions) { + $this->getManager()->setMigrations(null); - if (isset($envOptions['name'])) { - $output->writeln('using database ' . $envOptions['name']); - } else { - $output->writeln('Could not determine database name! Please specify a database name in your config file.'); + if (isset($adapterOptions['dbRef'])) { + $this->getManager()->setDbRef($adapterOptions['dbRef']); + } - return 1; - } + $this->outputEnvironmentInfo($adapterOptions, $output); - if (isset($envOptions['table_prefix'])) { - $output->writeln('using table prefix ' . $envOptions['table_prefix']); - } - if (isset($envOptions['table_suffix'])) { - $output->writeln('using table suffix ' . $envOptions['table_suffix']); + if ($date !== null) { + $this->getManager()->migrateToDateTime($environment, new \DateTime($date)); + } else { + $this->getManager()->migrate($environment, $version); + } } - // run the migrations - $start = microtime(true); - if ($date !== null) { - $this->getManager()->migrateToDateTime($environment, new \DateTime($date)); - } else { - $this->getManager()->migrate($environment, $version); - } $end = microtime(true); - $output->writeln(''); $output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . ''); diff --git a/src/Phinx/Console/Command/Rollback.php b/src/Phinx/Console/Command/Rollback.php index 48550144f..845a3b238 100644 --- a/src/Phinx/Console/Command/Rollback.php +++ b/src/Phinx/Console/Command/Rollback.php @@ -96,32 +96,32 @@ protected function execute(InputInterface $input, OutputInterface $output) } $envOptions = $config->getEnvironment($environment); - if (isset($envOptions['adapter'])) { - $output->writeln('using adapter ' . $envOptions['adapter']); - } - - if (isset($envOptions['wrapper'])) { - $output->writeln('using wrapper ' . $envOptions['wrapper']); - } - - if (isset($envOptions['name'])) { - $output->writeln('using database ' . $envOptions['name']); - } - - $versionOrder = $this->getConfig()->getVersionOrder(); - $output->writeln('ordering by ' . $versionOrder . " time"); - - // rollback the specified environment - if ($date === null) { - $targetMustMatchVersion = true; - $target = $version; - } else { - $targetMustMatchVersion = false; - $target = $this->getTargetFromDate($date); + $databases = $config->getStorageConfigs($envOptions); + + $start = microtime(true); + + foreach ($databases as $adapterOptions) { + // rollback the specified environment + if ($date === null) { + $targetMustMatchVersion = true; + $target = $version; + } else { + $targetMustMatchVersion = false; + $target = $this->getTargetFromDate($date); + } + + if (isset($adapterOptions['dbRef'])) { + $this->getManager()->setDbRef($adapterOptions['dbRef']); + } + + $this->outputEnvironmentInfo($adapterOptions, $output); + + $versionOrder = $this->getConfig()->getVersionOrder(); + $output->writeln('ordering by ' . $versionOrder . " time"); + + $this->getManager()->rollback($environment, $target, $force, $targetMustMatchVersion); } - $start = microtime(true); - $this->getManager()->rollback($environment, $target, $force, $targetMustMatchVersion); $end = microtime(true); $output->writeln(''); diff --git a/src/Phinx/Console/Command/SeedRun.php b/src/Phinx/Console/Command/SeedRun.php index 642689671..e62b265d8 100644 --- a/src/Phinx/Console/Command/SeedRun.php +++ b/src/Phinx/Console/Command/SeedRun.php @@ -44,19 +44,21 @@ protected function configure() $this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment'); $this->setName('seed:run') - ->setDescription('Run database seeders') - ->addOption('--seed', '-s', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'What is the name of the seeder?') - ->setHelp( - <<setDescription('Run database seeders') + ->addOption('--seed', '-s', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'What is the name of the seeder?') + ->addOption('--database', '-d', InputOption::VALUE_REQUIRED, 'What is the db reference required?') + ->setHelp( + <<seed:run command runs all available or individual seeders phinx seed:run -e development phinx seed:run -e development -s UserSeeder phinx seed:run -e development -s UserSeeder -s PermissionSeeder -s LogSeeder +phinx seed:run -e development -s UserSeeder -d databaseReference phinx seed:run -e development -v EOT - ); + ); } /** @@ -72,6 +74,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $seedSet = $input->getOption('seed'); $environment = $input->getOption('environment'); + $dbRef = $input->getOption('database'); if ($environment === null) { $environment = $this->getConfig()->getDefaultEnvironment(); @@ -81,38 +84,40 @@ protected function execute(InputInterface $input, OutputInterface $output) } $envOptions = $this->getConfig()->getEnvironment($environment); - if (isset($envOptions['adapter'])) { - $output->writeln('using adapter ' . $envOptions['adapter']); - } - - if (isset($envOptions['wrapper'])) { - $output->writeln('using wrapper ' . $envOptions['wrapper']); - } - - if (isset($envOptions['name'])) { - $output->writeln('using database ' . $envOptions['name']); - } else { - $output->writeln('Could not determine database name! Please specify a database name in your config file.'); - - return; - } - - if (isset($envOptions['table_prefix'])) { - $output->writeln('using table prefix ' . $envOptions['table_prefix']); - } - if (isset($envOptions['table_suffix'])) { - $output->writeln('using table suffix ' . $envOptions['table_suffix']); - } - + $databases = $this->getConfig()->getStorageConfigs($envOptions); $start = microtime(true); - if (empty($seedSet)) { - // run all the seed(ers) - $this->getManager()->seed($environment); + if (!is_null($dbRef)) { + $this->getManager()->setDbRef($dbRef); + $this->outputEnvironmentInfo($databases[$dbRef], $output); + if (empty($seedSet)) { + // run all the seed(ers) + $this->getManager()->seed($environment); + } else { + // run seed(ers) specified in a comma-separated list of classes + foreach ($seedSet as $seed) { + $this->getManager()->seed($environment, trim($seed)); + } + } } else { - // run seed(ers) specified in a comma-separated list of classes - foreach ($seedSet as $seed) { - $this->getManager()->seed($environment, trim($seed)); + foreach ($databases as $adapterOptions) { + $this->getManager()->setSeeds(null); + + if (isset($adapterOptions['dbRef'])) { + $this->getManager()->setDbRef($adapterOptions['dbRef']); + } + + $this->outputEnvironmentInfo($adapterOptions, $output); + + if (empty($seedSet)) { + // run all the seed(ers) + $this->getManager()->seed($environment); + } else { + // run seed(ers) specified in a comma-separated list of classes + foreach ($seedSet as $seed) { + $this->getManager()->seed($environment, trim($seed)); + } + } } } diff --git a/src/Phinx/Console/Command/Status.php b/src/Phinx/Console/Command/Status.php index 79df23829..4c95ec794 100644 --- a/src/Phinx/Console/Command/Status.php +++ b/src/Phinx/Console/Command/Status.php @@ -84,7 +84,19 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln('ordering by ' . $this->getConfig()->getVersionOrder() . " time"); - // print the status - return $this->getManager()->printStatus($environment, $format); + $envOptions = $this->getConfig()->getEnvironment($environment); + $databases = $this->getConfig()->getStorageConfigs($envOptions); + + // run the migrations + $start = microtime(true); + + foreach ($databases as $adapterOptions) { + $this->getManager()->setMigrations(null); + if (isset($adapterOptions['dbRef'])) { + $this->getManager()->setDbRef($adapterOptions['dbRef']); + } + + $this->getManager()->printStatus($environment, $format); + } } } diff --git a/src/Phinx/Migration/Manager.php b/src/Phinx/Migration/Manager.php index 3a2414611..52d8e898d 100644 --- a/src/Phinx/Migration/Manager.php +++ b/src/Phinx/Migration/Manager.php @@ -59,6 +59,21 @@ class Manager */ protected $environments; + /** + * @var string + */ + protected $dbRef; + + /** + * @var string + */ + protected $environmentName; + + /** + * @var string + */ + protected $adapter; + /** * @var array */ @@ -102,6 +117,7 @@ public function __construct(ConfigInterface $config, InputInterface $input, Outp */ public function printStatus($environment, $format = null) { + $this->setEnvironmentName($environment); $output = $this->getOutput(); $migrations = []; $hasDownMigration = false; @@ -302,6 +318,7 @@ public function migrateToDateTime($environment, \DateTime $dateTime) */ public function migrate($environment, $version = null) { + $this->setEnvironmentName($environment); $migrations = $this->getMigrations(); $env = $this->getEnvironment($environment); $versions = $env->getVersions(); @@ -402,6 +419,7 @@ public function executeSeed($name, SeedInterface $seed) // Execute the seeder and log the time elapsed. $start = microtime(true); $this->getEnvironment($name)->executeSeed($seed); + $end = microtime(true); $this->getOutput()->writeln( @@ -531,6 +549,7 @@ public function rollback($environment, $target = null, $force = false, $targetMu */ public function seed($environment, $seed = null) { + $this->setEnvironmentName($environment); $seeds = $this->getSeeds(); if ($seed === null) { @@ -538,18 +557,42 @@ public function seed($environment, $seed = null) foreach ($seeds as $seeder) { if (array_key_exists($seeder->getName(), $seeds)) { $this->executeSeed($environment, $seeder); + unset($this->seeds[$seeder->getName()]); } } } else { // run only one seeder if (array_key_exists($seed, $seeds)) { $this->executeSeed($environment, $seeds[$seed]); + unset($this->seeds[$seed]); } else { - throw new \InvalidArgumentException(sprintf('The seed class "%s" does not exist', $seed)); + $this->getOutput()->writeln(sprintf('The seed class "%s" does not exist', $seed)); } } } + /** + * Set the dbRef property + * + * @param string $ref + * @return \Phinx\Migration\Manager + */ + public function setDbRef($ref) + { + $this->dbRef = $ref; + return $this; + } + + /** + * Get the adapter property + * + * @return string + */ + public function getDbRef() + { + return $this->dbRef; + } + /** * Sets the environments. * @@ -572,6 +615,34 @@ public function setEnvironments($environments = []) */ public function getEnvironment($name) { + if ($this->getDbRef() !== null) { + return $this->getMultiEnvironment($name); + } + + return $this->getSingleEnvironment($name); + } + + public function setEnvironmentName($name) + { + $this->environmentName = $name; + return $this; + } + + public function getEnvironmentName() + { + return $this->environmentName; + } + + /** + * Gets the manager class for the given environment when given as a single instance. + * + * @param string $name Environment Name + * @throws \InvalidArgumentException + * @return \Phinx\Migration\Manager\Environment + */ + public function getSingleEnvironment($name) + { + if (isset($this->environments[$name])) { return $this->environments[$name]; } @@ -586,10 +657,46 @@ public function getEnvironment($name) // create an environment instance and cache it $envOptions = $this->getConfig()->getEnvironment($name); - $envOptions['version_order'] = $this->getConfig()->getVersionOrder(); + $envOptions['version_order'] = $this->getConfig()->getVersionOrder(); $environment = new Environment($name, $envOptions); $this->environments[$name] = $environment; + + $environment->setInput($this->getInput()); + $environment->setOutput($this->getOutput()); + + return $environment; + } + + /** + * Gets the manager class for the given environment when used as part of a mulitple deployment. + * + * @param string $name Environment Name + * @throws \InvalidArgumentException + * @return \Phinx\Migration\Manager\Environment + */ + public function getMultiEnvironment($name) + { + if (isset($this->environments[$name][$this->getDbRef()])) { + return $this->environments[$name][$this->getDbRef()]; + } + + // check the environment exists + if (!$this->getConfig()->hasEnvironment($name)) { + throw new \InvalidArgumentException(sprintf( + 'The environment "%s" does not exist', + $name + )); + } + + // create an environment instance and cache it + $envOptions = $this->getConfig()->getEnvironment($name); + $envOptions = $envOptions[$this->getDbRef()]; + + $envOptions['version_order'] = $this->getConfig()->getVersionOrder(); + $environment = new Environment($name, $envOptions); + $this->environments[$name][$this->getDbRef()] = $environment; + $environment->setInput($this->getInput()); $environment->setOutput($this->getOutput()); @@ -648,7 +755,7 @@ public function getOutput() * @param array $migrations Migrations * @return \Phinx\Migration\Manager */ - public function setMigrations(array $migrations) + public function setMigrations(array $migrations = null) { $this->migrations = $migrations; @@ -666,7 +773,6 @@ public function getMigrations() { if ($this->migrations === null) { $phpFiles = $this->getMigrationFiles(); - // filter the files to only get the ones that match our naming scheme $fileNames = []; /** @var \Phinx\Migration\AbstractMigration[] $versions */ @@ -737,7 +843,7 @@ public function getMigrations() protected function getMigrationFiles() { $config = $this->getConfig(); - $paths = $config->getMigrationPaths(); + $paths = $config->getMigrationPaths($this->getEnvironmentName(), $this->getDbRef()); $files = []; foreach ($paths as $path) { @@ -761,7 +867,7 @@ protected function getMigrationFiles() * @param array $seeds Seeders * @return \Phinx\Migration\Manager */ - public function setSeeds(array $seeds) + public function setSeeds(array $seeds = null) { $this->seeds = $seeds; @@ -834,7 +940,8 @@ public function getSeeds() protected function getSeedFiles() { $config = $this->getConfig(); - $paths = $config->getSeedPaths(); + $paths = $config->getSeedPaths($this->getEnvironmentName(), $this->getDbRef()); + $files = []; foreach ($paths as $path) { diff --git a/tests/Phinx/Config/AbstractConfigTest.php b/tests/Phinx/Config/AbstractConfigTest.php index 4ad6c7b6b..c8243f2dc 100644 --- a/tests/Phinx/Config/AbstractConfigTest.php +++ b/tests/Phinx/Config/AbstractConfigTest.php @@ -17,11 +17,31 @@ abstract class AbstractConfigTest extends TestCase */ protected $migrationPath = null; + /** + * @var string + */ + protected $migrationPathWithMultiDb = null; + + /** + * @var string + */ + protected $migrationPathWithMultiDbAsString = null; + /** * @var string */ protected $seedPath = null; + /** + * @var string + */ + protected $seedPathWithMultiDb = null; + + /** + * @var string + */ + protected $seedPathWithMultiDbAsString = null; + /** * Returns a sample configuration array for use with the unit tests. * @@ -59,6 +79,49 @@ public function getConfigArray() ]; } + public function getConfigArrayWithMultiDb() + { + return [ + 'default' => [ + 'paths' => [ + 'migrations' => '%%PHINX_CONFIG_PATH%%/testmigrations2', + 'seeds' => '%%PHINX_CONFIG_PATH%%/db/seeds', + ] + ], + 'paths' => [ + 'migrations' => $this->getMigrationPaths(), + 'seeds' => $this->getSeedPaths() + ], + 'templates' => [ + 'file' => '%%PHINX_CONFIG_PATH%%/tpl/testtemplate.txt', + 'class' => '%%PHINX_CONFIG_PATH%%/tpl/testtemplate.php' + ], + 'environments' => [ + 'default_migration_table' => 'phinxlog', + 'default_database' => 'testing', + 'testing' => [ + 'db1' => [ + 'adapter' => 'sqllite', + 'wrapper' => 'testwrapper', + 'paths' => [ + 'migrations' => $this->getMigrationPathsWithMultiDb(), + 'seeds' => $this->getSeedPathsWithMultiDb() + ], + ] + ], + 'production' => [ + 'db1' => [ + 'adapter' => 'mysql', + 'paths' => [ + 'migrations' => $this->getMigrationPathsWithMultiDbAsString(), + 'seeds' => $this->getSeedPathsWithMultiDbAsString() + ], + ] + ] + ] + ]; + } + /** * Generate dummy migration paths * @@ -73,6 +136,24 @@ protected function getMigrationPaths() return [$this->migrationPath]; } + protected function getMigrationPathsWithMultiDb() + { + if (null === $this->migrationPathWithMultiDb) { + $this->migrationPathWithMultiDb = uniqid('phinx', true); + } + + return [$this->migrationPathWithMultiDb]; + } + + protected function getMigrationPathsWithMultiDbAsString() + { + if (null === $this->migrationPathWithMultiDbAsString) { + $this->migrationPathWithMultiDbAsString = uniqid('phinx', true); + } + + return $this->migrationPathWithMultiDbAsString; + } + /** * Generate dummy seed paths * @@ -86,4 +167,32 @@ protected function getSeedPaths() return [$this->seedPath]; } + + /** + * Generate dummy seed paths + * + * @return string[] + */ + protected function getSeedPathsWithMultiDb() + { + if (null === $this->seedPathWithMultiDb) { + $this->seedPathWithMultiDb = uniqid('phinx', true); + } + + return [$this->seedPathWithMultiDb]; + } + + /** + * Generate dummy seed paths + * + * @return string[] + */ + protected function getSeedPathsWithMultiDbAsString() + { + if (null === $this->seedPathWithMultiDbAsString) { + $this->seedPathWithMultiDbAsString = uniqid('phinx', true); + } + + return $this->seedPathWithMultiDbAsString; + } } diff --git a/tests/Phinx/Config/ConfigMigrationPathsTest.php b/tests/Phinx/Config/ConfigMigrationPathsTest.php index 14862d3eb..ed4dd5b97 100644 --- a/tests/Phinx/Config/ConfigMigrationPathsTest.php +++ b/tests/Phinx/Config/ConfigMigrationPathsTest.php @@ -30,6 +30,16 @@ public function testGetMigrationPaths() $this->assertEquals($this->getMigrationPaths(), $config->getMigrationPaths()); } + /** + * Normal behavior + */ + public function testGetMigrationPathsWithMultiDb() + { + $config = new Config($this->getConfigArrayWithMultiDb()); + $this->assertEquals($this->getMigrationPathsWithMultiDb(), $config->getMigrationPaths('testing', 'db1')); + $this->assertEquals([$this->getMigrationPathsWithMultiDbAsString()], $config->getMigrationPaths('production', 'db1')); + } + public function testGetMigrationPathConvertsStringToArray() { $values = [ diff --git a/tests/Phinx/Config/ConfigSeedPathsTest.php b/tests/Phinx/Config/ConfigSeedPathsTest.php index 8aaa08231..dfe3e5bc6 100644 --- a/tests/Phinx/Config/ConfigSeedPathsTest.php +++ b/tests/Phinx/Config/ConfigSeedPathsTest.php @@ -30,15 +30,20 @@ public function testGetSeedPaths() $this->assertEquals($this->getSeedPaths(), $config->getSeedPaths()); } - public function testGetSeedPathConvertsStringToArray() + /** + * Normal behavior + */ + public function testGetSeedPathsWithMultiDb() { - $values = [ - 'paths' => [ - 'seeds' => '/test' - ] - ]; + $config = new Config($this->getConfigArrayWithMultiDb()); + $this->assertEquals($this->getSeedPathsWithMultiDb(), $config->getSeedPaths('testing', 'db1')); + $this->assertEquals([$this->getSeedPathsWithMultiDbAsString()], $config->getSeedPaths('production', 'db1')); + } - $config = new Config($values); + public function testGetSeedPathConvertsStringToArray() + { + + $config = new Config($this->getConfigArray()); $paths = $config->getSeedPaths(); $this->assertInternalType('array', $paths); diff --git a/tests/Phinx/Config/ConfigTest.php b/tests/Phinx/Config/ConfigTest.php index d00d3714f..599ffbbfe 100644 --- a/tests/Phinx/Config/ConfigTest.php +++ b/tests/Phinx/Config/ConfigTest.php @@ -283,4 +283,13 @@ public function isVersionOrderCreationTimeDataProvider() ], ]; } + + public function testGetStorageSpecificConfig() + { + $config = new Config($this->getConfigArrayWithMultiDb()); + $envOptions = $config->getEnvironment('testing'); + $envOptions['default_database']= __FILE__; + $multiEnvOptions = $config->getStorageConfigs($envOptions); + $this->assertArrayHasKey('db1', $multiEnvOptions); + } } diff --git a/tests/Phinx/Console/Command/CreateTest.php b/tests/Phinx/Console/Command/CreateTest.php index b4ebd5671..50d256b14 100644 --- a/tests/Phinx/Console/Command/CreateTest.php +++ b/tests/Phinx/Console/Command/CreateTest.php @@ -26,6 +26,8 @@ class CreateTest extends TestCase */ protected $config = []; + protected $configMultiDb = []; + /** * @var InputInterface $input */ @@ -65,6 +67,39 @@ protected function setUp() } } + @mkdir(sys_get_temp_dir() . DIRECTORY_SEPARATOR . '/db1/migrations', 0777, true); + $this->configMultiDb = new Config( + [ + 'paths' => [ + 'migrations' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'migrations', + ], + 'environments' => [ + 'default_migration_table' => 'phinxlog', + 'default_database' => 'development', + 'development' => [ + 'db1' => [ + 'paths' => [ + 'migrations' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'db1' . DIRECTORY_SEPARATOR . 'migrations', + 'seeds' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'db1' . DIRECTORY_SEPARATOR . 'migrations', + ], + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + ], + ], + ] + ); + + foreach ($this->configMultiDb->getMigrationPaths() as $path) { + foreach (glob($path . '/*.*') as $migration) { + unlink($migration); + } + } + $this->input = new ArrayInput([]); $this->output = new StreamOutput(fopen('php://memory', 'a', false)); } @@ -95,6 +130,32 @@ public function testExecuteWithDuplicateMigrationNames() $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateMigration']); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The migration class name "MyDuplicateMigration" already exists + */ + public function testExecuteWithDuplicateMigrationNamesWithMultDbConfig() + { + $application = new PhinxApplication('testing'); + $application->add(new Create()); + + /** @var Create $command */ + $command = $application->find('create'); + + /** @var Manager $managerStub mock the manager class */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->configMultiDb, $this->input, $this->output]) + ->getMock(); + + $command->setConfig($this->configMultiDb); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateMigration']); + sleep(1.01); // need at least a second due to file naming scheme + $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateMigration']); + } + /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage The migration class name "Foo\Bar\MyDuplicateMigration" already exists @@ -127,6 +188,52 @@ public function testExecuteWithDuplicateMigrationNamesWithNamespace() $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateMigration']); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The migration class name "Foo\Bar\MyDuplicateMigration" already exists + */ + public function testExecuteWithDuplicateMigrationNamesWithNamespaceWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Create()); + + /** @var Create $command */ + $command = $application->find('create'); + + /** @var Manager $managerStub mock the manager class */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->configMultiDb, $this->input, $this->output]) + ->getMock(); + + $config = clone $this->configMultiDb; + $config['environments']= [ + 'development' => [ + 'db1' => [ + 'paths' => [ + 'migrations' => [ + 'Foo\\Bar' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'db1' . DIRECTORY_SEPARATOR . 'migrations', + ], + 'seeds' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'db1' . DIRECTORY_SEPARATOR . 'migrations', + ], + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + ] + ]; + + $command->setConfig($config); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateMigration']); + sleep(1.01); // need at least a second due to file naming scheme + $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateMigration']); + } + /** * @expectedException \Exception * @expectedExceptionMessage Cannot use --template and --class at the same time diff --git a/tests/Phinx/Console/Command/MigrateTest.php b/tests/Phinx/Console/Command/MigrateTest.php index fe179ec74..8ff746bd5 100644 --- a/tests/Phinx/Console/Command/MigrateTest.php +++ b/tests/Phinx/Console/Command/MigrateTest.php @@ -34,6 +34,15 @@ class MigrateTest extends TestCase protected function setUp() { + + $this->getConfig(); + $this->input = new ArrayInput([]); + $this->output = new StreamOutput(fopen('php://memory', 'a', false)); + } + + public function getConfig() + { + $this->config = new Config([ 'paths' => [ 'migrations' => __FILE__, @@ -48,12 +57,51 @@ protected function setUp() 'user' => '', 'pass' => '', 'port' => 3006, - ] + ], ] ]); - $this->input = new ArrayInput([]); - $this->output = new StreamOutput(fopen('php://memory', 'a', false)); + } + + public function getMultiDbConfig() + { + + $config = new Config([ + 'paths' => [ + 'migrations' => __FILE__, + ], + 'environments' => [ + 'default_migration_table' => 'phinxlog', + 'default_database' => 'development', + 'development' => [ + 'db1' => [ + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development', + 'paths' => [ + 'migrations' => __FILE__, + ], + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + 'db2' => [ + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development_2', + 'paths' => [ + 'migrations' => __FILE__, + ], + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + ], + ] + ]); + + return $config; + } public function testExecute() @@ -82,7 +130,7 @@ public function testExecute() $this->assertSame(0, $exitCode); } - public function testExecuteWithEnvironmentOption() + public function testExecuteWithMultiDb() { $application = new PhinxApplication('testing'); $application->add(new Migrate()); @@ -97,15 +145,64 @@ public function testExecuteWithEnvironmentOption() ->getMock(); $managerStub->expects($this->any()) ->method('migrate'); + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $exitCode = $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); + + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); + $this->assertSame(0, $exitCode); + } + + public function testExecuteWithEnvironmentOption() + { + $application = new PhinxApplication('testing'); + $application->add(new Migrate()); + + /** @var Migrate $command */ + $command = $application->find('migrate'); + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->config, $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->any()) + ->method('migrate'); $command->setConfig($this->config); $command->setManager($managerStub); $commandTester = new CommandTester($command); - $exitCode = $commandTester->execute(['command' => $command->getName(), '--environment' => 'fakeenv'], ['decorated' => false]); + $exitCode = $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); + + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); + $this->assertSame(0, $exitCode); + } + + public function testExecuteWithEnvironmentOptionWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Migrate()); + + /** @var Migrate $command */ + $command = $application->find('migrate'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->any()) + ->method('migrate'); + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $exitCode = $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); - $this->assertRegExp('/using environment fakeenv/', $commandTester->getDisplay()); - $this->assertSame(1, $exitCode); + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); + $this->assertSame(0, $exitCode); } public function testDatabaseNameSpecified() @@ -133,4 +230,30 @@ public function testDatabaseNameSpecified() $this->assertRegExp('/using database development/', $commandTester->getDisplay()); $this->assertSame(0, $exitCode); } + + public function testDatabaseNameSpecifiedWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Migrate()); + + /** @var Migrate $command */ + $command = $application->find('migrate'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('migrate'); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $exitCode = $commandTester->execute(['command' => $command->getName()], ['decorated' => false]); + + $this->assertRegExp('/using database development/', $commandTester->getDisplay()); + $this->assertSame(0, $exitCode); + } } diff --git a/tests/Phinx/Console/Command/RollbackTest.php b/tests/Phinx/Console/Command/RollbackTest.php index 96712f3be..935634817 100644 --- a/tests/Phinx/Console/Command/RollbackTest.php +++ b/tests/Phinx/Console/Command/RollbackTest.php @@ -61,6 +61,47 @@ protected function setUp() $this->output = new StreamOutput(fopen('php://memory', 'a', false)); } + protected function getMultiDbConfig() + { + + $config = new Config([ + 'paths' => [ + 'migrations' => __FILE__, + ], + 'environments' => [ + 'default_migration_table' => 'phinxlog', + 'default_database' => 'development', + 'development' => [ + 'db1' => [ + 'adapter' => 'mysql', + 'paths' => [ + 'migrations' => __FILE__, + ], + 'host' => 'fakehost', + 'name' => 'development', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + 'db2' => [ + 'adapter' => 'mysql', + 'paths' => [ + 'migrations' => __FILE__, + ], + 'host' => 'fakehost', + 'name' => 'development_2', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + ], + ] + ]); + + return $config; + + } + public function testExecute() { $application = new PhinxApplication('testing'); @@ -92,6 +133,37 @@ public function testExecute() $this->assertRegExp('/ordering by creation time/', $display); } + public function testExecuteWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Rollback()); + + /** @var Rollback $command */ + $command = $application->find('rollback'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('rollback') + ->with(self::DEFAULT_TEST_ENVIRONMENT, null, false, true); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()], ['decorated' => false]); + + $display = $commandTester->getDisplay(); + + $this->assertRegExp('/no environment specified/', $display); + + // note that the default order is by creation time + $this->assertRegExp('/ordering by creation time/', $display); + } + public function testExecuteWithEnvironmentOption() { $application = new PhinxApplication('testing'); @@ -107,14 +179,39 @@ public function testExecuteWithEnvironmentOption() ->getMock(); $managerStub->expects($this->once()) ->method('rollback') - ->with('fakeenv', null, false, true); + ->with('development', null, false, true); $command->setConfig($this->config); $command->setManager($managerStub); $commandTester = new CommandTester($command); - $commandTester->execute(['command' => $command->getName(), '--environment' => 'fakeenv'], ['decorated' => false]); - $this->assertRegExp('/using environment fakeenv/', $commandTester->getDisplay()); + $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); + } + + public function testExecuteWithEnvironmentOptionWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Rollback()); + + /** @var Rollback $command */ + $command = $application->find('rollback'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('rollback') + ->with('development', null, false, true); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); } public function testDatabaseNameSpecified() @@ -142,6 +239,33 @@ public function testDatabaseNameSpecified() $this->assertRegExp('/using database development/', $commandTester->getDisplay()); } + public function testDatabaseNameSpecifiedWithMultiDb() + { + + $application = new PhinxApplication('testing'); + $application->add(new Rollback()); + + /** @var Rollback $command */ + $command = $application->find('rollback'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('rollback') + ->with(self::DEFAULT_TEST_ENVIRONMENT, null, false); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()], ['decorated' => false]); + $this->assertRegExp('/using database development/', $commandTester->getDisplay()); + + } + public function testStartTimeVersionOrder() { $application = new \Phinx\Console\PhinxApplication('testing'); @@ -169,6 +293,34 @@ public function testStartTimeVersionOrder() $this->assertRegExp('/ordering by execution time/', $commandTester->getDisplay()); } + public function testStartTimeVersionOrderWithMultiDb() + { + $application = new \Phinx\Console\PhinxApplication('testing'); + $application->add(new Rollback()); + + // setup dependencies + $config = $this->getMultiDbConfig(); + $config['version_order'] = \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME; + + $command = $application->find('rollback'); + + // mock the manager class + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$config, $this->input, $this->output]) + ->getMock(); + + $managerStub->expects($this->exactly(2)) + ->method('rollback') + ->with(self::DEFAULT_TEST_ENVIRONMENT, null, false, true); + + $command->setConfig($config); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()], ['decorated' => false]); + $this->assertRegExp('/ordering by execution time/', $commandTester->getDisplay()); + } + public function testWithDate() { $application = new \Phinx\Console\PhinxApplication('testing'); @@ -204,6 +356,41 @@ public function testWithDate() $commandTester->execute(['command' => $command->getName(), '-d' => $date], ['decorated' => false]); } + public function testWithDateWithMultiDb() + { + $application = new \Phinx\Console\PhinxApplication('testing'); + + $date = '20160101'; + $target = '20160101000000'; + $rollbackStub = $this->getMockBuilder('\Phinx\Console\Command\Rollback') + ->setMethods(['getTargetFromDate']) + ->getMock(); + + $rollbackStub->expects($this->exactly(2)) + ->method('getTargetFromDate') + ->with($date) + ->will($this->returnValue($target)); + + $application->add($rollbackStub); + + // setup dependencies + $command = $application->find('rollback'); + + // mock the manager class + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('rollback') + ->with(self::DEFAULT_TEST_ENVIRONMENT, $target, false, false); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName(), '-d' => $date], ['decorated' => false]); + } + /** * @dataProvider getTargetFromDataProvider */ @@ -283,4 +470,32 @@ public function testStarTimeVersionOrderWithDate() $commandTester->execute(['command' => $command->getName(), '-d' => $targetDate], ['decorated' => false]); $this->assertRegExp('/ordering by execution time/', $commandTester->getDisplay()); } + + public function testStarTimeVersionOrderWithDateWithMultiDb() + { + $application = new \Phinx\Console\PhinxApplication('testing'); + $application->add(new Rollback()); + + // setup dependencies + $config = $this->getMultiDbConfig(); + $config['version_order'] = \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME; + + $command = $application->find('rollback'); + + // mock the manager class + $targetDate = '20150101'; + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$config, $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('rollback') + ->with(self::DEFAULT_TEST_ENVIRONMENT, '20150101000000', false, false); + + $command->setConfig($config); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName(), '-d' => $targetDate], ['decorated' => false]); + $this->assertRegExp('/ordering by execution time/', $commandTester->getDisplay()); + } } diff --git a/tests/Phinx/Console/Command/SeedCreateTest.php b/tests/Phinx/Console/Command/SeedCreateTest.php index cc77f5b74..5a3a158f5 100644 --- a/tests/Phinx/Console/Command/SeedCreateTest.php +++ b/tests/Phinx/Console/Command/SeedCreateTest.php @@ -57,6 +57,51 @@ protected function setUp() $this->output = new StreamOutput(fopen('php://memory', 'a', false)); } + protected function getMultiDbConfig() + { + + @mkdir(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'db1' . DIRECTORY_SEPARATOR . 'seeds', 0777, true); + $config = new Config([ + 'paths' => [ + 'migrations' => sys_get_temp_dir(), + 'seeds' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'db1' . DIRECTORY_SEPARATOR . 'seeds', + ], + 'environments' => [ + 'default_migration_table' => 'phinxlog', + 'default_database' => 'development', + 'development' => [ + 'db1' => [ + 'paths' => [ + 'migrations' => sys_get_temp_dir(), + 'seeds' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'db1' . DIRECTORY_SEPARATOR . 'seeds', + ], + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + 'db2' => [ + 'paths' => [ + 'migrations' => sys_get_temp_dir(), + 'seeds' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'db2' . DIRECTORY_SEPARATOR . 'seeds', + ], + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development_2', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + ], + ] + ]); + + return $config; + + } + /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage The file "MyDuplicateSeeder.php" already exists @@ -83,6 +128,32 @@ public function testExecute() $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateSeeder'], ['decorated' => false]); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The file "MyDuplicateSeeder.php" already exists + */ + public function testExecuteWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new SeedCreate()); + + /** @var SeedCreate $command */ + $command = $application->find('seed:create'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateSeeder'], ['decorated' => false]); + $commandTester->execute(['command' => $command->getName(), 'name' => 'MyDuplicateSeeder'], ['decorated' => false]); + } + /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage The seed class name "badseedname" is invalid. Please use CamelCase format @@ -107,4 +178,29 @@ public function testExecuteWithInvalidClassName() $commandTester = new CommandTester($command); $commandTester->execute(['command' => $command->getName(), 'name' => 'badseedname'], ['decorated' => false]); } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The seed class name "badseedname" is invalid. Please use CamelCase format + */ + public function testExecuteWithInvalidClassNameWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new SeedCreate()); + + /** @var SeedCreate $command */ + $command = $application->find('seed:create'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName(), 'name' => 'badseedname'], ['decorated' => false]); + } } diff --git a/tests/Phinx/Console/Command/SeedRunTest.php b/tests/Phinx/Console/Command/SeedRunTest.php index d80570458..6df790d5f 100644 --- a/tests/Phinx/Console/Command/SeedRunTest.php +++ b/tests/Phinx/Console/Command/SeedRunTest.php @@ -57,6 +57,50 @@ protected function setUp() $this->output = new StreamOutput(fopen('php://memory', 'a', false)); } + protected function getMultiDbConfig() + { + + $config = new Config([ + 'paths' => [ + 'migrations' => __FILE__, + 'seeds' => __FILE__, + ], + 'environments' => [ + 'default_migration_table' => 'phinxlog', + 'default_database' => 'development', + 'development' => [ + 'db1' => [ + 'paths' => [ + 'migrations' => __FILE__, + 'seeds' => __FILE__, + ], + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + 'db2' => [ + 'paths' => [ + 'migrations' => __FILE__, + 'seeds' => __FILE__, + ], + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development_2', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + ], + ] + ]); + + return $config; + + } + public function testExecute() { $application = new PhinxApplication('testing'); @@ -82,6 +126,31 @@ public function testExecute() $this->assertRegExp('/no environment specified/', $commandTester->getDisplay()); } + public function testExecuteWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new SeedRun()); + + /** @var SeedRun $command */ + $command = $application->find('seed:run'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('seed')->with($this->identicalTo('development'), $this->identicalTo(null)); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()], ['decorated' => false]); + + $this->assertRegExp('/no environment specified/', $commandTester->getDisplay()); + } + public function testExecuteWithEnvironmentOption() { $application = new PhinxApplication('testing'); @@ -102,8 +171,32 @@ public function testExecuteWithEnvironmentOption() $command->setManager($managerStub); $commandTester = new CommandTester($command); - $commandTester->execute(['command' => $command->getName(), '--environment' => 'fakeenv'], ['decorated' => false]); - $this->assertRegExp('/using environment fakeenv/', $commandTester->getDisplay()); + $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); + } + + public function testExecuteWithEnvironmentOptionWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new SeedRun()); + + /** @var SeedRun $command */ + $command = $application->find('seed:run'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->any()) + ->method('migrate'); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); } public function testDatabaseNameSpecified() @@ -130,6 +223,30 @@ public function testDatabaseNameSpecified() $this->assertRegExp('/using database development/', $commandTester->getDisplay()); } + public function testDatabaseNameSpecifiedWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new SeedRun()); + + /** @var SeedRun $command */ + $command = $application->find('seed:run'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('seed'); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute(['command' => $command->getName()], ['decorated' => false]); + $this->assertRegExp('/using database development/', $commandTester->getDisplay()); + } + public function testExecuteMultipleSeeders() { $application = new PhinxApplication('testing'); @@ -164,4 +281,39 @@ public function testExecuteMultipleSeeders() $this->assertRegExp('/no environment specified/', $commandTester->getDisplay()); } + + public function testExecuteMultipleSeedersWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new SeedRun()); + + /** @var SeedRun $command */ + $command = $application->find('seed:run'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(6)) + ->method('seed')->withConsecutive( + [$this->identicalTo('development'), $this->identicalTo('One')], + [$this->identicalTo('development'), $this->identicalTo('Two')], + [$this->identicalTo('development'), $this->identicalTo('Three')] + ); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $commandTester->execute( + [ + 'command' => $command->getName(), + '--seed' => ['One', 'Two', 'Three'], + ], + ['decorated' => false] + ); + + $this->assertRegExp('/no environment specified/', $commandTester->getDisplay()); + } } diff --git a/tests/Phinx/Console/Command/StatusTest.php b/tests/Phinx/Console/Command/StatusTest.php index 8f670e97a..3fbd5b006 100644 --- a/tests/Phinx/Console/Command/StatusTest.php +++ b/tests/Phinx/Console/Command/StatusTest.php @@ -61,6 +61,50 @@ protected function setUp() $this->output = new StreamOutput(fopen('php://memory', 'a', false)); } + protected function getMultiDbConfig() + { + + $config = new Config([ + 'paths' => [ + 'migrations' => __FILE__, + 'seeds' => __FILE__, + ], + 'environments' => [ + 'default_migration_table' => 'phinxlog', + 'default_database' => 'development', + 'development' => [ + 'db1' => [ + 'paths' => [ + 'migrations' => __FILE__, + 'seeds' => __FILE__, + ], + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + 'db2' => [ + 'paths' => [ + 'migrations' => __FILE__, + 'seeds' => __FILE__, + ], + 'adapter' => 'mysql', + 'host' => 'fakehost', + 'name' => 'development_2', + 'user' => '', + 'pass' => '', + 'port' => 3006, + ], + ], + ] + ]); + + return $config; + + } + public function testExecute() { $application = new PhinxApplication('testing'); @@ -94,6 +138,39 @@ public function testExecute() $this->assertRegExp('/ordering by creation time/', $display); } + public function testExecuteWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Status()); + + /** @var Status $command */ + $command = $application->find('status'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('printStatus') + ->with(self::DEFAULT_TEST_ENVIRONMENT, null) + ->will($this->returnValue(0)); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $return = $commandTester->execute(['command' => $command->getName()], ['decorated' => false]); + + $this->assertEquals(0, $return); + + $display = $commandTester->getDisplay(); + $this->assertRegExp('/no environment specified/', $display); + + // note that the default order is by creation time + $this->assertRegExp('/ordering by creation time/', $display); + } + public function testExecuteWithEnvironmentOption() { $application = new PhinxApplication('testing'); @@ -109,16 +186,43 @@ public function testExecuteWithEnvironmentOption() ->getMock(); $managerStub->expects($this->once()) ->method('printStatus') - ->with('fakeenv', null) + ->with('development', null) ->will($this->returnValue(0)); $command->setConfig($this->config); $command->setManager($managerStub); $commandTester = new CommandTester($command); - $return = $commandTester->execute(['command' => $command->getName(), '--environment' => 'fakeenv'], ['decorated' => false]); + $return = $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); + $this->assertEquals(0, $return); + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); + } + + public function testExecuteWithEnvironmentOptionWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Status()); + + /** @var Status $command */ + $command = $application->find('status'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('printStatus') + ->with('development', null) + ->will($this->returnValue(0)); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $return = $commandTester->execute(['command' => $command->getName(), '--environment' => 'development'], ['decorated' => false]); $this->assertEquals(0, $return); - $this->assertRegExp('/using environment fakeenv/', $commandTester->getDisplay()); + $this->assertRegExp('/using environment development/', $commandTester->getDisplay()); } public function testFormatSpecified() @@ -148,6 +252,33 @@ public function testFormatSpecified() $this->assertRegExp('/using format json/', $commandTester->getDisplay()); } + public function testFormatSpecifiedWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Status()); + + /** @var Status $command */ + $command = $application->find('status'); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$this->getMultiDbConfig(), $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('printStatus') + ->with(self::DEFAULT_TEST_ENVIRONMENT, 'json') + ->will($this->returnValue(0)); + + $command->setConfig($this->getMultiDbConfig()); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $return = $commandTester->execute(['command' => $command->getName(), '--format' => 'json'], ['decorated' => false]); + $this->assertEquals(0, $return); + $this->assertRegExp('/using format json/', $commandTester->getDisplay()); + } + public function testExecuteVersionOrderByExecutionTime() { $application = new PhinxApplication('testing'); @@ -180,4 +311,39 @@ public function testExecuteVersionOrderByExecutionTime() $this->assertRegExp('/no environment specified/', $display); $this->assertRegExp('/ordering by execution time/', $display); } + + public function testExecuteVersionOrderByExecutionTimeWithMultiDb() + { + $application = new PhinxApplication('testing'); + $application->add(new Status()); + + /** @var Status $command */ + $command = $application->find('status'); + + $config = $this->getMultiDbConfig(); + + // mock the manager class + /** @var Manager|PHPUnit_Framework_MockObject_MockObject $managerStub */ + $managerStub = $this->getMockBuilder('\Phinx\Migration\Manager') + ->setConstructorArgs([$config, $this->input, $this->output]) + ->getMock(); + $managerStub->expects($this->exactly(2)) + ->method('printStatus') + ->with(self::DEFAULT_TEST_ENVIRONMENT, null) + ->will($this->returnValue(0)); + + $config['version_order'] = \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME; + + $command->setConfig($config); + $command->setManager($managerStub); + + $commandTester = new CommandTester($command); + $return = $commandTester->execute(['command' => $command->getName()], ['decorated' => false]); + + $this->assertEquals(0, $return); + + $display = $commandTester->getDisplay(); + $this->assertRegExp('/no environment specified/', $display); + $this->assertRegExp('/ordering by execution time/', $display); + } } diff --git a/tests/Phinx/Migration/ManagerTest.php b/tests/Phinx/Migration/ManagerTest.php index 8bcd39f60..8700ef340 100644 --- a/tests/Phinx/Migration/ManagerTest.php +++ b/tests/Phinx/Migration/ManagerTest.php @@ -125,6 +125,13 @@ public function testInstantiation() ); } + public function testSetDbRef() + { + $reference = 'TestReference'; + $this->manager->setDbRef($reference); + $this->assertEquals($reference, $this->manager->getDbRef()); + } + public function testPrintStatusMethod() { // stub environment @@ -5358,10 +5365,6 @@ public function testExecuteASingleSeedWorksAsExpectedWithMixedNamespace() $this->assertContains('Baz\UserSeeder', $output); } - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage The seed class "NonExistentSeeder" does not exist - */ public function testExecuteANonExistentSeedWorksAsExpected() { // stub environment @@ -5372,13 +5375,9 @@ public function testExecuteANonExistentSeedWorksAsExpected() $this->manager->seed('mockenv', 'NonExistentSeeder'); rewind($this->manager->getOutput()->getStream()); $output = stream_get_contents($this->manager->getOutput()->getStream()); - $this->assertContains('UserSeeder', $output); + $this->assertContains('NonExistentSeeder', $output); } - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage The seed class "Foo\Bar\NonExistentSeeder" does not exist - */ public function testExecuteANonExistentSeedWorksAsExpectedWithNamespace() { // stub environment @@ -5390,13 +5389,9 @@ public function testExecuteANonExistentSeedWorksAsExpectedWithNamespace() $this->manager->seed('mockenv', 'Foo\Bar\NonExistentSeeder'); rewind($this->manager->getOutput()->getStream()); $output = stream_get_contents($this->manager->getOutput()->getStream()); - $this->assertContains('Foo\Bar\UserSeeder', $output); + $this->assertContains('Foo\Bar\NonExistentSeeder', $output); } - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage The seed class "Baz\NonExistentSeeder" does not exist - */ public function testExecuteANonExistentSeedWorksAsExpectedWithMixedNamespace() { // stub environment @@ -5405,12 +5400,11 @@ public function testExecuteANonExistentSeedWorksAsExpectedWithMixedNamespace() ->getMock(); $this->manager->setConfig($this->getConfigWithMixedNamespace()); $this->manager->setEnvironments(['mockenv' => $envStub]); - $this->manager->seed('mockenv', 'Baz\NonExistentSeeder'); + $this->manager->seed('mockenv', 'Foo\Baz\NonExistentSeeder'); rewind($this->manager->getOutput()->getStream()); $output = stream_get_contents($this->manager->getOutput()->getStream()); - $this->assertContains('UserSeeder', $output); - $this->assertContains('Baz\UserSeeder', $output); - $this->assertContains('Foo\Bar\UserSeeder', $output); + $this->assertContains('Baz\NonExistentSeeder', $output); + $this->assertContains('Foo\Baz\NonExistentSeeder', $output); } public function testGettingInputObject()