From 3c70ad3f7dee41d9f5ad34a8f0c3bad186babd36 Mon Sep 17 00:00:00 2001 From: "Jonathan H. Wage" Date: Mon, 8 Apr 2019 17:21:33 +0100 Subject: [PATCH] Use the same Schema object when running migrations in a dry run to fix #806 --- lib/Doctrine/Migrations/Migrator.php | 7 +++++++ .../Migrations/MigratorConfiguration.php | 17 +++++++++++++++++ .../Migrations/Version/ExecutionResult.php | 19 +++++++++++++++++++ lib/Doctrine/Migrations/Version/Executor.php | 15 ++++++++++++++- .../Tests/Functional/FunctionalTest.php | 8 +++++++- .../Tests/Version/ExecutionResultTest.php | 19 +++++++++++++++++++ 6 files changed, 83 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/Migrations/Migrator.php b/lib/Doctrine/Migrations/Migrator.php index 18e2fe18b2..7791ee407b 100644 --- a/lib/Doctrine/Migrations/Migrator.php +++ b/lib/Doctrine/Migrations/Migrator.php @@ -179,6 +179,13 @@ private function executeMigration( foreach ($migrationsToExecute as $version) { $versionExecutionResult = $version->execute($direction, $migratorConfiguration); + // capture the to Schema for the migration so we have the ability to use + // it as the from Schema for the next migration when we are running a dry run + // $toSchema may be null in the case of skipped migrations + if (! $versionExecutionResult->isSkipped()) { + $migratorConfiguration->setFromSchema($versionExecutionResult->getToSchema()); + } + $sql[$version->getVersion()] = $versionExecutionResult->getSql(); $time += $versionExecutionResult->getTime(); } diff --git a/lib/Doctrine/Migrations/MigratorConfiguration.php b/lib/Doctrine/Migrations/MigratorConfiguration.php index bf4f65af78..1c902b316d 100644 --- a/lib/Doctrine/Migrations/MigratorConfiguration.php +++ b/lib/Doctrine/Migrations/MigratorConfiguration.php @@ -4,6 +4,8 @@ namespace Doctrine\Migrations; +use Doctrine\DBAL\Schema\Schema; + /** * The MigratorConfiguration class is responsible for defining the configuration for a migration. * @@ -26,6 +28,9 @@ class MigratorConfiguration /** @var bool */ private $allOrNothing = false; + /** @var Schema|null */ + private $fromSchema; + public function isDryRun() : bool { return $this->dryRun; @@ -73,4 +78,16 @@ public function setAllOrNothing(bool $allOrNothing) : self return $this; } + + public function getFromSchema() : ?Schema + { + return $this->fromSchema; + } + + public function setFromSchema(Schema $fromSchema) : self + { + $this->fromSchema = $fromSchema; + + return $this; + } } diff --git a/lib/Doctrine/Migrations/Version/ExecutionResult.php b/lib/Doctrine/Migrations/Version/ExecutionResult.php index 72c02e022d..ff934722d4 100644 --- a/lib/Doctrine/Migrations/Version/ExecutionResult.php +++ b/lib/Doctrine/Migrations/Version/ExecutionResult.php @@ -4,6 +4,8 @@ namespace Doctrine\Migrations\Version; +use Doctrine\DBAL\Schema\Schema; +use RuntimeException; use Throwable; use function count; @@ -38,6 +40,9 @@ class ExecutionResult /** @var Throwable|null */ private $exception; + /** @var Schema|null */ + private $toSchema; + /** * @param string[] $sql * @param mixed[] $params @@ -152,4 +157,18 @@ public function getException() : ?Throwable { return $this->exception; } + + public function setToSchema(Schema $toSchema) : void + { + $this->toSchema = $toSchema; + } + + public function getToSchema() : Schema + { + if ($this->toSchema === null) { + throw new RuntimeException('Cannot call getToSchema() when toSchema is null.'); + } + + return $this->toSchema; + } } diff --git a/lib/Doctrine/Migrations/Version/Executor.php b/lib/Doctrine/Migrations/Version/Executor.php index aafad0bd13..4b1fee854b 100644 --- a/lib/Doctrine/Migrations/Version/Executor.php +++ b/lib/Doctrine/Migrations/Version/Executor.php @@ -5,6 +5,7 @@ namespace Doctrine\Migrations\Version; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\Configuration\Configuration; use Doctrine\Migrations\Events; @@ -192,7 +193,7 @@ private function executeMigration( $version->setState(State::PRE); - $fromSchema = $this->schemaProvider->createFromSchema(); + $fromSchema = $this->getFromSchema($migratorConfiguration); $migration->{'pre' . ucfirst($direction)}($fromSchema); @@ -206,6 +207,8 @@ private function executeMigration( $toSchema = $this->schemaProvider->createToSchema($fromSchema); + $versionExecutionResult->setToSchema($toSchema); + $migration->$direction($toSchema); foreach ($this->schemaProvider->getSqlDiffToMigrate($fromSchema, $toSchema) as $sql) { @@ -368,4 +371,14 @@ private function outputSqlQuery(int $idx, string $query) : void $params ))); } + + private function getFromSchema(MigratorConfiguration $migratorConfiguration) : Schema + { + // if we're in a dry run, use the from Schema instead of reading the schema from the database + if ($migratorConfiguration->isDryRun() && $migratorConfiguration->getFromSchema() !== null) { + return $migratorConfiguration->getFromSchema(); + } + + return $this->schemaProvider->createFromSchema(); + } } diff --git a/tests/Doctrine/Migrations/Tests/Functional/FunctionalTest.php b/tests/Doctrine/Migrations/Tests/Functional/FunctionalTest.php index 3d4e179592..058b9d6564 100644 --- a/tests/Doctrine/Migrations/Tests/Functional/FunctionalTest.php +++ b/tests/Doctrine/Migrations/Tests/Functional/FunctionalTest.php @@ -200,7 +200,13 @@ public function testDryRunWithTableCreatedWithSchemaInFirstMigration() : void $migrator = $this->createTestMigrator($this->config); $migrator->migrate('2', $migratorConfiguration); - $schema = $this->config->getConnection()->getSchemaManager()->createSchema(); + $schema = $migratorConfiguration->getFromSchema(); + + self::assertInstanceOf(Schema::class, $schema); + self::assertTrue($schema->hasTable('foo')); + + $table = $schema->getTable('foo'); + self::assertTrue($table->hasColumn('bar')); } public function testMigrateDownSeveralSteps() : void diff --git a/tests/Doctrine/Migrations/Tests/Version/ExecutionResultTest.php b/tests/Doctrine/Migrations/Tests/Version/ExecutionResultTest.php index 49f8f63eb1..af66b92494 100644 --- a/tests/Doctrine/Migrations/Tests/Version/ExecutionResultTest.php +++ b/tests/Doctrine/Migrations/Tests/Version/ExecutionResultTest.php @@ -4,9 +4,11 @@ namespace Doctrine\Migrations\Tests\Version; +use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\Version\ExecutionResult; use InvalidArgumentException; use PHPUnit\Framework\TestCase; +use RuntimeException; class ExecutionResultTest extends TestCase { @@ -95,6 +97,23 @@ public function testException() : void self::assertSame($exception, $this->versionExecutionResult->getException()); } + public function testToSchema() : void + { + $toSchema = $this->createMock(Schema::class); + + $this->versionExecutionResult->setToSchema($toSchema); + + self::assertSame($toSchema, $this->versionExecutionResult->getToSchema()); + } + + public function testToSchemaThrowsRuntimExceptionWhenToSchemaIsNull() : void + { + self::expectException(RuntimeException::class); + self::expectExceptionMessage('Cannot call getToSchema() when toSchema is null.'); + + $this->versionExecutionResult->getToSchema(); + } + protected function setUp() : void { $this->versionExecutionResult = new ExecutionResult(