diff --git a/docs/en/reference/custom_configuration.rst b/docs/en/reference/custom_configuration.rst index eefb6df003..9602d0d597 100644 --- a/docs/en/reference/custom_configuration.rst +++ b/docs/en/reference/custom_configuration.rst @@ -18,6 +18,7 @@ code that would looks like the following: $configuration->setMigrationsDirectory('/path/to/project/src/App/Migrations'); $configuration->setMigrationsNamespace('App/Migrations'); $configuration->registerMigrationsFromDirectory('/path/to/project/src/App/Migrations'); + $configuration->setAllOrNothing(true); // My command that extends Doctrine\DBAL\Migrations\Tools\Console\Command\AbstractCommand $command->setMigrationConfiguration($configuration); diff --git a/docs/en/reference/installation.rst b/docs/en/reference/installation.rst index 155791d268..e4e8df46dc 100644 --- a/docs/en/reference/installation.rst +++ b/docs/en/reference/installation.rst @@ -70,6 +70,8 @@ file like the following: /path/to/migrations/classes/DoctrineMigrations + 1 + Of course you could do the same thing with a *configuration.yml* file: @@ -82,6 +84,7 @@ Of course you could do the same thing with a *configuration.yml* file: column_name: version executed_at_column_name: executed_at migrations_directory: /path/to/migrations/classes/DoctrineMigrations + all_or_nothing: true With the above example, the migrations tool will search the ``migrations_directory`` recursively for files that begin with ``Version`` followed one to 255 characters diff --git a/docs/en/reference/introduction.rst b/docs/en/reference/introduction.rst index 7c2f392010..05bc4b03d3 100644 --- a/docs/en/reference/introduction.rst +++ b/docs/en/reference/introduction.rst @@ -63,7 +63,7 @@ commands to our `Doctrine Command Line Interface ` for you. - And if you want to specify each migration manually in YAML you can: .. code-block:: yaml @@ -193,10 +192,80 @@ And if you want to specify each migration manually in YAML you can: table_name: doctrine_migration_versions migrations_directory: /path/to/migrations/classes/DoctrineMigrations migrations: - migration1: - version: 20100704000000 - class: DoctrineMigrations\NewMigration + migration1: + version: 20100704000000 + class: DoctrineMigrations\NewMigration If you specify your own migration classes (like `DoctrineMigrations\NewMigration` in the previous example) you will need an autoloader unless all those classes begin with the prefix Version*, for example path/to/migrations/classes/VersionNewMigration.php. + +All or Nothing Migrations +~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want your migrations to be all or nothing then you can configure your migrations behave that way. +This means when you executed multiple migrations in a row, the whole migration will be wrapped +in a single migration and if one of the migrations fails, the transaction will be rolled back. + +.. note:: + + This only works if the database connection you are using supports transactional DDL statements. + +.. configuration-block:: + + .. code-block:: php + + $configuration = new Configuration($connection); + $configuration->setAllOrNothing(true); + + .. code-block:: xml + + + + + Doctrine Sandbox Migrations + + DoctrineMigrations + + + + /path/to/migrations/classes/DoctrineMigrations + + 1 + + + + .. code-block:: yaml + + name: Doctrine Sandbox Migrations + migrations_namespace: DoctrineMigrations + table_name: doctrine_migration_versions + migrations_directory: /path/to/migrations/classes/DoctrineMigrations + all_or_nothing: true + + + .. code-block:: json + + { + "name" : "Doctrine Sandbox Migrations", + "migrations_namespace" : "DoctrineMigrations", + "table_name" : "doctrine_migration_versions", + "migrations_directory" : "/path/to/migrations/classes/DoctrineMigrations", + "all_or_nothing" : true + } + +You can also optionally use the ``--all-or-nothing`` option from the command line to enable or disable +the feature for a specific migration run: + +.. code-block:: bash + + $ ./doctrine migrations:migrate --all-or-nothing + +Or if you have it enabled in your configuration setup and you want to disable it for a migration: + +.. code-block:: bash + + $ ./doctrine migrations:migrate --all-or-nothing=0 diff --git a/lib/Doctrine/Migrations/Configuration/AbstractFileConfiguration.php b/lib/Doctrine/Migrations/Configuration/AbstractFileConfiguration.php index d6344e5bd0..f832b5c3f2 100644 --- a/lib/Doctrine/Migrations/Configuration/AbstractFileConfiguration.php +++ b/lib/Doctrine/Migrations/Configuration/AbstractFileConfiguration.php @@ -30,6 +30,7 @@ abstract class AbstractFileConfiguration extends Configuration 'migrations_directory', 'migrations', 'custom_template', + 'all_or_nothing', ]; /** @var string */ @@ -113,11 +114,15 @@ protected function setConfiguration(array $config) : void $this->loadMigrations($config['migrations']); } - if (! isset($config['custom_template'])) { + if (isset($config['custom_template'])) { + $this->setCustomTemplate($config['custom_template']); + } + + if (! isset($config['all_or_nothing'])) { return; } - $this->setCustomTemplate($config['custom_template']); + $this->setAllOrNothing($config['all_or_nothing']); } protected function getDirectoryRelativeToFile(string $file, string $input) : string diff --git a/lib/Doctrine/Migrations/Configuration/Configuration.php b/lib/Doctrine/Migrations/Configuration/Configuration.php index ea01b39beb..255fe57e49 100644 --- a/lib/Doctrine/Migrations/Configuration/Configuration.php +++ b/lib/Doctrine/Migrations/Configuration/Configuration.php @@ -63,6 +63,9 @@ class Configuration /** @var bool */ private $isDryRun = false; + /** @var bool */ + private $allOrNothing = false; + /** @var Connection */ private $connection; @@ -289,6 +292,16 @@ public function isDryRun() : bool return $this->isDryRun; } + public function setAllOrNothing(bool $allOrNothing) : void + { + $this->allOrNothing = $allOrNothing; + } + + public function isAllOrNothing() : bool + { + return $this->allOrNothing; + } + public function isMigrationTableCreated() : bool { return $this->getDependencyFactory()->getMigrationTableStatus()->isCreated(); diff --git a/lib/Doctrine/Migrations/Configuration/XML/configuration.xsd b/lib/Doctrine/Migrations/Configuration/XML/configuration.xsd index ff93498107..155a25f718 100644 --- a/lib/Doctrine/Migrations/Configuration/XML/configuration.xsd +++ b/lib/Doctrine/Migrations/Configuration/XML/configuration.xsd @@ -24,6 +24,7 @@ + diff --git a/lib/Doctrine/Migrations/Configuration/XmlConfiguration.php b/lib/Doctrine/Migrations/Configuration/XmlConfiguration.php index 200259db91..2b50c9a91c 100644 --- a/lib/Doctrine/Migrations/Configuration/XmlConfiguration.php +++ b/lib/Doctrine/Migrations/Configuration/XmlConfiguration.php @@ -65,6 +65,10 @@ protected function doLoad(string $file) : void $config['migrations_directory'] = $this->getDirectoryRelativeToFile($file, (string) $xml->{'migrations-directory'}); } + if (isset($xml->{'all-or-nothing'})) { + $config['all_or_nothing'] = (bool) $xml->{'all-or-nothing'}; + } + if (isset($xml->migrations->migration)) { $migrations = []; diff --git a/lib/Doctrine/Migrations/Migrator.php b/lib/Doctrine/Migrations/Migrator.php index cb57760bb9..dce02eb7d5 100644 --- a/lib/Doctrine/Migrations/Migrator.php +++ b/lib/Doctrine/Migrations/Migrator.php @@ -9,6 +9,7 @@ use Doctrine\Migrations\Exception\NoMigrationsToExecute; use Doctrine\Migrations\Exception\UnknownMigrationVersion; use Doctrine\Migrations\Tools\BytesFormatter; +use Throwable; use const COUNT_RECURSIVE; use function count; use function sprintf; @@ -50,7 +51,10 @@ public function setNoMigrationException(bool $noMigrationException = false) : vo /** @return string[][] */ public function getSql(?string $to = null) : array { - return $this->migrate($to, true); + $migratorConfig = (new MigratorConfig()) + ->setDryRun(true); + + return $this->migrate($to, $migratorConfig); } public function writeSqlFile(string $path, ?string $to = null) : bool @@ -87,10 +91,12 @@ public function writeSqlFile(string $path, ?string $to = null) : bool */ public function migrate( ?string $to = null, - bool $dryRun = false, - bool $timeAllQueries = false, - ?callable $confirm = null + ?MigratorConfig $migratorConfig = null ) : array { + $migratorConfig = $migratorConfig ?? new MigratorConfig(); + $dryRun = $migratorConfig->isDryRun(); + $confirm = $migratorConfig->getConfirm(); + if ($to === null) { $to = $this->migrationRepository->getLatestVersion(); } @@ -144,15 +150,39 @@ public function migrate( $this->configuration->dispatchMigrationEvent(Events::onMigrationsMigrating, $direction, $dryRun); - $sql = []; + $connection = $this->configuration->getConnection(); + + $allOrNothing = $migratorConfig->isAllOrNothing(); + + if ($allOrNothing) { + $connection->beginTransaction(); + } + + try { + $this->configuration->dispatchMigrationEvent(Events::onMigrationsMigrating, $direction, $dryRun); + + $sql = []; + $time = 0; + + foreach ($migrationsToExecute as $version) { + $versionExecutionResult = $version->execute($direction, $migratorConfig); - foreach ($migrationsToExecute as $version) { - $versionExecutionResult = $version->execute($direction, $dryRun, $timeAllQueries); + $sql[$version->getVersion()] = $versionExecutionResult->getSql(); + $time += $versionExecutionResult->getTime(); + } - $sql[$version->getVersion()] = $versionExecutionResult->getSql(); + $this->configuration->dispatchMigrationEvent(Events::onMigrationsMigrated, $direction, $dryRun); + } catch (Throwable $e) { + if ($allOrNothing) { + $connection->rollBack(); + } + + throw $e; } - $this->configuration->dispatchMigrationEvent(Events::onMigrationsMigrated, $direction, $dryRun); + if ($allOrNothing) { + $connection->commit(); + } $stopwatchEvent->stop(); diff --git a/lib/Doctrine/Migrations/MigratorConfig.php b/lib/Doctrine/Migrations/MigratorConfig.php new file mode 100644 index 0000000000..984d372038 --- /dev/null +++ b/lib/Doctrine/Migrations/MigratorConfig.php @@ -0,0 +1,83 @@ +dryRun; + } + + public function setDryRun(bool $dryRun) : self + { + $this->dryRun = $dryRun; + + return $this; + } + + public function getTimeAllQueries() : bool + { + return $this->timeAllQueries; + } + + public function setTimeAllQueries(bool $timeAllQueries) : self + { + $this->timeAllQueries = $timeAllQueries; + + return $this; + } + + public function getNoMigrationException() : bool + { + return $this->noMigrationException; + } + + public function setNoMigrationException(bool $noMigrationException = false) : self + { + $this->noMigrationException = $noMigrationException; + + return $this; + } + + public function isAllOrNothing() : bool + { + return $this->allOrNothing; + } + + public function setAllOrNothing(bool $allOrNothing) : self + { + $this->allOrNothing = $allOrNothing; + + return $this; + } + + public function getConfirm() : ?callable + { + return $this->confirm; + } + + public function setConfirm(callable $confirm) : self + { + $this->confirm = $confirm; + + return $this; + } +} diff --git a/lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php b/lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php index 6f32e35f17..aee128809f 100644 --- a/lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php +++ b/lib/Doctrine/Migrations/Tools/Console/Command/ExecuteCommand.php @@ -4,6 +4,7 @@ namespace Doctrine\Migrations\Tools\Console\Command; +use Doctrine\Migrations\MigratorConfig; use Doctrine\Migrations\VersionDirection; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -87,7 +88,7 @@ protected function configure() : void public function execute(InputInterface $input, OutputInterface $output) : int { $version = $input->getArgument('version'); - $timeAllqueries = $input->getOption('query-time'); + $timeAllQueries = $input->getOption('query-time'); $dryRun = $input->getOption('dry-run'); $path = $input->getOption('write-sql'); $direction = $input->getOption('down') !== false @@ -104,16 +105,28 @@ public function execute(InputInterface $input, OutputInterface $output) : int return 0; } - $question = 'WARNING! You are about to execute a database migration that could result in schema changes and data lost. Are you sure you wish to continue? (y/n)'; + $cancelled = false; - if (! $this->canExecute($question, $input, $output)) { + $migratorConfig = (new MigratorConfig()) + ->setDryRun($dryRun) + ->setTimeAllQueries($timeAllQueries) + ->setConfirm(function () use ($input, $output, &$cancelled) { + $question = 'WARNING! You are about to execute a database migration that could result in schema changes and data lost. Are you sure you wish to continue? (y/n)'; + + $canContinue = $this->canExecute($question, $input, $output); + $cancelled = ! $canContinue; + + return $canContinue; + }) + ; + + $version->execute($direction, $migratorConfig); + + if ($cancelled) { $output->writeln('Migration cancelled!'); return 1; } - - $version->execute($direction, $dryRun, $timeAllqueries); - return 0; } } diff --git a/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php b/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php index 279548d916..35309c577d 100644 --- a/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php +++ b/lib/Doctrine/Migrations/Tools/Console/Command/MigrateCommand.php @@ -5,6 +5,7 @@ namespace Doctrine\Migrations\Tools\Console\Command; use Doctrine\Migrations\Migrator; +use Doctrine\Migrations\MigratorConfig; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -56,6 +57,13 @@ protected function configure() : void InputOption::VALUE_NONE, 'Don\'t throw an exception if no migration is available (CI).' ) + ->addOption( + 'all-or-nothing', + null, + InputOption::VALUE_OPTIONAL, + 'Wrap the entire migration in a transaction.', + false + ) ->setHelp(<<%command.name% command executes a migration to a specified version or the latest available version: @@ -89,6 +97,8 @@ protected function configure() : void You can also time all the different queries if you wanna know which one is taking so long: %command.full_name% --query-time + +Use the --all-or-nothing option to wrap the entire migration in a transaction. EOT ); @@ -104,8 +114,18 @@ public function execute(InputInterface $input, OutputInterface $output) : int $version = (string) $input->getArgument('version'); $path = $input->getOption('write-sql'); $allowNoMigration = (bool) $input->getOption('allow-no-migration'); - $timeAllqueries = (bool) $input->getOption('query-time'); + $timeAllQueries = (bool) $input->getOption('query-time'); $dryRun = (bool) $input->getOption('dry-run'); + $allOrNothing = $input->getOption('all-or-nothing'); + + if ($allOrNothing !== false) { + $allOrNothing = $allOrNothing !== null + ? (bool) $allOrNothing + : true + ; + } else { + $allOrNothing = $this->configuration->isAllOrNothing(); + } $this->configuration->setIsDryRun($dryRun); @@ -134,19 +154,22 @@ public function execute(InputInterface $input, OutputInterface $output) : int $migrator->setNoMigrationException($allowNoMigration); - $result = $migrator->migrate( - $version, - $dryRun, - $timeAllqueries, - function () use ($input, $output, &$cancelled) { + $migratorConfig = (new MigratorConfig()) + ->setDryRun($dryRun) + ->setTimeAllQueries($timeAllQueries) + ->setNoMigrationException($allowNoMigration) + ->setAllOrNothing($allOrNothing) + ->setConfirm(function () use ($input, $output, &$cancelled) { $question = 'WARNING! You are about to execute a database migration that could result in schema changes and data loss. Are you sure you wish to continue? (y/n)'; $canContinue = $this->canExecute($question, $input, $output); $cancelled = ! $canContinue; return $canContinue; - } - ); + }) + ; + + $migrator->migrate($version, $migratorConfig); if ($cancelled) { $output->writeln('Migration cancelled!'); diff --git a/lib/Doctrine/Migrations/Version.php b/lib/Doctrine/Migrations/Version.php index 1df55a35a7..4d97a304a1 100644 --- a/lib/Doctrine/Migrations/Version.php +++ b/lib/Doctrine/Migrations/Version.php @@ -139,7 +139,10 @@ public function writeSqlFile( string $path, string $direction = VersionDirection::UP ) : bool { - $versionExecutionResult = $this->execute($direction, true); + $migratorConfig = (new MigratorConfig()) + ->setDryRun(true); + + $versionExecutionResult = $this->execute($direction, $migratorConfig); if (count($versionExecutionResult->getParams()) !== 0) { throw MigrationNotConvertibleToSql::new($this->class); @@ -160,15 +163,13 @@ public function writeSqlFile( public function execute( string $direction, - bool $dryRun = false, - bool $timeAllQueries = false + ?MigratorConfig $migratorConfig = null ) : VersionExecutionResult { return $this->versionExecutor->execute( $this, $this->migration, $direction, - $dryRun, - $timeAllQueries + $migratorConfig ); } diff --git a/lib/Doctrine/Migrations/VersionExecutor.php b/lib/Doctrine/Migrations/VersionExecutor.php index 38062f5bd5..60c699752b 100644 --- a/lib/Doctrine/Migrations/VersionExecutor.php +++ b/lib/Doctrine/Migrations/VersionExecutor.php @@ -106,12 +106,13 @@ public function execute( Version $version, AbstractMigration $migration, string $direction, - bool $dryRun = false, - bool $timeAllQueries = false + ?MigratorConfig $migratorConfig = null ) : VersionExecutionResult { + $migratorConfig = $migratorConfig ?? new MigratorConfig(); + $versionExecutionResult = new VersionExecutionResult(); - $this->startMigration($version, $migration, $direction, $dryRun); + $this->startMigration($version, $migration, $direction, $migratorConfig); try { $this->executeMigration( @@ -119,8 +120,7 @@ public function execute( $migration, $versionExecutionResult, $direction, - $dryRun, - $timeAllQueries + $migratorConfig ); $versionExecutionResult->setSql($this->sql); @@ -132,7 +132,7 @@ public function execute( $version, $migration, $direction, - $dryRun + $migratorConfig ); $versionExecutionResult->setSkipped(true); @@ -152,7 +152,7 @@ private function startMigration( Version $version, AbstractMigration $migration, string $direction, - bool $dryRun + MigratorConfig $migratorConfig ) : void { $this->sql = []; $this->params = []; @@ -162,14 +162,14 @@ private function startMigration( $version, Events::onMigrationsVersionExecuting, $direction, - $dryRun + $migratorConfig->isDryRun() ); if (! $migration->isTransactional()) { return; } - //only start transaction if in transactional mode + // only start transaction if in transactional mode $this->connection->beginTransaction(); } @@ -178,8 +178,7 @@ private function executeMigration( AbstractMigration $migration, VersionExecutionResult $versionExecutionResult, string $direction, - bool $dryRun, - bool $timeAllQueries + MigratorConfig $migratorConfig ) : VersionExecutionResult { $stopwatchEvent = $this->stopwatch->start('execute'); @@ -206,8 +205,8 @@ private function executeMigration( } if (count($this->sql) !== 0) { - if (! $dryRun) { - $this->executeVersionExecutionResult($version, $dryRun, $timeAllQueries); + if (! $migratorConfig->isDryRun()) { + $this->executeVersionExecutionResult($version, $migratorConfig); } else { foreach ($this->sql as $idx => $query) { $this->outputSqlQuery($idx, $query); @@ -224,7 +223,7 @@ private function executeMigration( $migration->{'post' . ucfirst($direction)}($toSchema); - if (! $dryRun) { + if (! $migratorConfig->isDryRun()) { $version->markVersion($direction); } @@ -258,7 +257,7 @@ private function executeMigration( $version, Events::onMigrationsVersionExecuted, $direction, - $dryRun + $migratorConfig->isDryRun() ); return $versionExecutionResult; @@ -269,14 +268,14 @@ private function skipMigration( Version $version, AbstractMigration $migration, string $direction, - bool $dryRun + MigratorConfig $migratorConfig ) : void { if ($migration->isTransactional()) { //only rollback transaction if in transactional mode $this->connection->rollBack(); } - if ($dryRun === false) { + if (! $migratorConfig->isDryRun()) { $version->markVersion($direction); } @@ -288,7 +287,7 @@ private function skipMigration( $version, Events::onMigrationsVersionSkipped, $direction, - $dryRun + $migratorConfig->isDryRun() ); } @@ -314,8 +313,7 @@ private function migrationError(Throwable $e, Version $version, AbstractMigratio private function executeVersionExecutionResult( Version $version, - bool $dryRun = false, - bool $timeAllQueries = false + MigratorConfig $migratorConfig ) : void { foreach ($this->sql as $key => $query) { $stopwatchEvent = $this->stopwatch->start('query'); @@ -330,7 +328,7 @@ private function executeVersionExecutionResult( $stopwatchEvent->stop(); - if (! $timeAllQueries) { + if (! $migratorConfig->getTimeAllQueries()) { continue; } diff --git a/lib/Doctrine/Migrations/VersionExecutorInterface.php b/lib/Doctrine/Migrations/VersionExecutorInterface.php index d0f2a861a1..60b984a892 100644 --- a/lib/Doctrine/Migrations/VersionExecutorInterface.php +++ b/lib/Doctrine/Migrations/VersionExecutorInterface.php @@ -19,7 +19,6 @@ public function execute( Version $version, AbstractMigration $migration, string $direction, - bool $dryRun = false, - bool $timeAllQueries = false + ?MigratorConfig $migratorConfig = null ) : VersionExecutionResult; } diff --git a/tests/Doctrine/Migrations/Tests/Configuration/AbstractConfigurationTest.php b/tests/Doctrine/Migrations/Tests/Configuration/AbstractConfigurationTest.php index 4ae6768a0e..e8098567a4 100644 --- a/tests/Doctrine/Migrations/Tests/Configuration/AbstractConfigurationTest.php +++ b/tests/Doctrine/Migrations/Tests/Configuration/AbstractConfigurationTest.php @@ -59,6 +59,13 @@ public function testMigrationsColumnLength() : void self::assertEquals(200, $config->getMigrationsColumnLength()); } + public function testAllOrNothing() : void + { + $config = $this->loadConfiguration(); + + self::assertTrue($config->isAllOrNothing()); + } + public function testMigrationsExecutedAtColumnName() : void { $config = $this->loadConfiguration(); diff --git a/tests/Doctrine/Migrations/Tests/Configuration/AbstractFileConfigurationTest.php b/tests/Doctrine/Migrations/Tests/Configuration/AbstractFileConfigurationTest.php index f688ec6c17..05e20c0f14 100644 --- a/tests/Doctrine/Migrations/Tests/Configuration/AbstractFileConfigurationTest.php +++ b/tests/Doctrine/Migrations/Tests/Configuration/AbstractFileConfigurationTest.php @@ -49,6 +49,7 @@ public function testSetConfiguration() : void 'registerMigrationsFromDirectory', 'registerMigration', 'setCustomTemplate', + 'setAllOrNothing', ]); $fileConfiguration->expects($this->once()) @@ -94,6 +95,10 @@ public function testSetConfiguration() : void ->method('setCustomTemplate') ->with('custom_template'); + $fileConfiguration->expects($this->once()) + ->method('setAllOrNothing') + ->with(true); + $fileConfiguration->setTestConfiguration([ 'migrations_namespace' => 'Doctrine', 'table_name' => 'migration_version', @@ -110,6 +115,7 @@ public function testSetConfiguration() : void ], ], 'custom_template' => 'custom_template', + 'all_or_nothing' => true, ]); } diff --git a/tests/Doctrine/Migrations/Tests/Configuration/ConfigurationTest.php b/tests/Doctrine/Migrations/Tests/Configuration/ConfigurationTest.php index d0ae94cead..60d06c1263 100644 --- a/tests/Doctrine/Migrations/Tests/Configuration/ConfigurationTest.php +++ b/tests/Doctrine/Migrations/Tests/Configuration/ConfigurationTest.php @@ -334,6 +334,17 @@ public function testGetVersionData() : void self::assertEquals($versionData, $configuration->getVersionData($version)); } + public function testGetSetAllOrNothing() : void + { + $configuration = $this->createPartialMock(Configuration::class, []); + + self::assertFalse($configuration->isAllOrNothing()); + + $configuration->setAllOrNothing(true); + + self::assertTrue($configuration->isAllOrNothing()); + } + /** * @return \PHPUnit_Framework_MockObject_MockObject|Connection */ diff --git a/tests/Doctrine/Migrations/Tests/Configuration/_files/config.json b/tests/Doctrine/Migrations/Tests/Configuration/_files/config.json index 499e492666..59ebf9d837 100644 --- a/tests/Doctrine/Migrations/Tests/Configuration/_files/config.json +++ b/tests/Doctrine/Migrations/Tests/Configuration/_files/config.json @@ -1,11 +1,11 @@ { - "name" : "Doctrine Sandbox Migrations", - "migrations_namespace" : "DoctrineMigrationsTest", - "table_name" : "doctrine_migration_versions_test", - "column_name" : "doctrine_migration_column_test", - "column_length" : 200, - "executed_at_column_name" : "doctrine_migration_executed_at_column_test", - "migrations_directory" : ".", - "migrations" : [] + "name" : "Doctrine Sandbox Migrations", + "migrations_namespace" : "DoctrineMigrationsTest", + "table_name" : "doctrine_migration_versions_test", + "column_name" : "doctrine_migration_column_test", + "column_length" : 200, + "executed_at_column_name" : "doctrine_migration_executed_at_column_test", + "migrations_directory" : ".", + "migrations" : [], + "all_or_nothing" : true } - diff --git a/tests/Doctrine/Migrations/Tests/Configuration/_files/config.php b/tests/Doctrine/Migrations/Tests/Configuration/_files/config.php index b95bc0fb8f..4e9b084b15 100644 --- a/tests/Doctrine/Migrations/Tests/Configuration/_files/config.php +++ b/tests/Doctrine/Migrations/Tests/Configuration/_files/config.php @@ -11,4 +11,5 @@ 'executed_at_column_name' => 'doctrine_migration_executed_at_column_test', 'migrations_directory' => '.', 'migrations' => [], + 'all_or_nothing' => true, ]; diff --git a/tests/Doctrine/Migrations/Tests/Configuration/_files/config.xml b/tests/Doctrine/Migrations/Tests/Configuration/_files/config.xml index fae1fb3841..62b707fd54 100644 --- a/tests/Doctrine/Migrations/Tests/Configuration/_files/config.xml +++ b/tests/Doctrine/Migrations/Tests/Configuration/_files/config.xml @@ -8,5 +8,6 @@ DoctrineMigrationsTest
. + 1 diff --git a/tests/Doctrine/Migrations/Tests/Configuration/_files/config.yml b/tests/Doctrine/Migrations/Tests/Configuration/_files/config.yml index bbefc1e416..9b0191a57b 100644 --- a/tests/Doctrine/Migrations/Tests/Configuration/_files/config.yml +++ b/tests/Doctrine/Migrations/Tests/Configuration/_files/config.yml @@ -7,3 +7,4 @@ column_length: 200 executed_at_column_name: doctrine_migration_executed_at_column_test migrations_directory: . migrations: [] +all_or_nothing: true diff --git a/tests/Doctrine/Migrations/Tests/Functional/FunctionalTest.php b/tests/Doctrine/Migrations/Tests/Functional/FunctionalTest.php index 44d9bd23d5..1616a140ac 100644 --- a/tests/Doctrine/Migrations/Tests/Functional/FunctionalTest.php +++ b/tests/Doctrine/Migrations/Tests/Functional/FunctionalTest.php @@ -11,6 +11,7 @@ use Doctrine\Migrations\Configuration\Configuration; use Doctrine\Migrations\Event\Listeners\AutoCommitListener; use Doctrine\Migrations\Events; +use Doctrine\Migrations\MigratorConfig; use Doctrine\Migrations\ParameterFormatter; use Doctrine\Migrations\Provider\LazySchemaDiffProvider; use Doctrine\Migrations\Provider\SchemaDiffProvider; @@ -163,8 +164,12 @@ public function testDryRunMigration() : void $this->config->registerMigration('2', MigrationSkipMigration::class); $this->config->registerMigration('3', MigrationMigrateFurther::class); + $migratorConfig = (new MigratorConfig()) + ->setDryRun(true) + ; + $migrator = $this->createTestMigrator($this->config); - $migrator->migrate('3', true); + $migrator->migrate('3', $migratorConfig); $schema = $this->config->getConnection()->getSchemaManager()->createSchema(); self::assertFalse($schema->hasTable('foo')); diff --git a/tests/Doctrine/Migrations/Tests/MigratorTest.php b/tests/Doctrine/Migrations/Tests/MigratorTest.php index e14b2e9f32..89df4e23b5 100644 --- a/tests/Doctrine/Migrations/Tests/MigratorTest.php +++ b/tests/Doctrine/Migrations/Tests/MigratorTest.php @@ -10,6 +10,7 @@ use Doctrine\Migrations\Exception\MigrationException; use Doctrine\Migrations\MigrationRepository; use Doctrine\Migrations\Migrator; +use Doctrine\Migrations\MigratorConfig; use Doctrine\Migrations\OutputWriter; use Doctrine\Migrations\QueryWriter; use Doctrine\Migrations\Stopwatch; @@ -138,7 +139,7 @@ public function testGetSql(?string $to) : void $migration->expects($this->once()) ->method('migrate') - ->with($to, true) + ->with($to) ->willReturn($expected); $result = $migration->getSql($to); @@ -267,10 +268,14 @@ public function testMigrateReturnsFalseWhenTheConfirmationIsDeclined() : void $called = false; $migration = $this->createTestMigrator($this->config); - $result = $migration->migrate(null, false, false, function () use (&$called) { - $called = true; - return false; - }); + $migratorConfig = (new MigratorConfig()) + ->setConfirm(function () use (&$called) { + $called = true; + + return false; + }); + + $result = $migration->migrate(null, $migratorConfig); self::assertEmpty($result); self::assertTrue($called, 'should have called the confirmation callback'); @@ -285,10 +290,15 @@ public function testMigrateWithDryRunDoesNotCallTheConfirmationCallback() : void $called = false; $migrator = $this->createTestMigrator($this->config); - $result = $migrator->migrate(null, true, false, function () use (&$called) { - $called = true; - return false; - }); + $migratorConfig = (new MigratorConfig()) + ->setDryRun(true) + ->setConfirm(function () use (&$called) { + $called = true; + + return false; + }); + + $result = $migrator->migrate(null, $migratorConfig); self::assertFalse($called); self::assertEquals(['20160707000000' => ['SELECT 1']], $result); diff --git a/tests/Doctrine/Migrations/Tests/Tools/Console/Command/ExecuteCommandTest.php b/tests/Doctrine/Migrations/Tests/Tools/Console/Command/ExecuteCommandTest.php index 32ec34dbc2..2e2fde8a49 100644 --- a/tests/Doctrine/Migrations/Tests/Tools/Console/Command/ExecuteCommandTest.php +++ b/tests/Doctrine/Migrations/Tests/Tools/Console/Command/ExecuteCommandTest.php @@ -128,65 +128,13 @@ public function testExecute() : void ->with($versionName) ->willReturn($version); - $this->executeCommand->expects($this->once()) - ->method('canExecute') - ->willReturn(true); - $version->expects($this->once()) ->method('execute') - ->with('down', true, true); + ->with('down'); self::assertEquals(0, $this->executeCommand->execute($input, $output)); } - public function testExecuteCanExecuteFalse() : void - { - $versionName = '1'; - - $input = $this->createMock(InputInterface::class); - $output = $this->createMock(OutputInterface::class); - $version = $this->createMock(Version::class); - - $input->expects($this->once()) - ->method('getArgument') - ->with('version') - ->willReturn($versionName); - - $input->expects($this->at(1)) - ->method('getOption') - ->with('query-time') - ->willReturn(true); - - $input->expects($this->at(2)) - ->method('getOption') - ->with('dry-run') - ->willReturn(true); - - $input->expects($this->at(3)) - ->method('getOption') - ->with('write-sql') - ->willReturn(false); - - $input->expects($this->at(4)) - ->method('getOption') - ->with('down') - ->willReturn(true); - - $this->migrationRepository->expects($this->once()) - ->method('getVersion') - ->with($versionName) - ->willReturn($version); - - $this->executeCommand->expects($this->once()) - ->method('canExecute') - ->willReturn(false); - - $version->expects($this->never()) - ->method('execute'); - - self::assertEquals(1, $this->executeCommand->execute($input, $output)); - } - protected function setUp() : void { $this->migrationRepository = $this->createMock(MigrationRepository::class); diff --git a/tests/Doctrine/Migrations/Tests/Tools/Console/Command/MigrateCommandTest.php b/tests/Doctrine/Migrations/Tests/Tools/Console/Command/MigrateCommandTest.php index 2d1bf6c319..fbb447026d 100644 --- a/tests/Doctrine/Migrations/Tests/Tools/Console/Command/MigrateCommandTest.php +++ b/tests/Doctrine/Migrations/Tests/Tools/Console/Command/MigrateCommandTest.php @@ -315,7 +315,7 @@ public function testExecuteMigrate() : void $migrator->expects($this->once()) ->method('migrate') - ->with('1234', false, false); + ->with('1234'); self::assertEquals(0, $this->migrateCommand->execute($input, $output)); } diff --git a/tests/Doctrine/Migrations/Tests/VersionExecutorTest.php b/tests/Doctrine/Migrations/Tests/VersionExecutorTest.php index 0662519341..d086b34587 100644 --- a/tests/Doctrine/Migrations/Tests/VersionExecutorTest.php +++ b/tests/Doctrine/Migrations/Tests/VersionExecutorTest.php @@ -9,6 +9,7 @@ use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\Configuration\Configuration; +use Doctrine\Migrations\MigratorConfig; use Doctrine\Migrations\OutputWriter; use Doctrine\Migrations\ParameterFormatterInterface; use Doctrine\Migrations\Provider\SchemaDiffProviderInterface; @@ -107,12 +108,15 @@ public function testExecuteUp() : void ->method('write') ->with("\n ++ migrated (took 100ms, used 100 memory)"); + $migratorConfig = (new MigratorConfig()) + ->setTimeAllQueries(true) + ; + $versionExecutionResult = $this->versionExecutor->execute( $this->version, $this->migration, VersionDirection::UP, - false, - true + $migratorConfig ); self::assertInstanceOf(VersionExecutionResult::class, $versionExecutionResult); @@ -170,12 +174,15 @@ public function testExecuteDown() : void ->method('write') ->with("\n -- reverted (took 100ms, used 100 memory)"); + $migratorConfig = (new MigratorConfig()) + ->setTimeAllQueries(true) + ; + $versionExecutionResult = $this->versionExecutor->execute( $this->version, $this->migration, VersionDirection::DOWN, - false, - true + $migratorConfig ); self::assertInstanceOf(VersionExecutionResult::class, $versionExecutionResult); diff --git a/tests/Doctrine/Migrations/Tests/VersionTest.php b/tests/Doctrine/Migrations/Tests/VersionTest.php index d6b82133a8..4758dea11e 100644 --- a/tests/Doctrine/Migrations/Tests/VersionTest.php +++ b/tests/Doctrine/Migrations/Tests/VersionTest.php @@ -10,6 +10,7 @@ use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\Configuration\Configuration; use Doctrine\Migrations\Exception\MigrationException; +use Doctrine\Migrations\MigratorConfig; use Doctrine\Migrations\OutputWriter; use Doctrine\Migrations\ParameterFormatter; use Doctrine\Migrations\Provider\SchemaDiffProviderInterface; @@ -117,7 +118,8 @@ public function testShowSqlStatementsParametersWithTypes() : void $version->getMigration()->setType([Connection::PARAM_INT_ARRAY]); - $version->execute(VersionDirection::UP, true); + $version->execute(VersionDirection::UP, (new MigratorConfig()) + ->setDryRun(true)); self::assertContains('([456, 3, 456])', $this->getOutputStreamContent($this->output)); } @@ -226,7 +228,7 @@ public function testWriteSqlFile(string $path, string $direction, array $getSqlR $version->expects($this->once()) ->method('execute') - ->with($direction, true) + ->with($direction) ->willReturn($versionExecutionResult); $queryWriter->method('write') @@ -437,7 +439,7 @@ public function testWriteSqlFileShouldUseStandardCommentMarkerInSql() : void $versionExecutionResult = new VersionExecutionResult(['SHOW DATABASES;']); $migration->method('execute') - ->with($direction, true) + ->with($direction) ->willReturn($versionExecutionResult); $sqlFilesDir = vfsStream::setup('sql_files_dir'); @@ -468,7 +470,8 @@ public function testDryRunCausesSqlToBeOutputViaTheOutputWriter() : void VersionDryRunWithoutParams::class ); - $version->execute(VersionDirection::UP, true); + $version->execute(VersionDirection::UP, (new MigratorConfig()) + ->setDryRun(true)); self::assertCount(3, $messages, 'should have written three messages (header, footer, 1 SQL statement)'); self::assertContains('SELECT 1 WHERE 1', $messages[1]); @@ -490,7 +493,8 @@ public function testDryRunWithQuestionMarkedParamsOutputsParamsWithSqlStatement( VersionDryRunQuestionMarkParams::class ); - $version->execute(VersionDirection::UP, true); + $version->execute(VersionDirection::UP, (new MigratorConfig()) + ->setDryRun(true)); self::assertCount(3, $messages, 'should have written three messages (header, footer, 1 SQL statement)'); self::assertContains('INSERT INTO test VALUES (?, ?)', $messages[1]); @@ -513,7 +517,8 @@ public function testDryRunWithNamedParametersOutputsParamsAndNamesWithSqlStateme VersionDryRunNamedParams::class ); - $version->execute(VersionDirection::UP, true); + $version->execute(VersionDirection::UP, (new MigratorConfig()) + ->setDryRun(true)); self::assertCount(3, $messages, 'should have written three messages (header, footer, 1 SQL statement)'); self::assertContains('INSERT INTO test VALUES (:one, :two)', $messages[1]); @@ -559,7 +564,8 @@ public function testDryRunWithParametersOfComplexTypesCorrectFormatsParameters( $version->getMigration()->setParam($value, $type); - $version->execute(VersionDirection::UP, true); + $version->execute(VersionDirection::UP, (new MigratorConfig()) + ->setDryRun(true)); self::assertCount(3, $messages, 'should have written three messages (header, footer, 1 SQL statement)'); self::assertContains('INSERT INTO test VALUES (?)', $messages[1]); @@ -584,7 +590,8 @@ public function testRunWithInsertNullValue() : void $version->getMigration()->setParam([null], []); - $version->execute(VersionDirection::UP, true); + $version->execute(VersionDirection::UP, (new MigratorConfig()) + ->setDryRun(true)); self::assertCount(3, $messages, 'should have written three messages (header, footer, 1 SQL statement)'); self::assertContains('INSERT INTO test VALUES (?)', $messages[1]);