diff --git a/composer.json b/composer.json index ee32768..3351088 100644 --- a/composer.json +++ b/composer.json @@ -11,11 +11,11 @@ ], "require": { "php": ">=7.2", - "spiral/core": "^2.7", - "spiral/database": "^2.7", - "spiral/files": "^2.7", - "spiral/tokenizer": "^2.7", - "spiral/reactor": "^2.7" + "spiral/core": "^2.8", + "spiral/database": "^2.9", + "spiral/files": "^2.8", + "spiral/tokenizer": "^2.8", + "spiral/reactor": "^2.8" }, "autoload": { "psr-4": { diff --git a/src/Migrator.php b/src/Migrator.php index 8cd14d6..1907e0d 100644 --- a/src/Migrator.php +++ b/src/Migrator.php @@ -12,6 +12,7 @@ namespace Spiral\Migrations; use Spiral\Database\Database; +use Spiral\Database\DatabaseInterface; use Spiral\Database\DatabaseManager; use Spiral\Database\Table; use Spiral\Migrations\Config\MigrationConfig; @@ -112,7 +113,7 @@ private function getDatabases(): array foreach ($this->repository->getMigrations() as $migration) { $database = $this->dbal->database($migration->getDatabase()); - if (! isset($result[$database->getName()])) { + if (!$this->isReadonly($database) && !isset($result[$database->getName()])) { $result[$database->getName()] = $database; } } @@ -120,6 +121,18 @@ private function getDatabases(): array return $result; } + /** + * Returns {@see true} in case that connection is readonly + * or {@see false} instead. + * + * @param DatabaseInterface $db + * @return bool + */ + private function isReadonly(DatabaseInterface $db): bool + { + return $db->getDriver()->isReadonly(); + } + /** * Create migration table inside given database * diff --git a/tests/Migrations/MigrationsDatabaseTest.php b/tests/Migrations/MigrationsDatabaseTest.php new file mode 100644 index 0000000..b815f9e --- /dev/null +++ b/tests/Migrations/MigrationsDatabaseTest.php @@ -0,0 +1,107 @@ +generateMigration('20200909.024119_333_333_migration_1.php', 'A3'); + + // Standard behavior + $this->assertFalse($this->migrator(false)->isConfigured()); + + // Ignore created migrations in case the connection is readonly + $this->assertTrue($this->migrator(true)->isConfigured()); + } + + private function generateMigration(string $file, string $class): string + { + $out = __DIR__ . '/../files/' . $file; + + file_put_contents($out, sprintf(file_get_contents(__DIR__ . '/../files/migration.stub'), $class)); + + return $out; + } + + /** + * @param bool $readonly + * @return Migrator + */ + private function migrator(bool $readonly): Migrator + { + $config = new MigrationConfig([ + 'directory' => __DIR__ . '/../files/', + 'table' => 'migrations', + 'safe' => true, + ]); + + return new Migrator( + $config, + $this->dbal($readonly), + new FileRepository($config, new Container()) + ); + } + + /** + * @param bool $readonly + * @return DatabaseManager + */ + private function dbal(bool $readonly): DatabaseManager + { + return new DatabaseManager( + new DatabaseConfig([ + 'default' => 'default', + 'databases' => [ + 'default' => ['driver' => 'test'], + ], + 'drivers' => [ + 'test' => [ + 'driver' => SQLiteDriver::class, + 'options' => [ + 'connection' => 'sqlite::memory:', + 'readonly' => $readonly, + 'username' => 'sqlite', + 'password' => '', + ], + ], + ], + ]) + ); + } + + /** + * @return void + */ + public function tearDown(): void + { + $files = new Files(); + foreach ($files->getFiles(__DIR__ . '/../files/', '*.php') as $file) { + $files->delete($file); + clearstatcache(true, $file); + } + + parent::tearDown(); + } +}