diff --git a/composer.json b/composer.json index 143b30c7..e97f5e7e 100644 --- a/composer.json +++ b/composer.json @@ -50,6 +50,7 @@ }, "require-dev": { "doctrine/doctrine-bundle": "^2.5", + "doctrine/doctrine-migrations-bundle": "^3.2", "ergebnis/composer-normalize": "^2.0.1", "symfony/browser-kit": "^5.4 || ^6.0", "symfony/dependency-injection": "^5.4 || ^6.0", diff --git a/src/Migration/IdToUuidMigration.php b/src/Migration/IdToUuidMigration.php index 74e932bb..f7b75de0 100644 --- a/src/Migration/IdToUuidMigration.php +++ b/src/Migration/IdToUuidMigration.php @@ -337,7 +337,10 @@ private function deletePreviousFKs(): void foreach ($this->foreignKeys as $foreignKey) { $table = $schema->getTable($foreignKey['table']); - $table->removeForeignKey($foreignKey['name']); + + if ($table->hasForeignKey($foreignKey['name'])) { + $table->removeForeignKey($foreignKey['name']); + } } $this->updateSchema($schema); diff --git a/tests/Bridge/Symfony/App/AppKernel.php b/tests/Bridge/Symfony/App/AppKernel.php index 48892313..bad16917 100644 --- a/tests/Bridge/Symfony/App/AppKernel.php +++ b/tests/Bridge/Symfony/App/AppKernel.php @@ -12,6 +12,7 @@ namespace Nucleos\Doctrine\Tests\Bridge\Symfony\App; use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; +use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle; use Nucleos\Doctrine\Bridge\Symfony\Bundle\NucleosDoctrineBundle; use Nucleos\Doctrine\Tests\Bridge\Symfony\App\Controller\SampleTestController; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; @@ -34,6 +35,7 @@ public function registerBundles(): iterable yield new FrameworkBundle(); yield new DoctrineBundle(); yield new NucleosDoctrineBundle(); + yield new DoctrineMigrationsBundle(); } public function getCacheDir(): string diff --git a/tests/Bridge/Symfony/App/Migrations/Version_1_0_0.php b/tests/Bridge/Symfony/App/Migrations/Version_1_0_0.php new file mode 100644 index 00000000..ffd6a76c --- /dev/null +++ b/tests/Bridge/Symfony/App/Migrations/Version_1_0_0.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nucleos\Doctrine\Tests\Bridge\Symfony\App\Migrations; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Types\Types; +use Doctrine\Migrations\AbstractMigration; + +final class Version_1_0_0 extends AbstractMigration +{ + public function getDescription(): string + { + return 'Initial structure'; + } + + public function up(Schema $schema): void + { + $this->createMeal($schema); + $this->createMealCategory($schema); + $this->createMealAttribute($schema); + $this->createIngredient($schema); + $this->createCategory($schema); + $this->createMenu($schema); + $this->createMealPage($schema); + $this->createPageCategory($schema); + $this->createAttribute($schema); + } + + public function down(Schema $schema): void + { + $this->throwIrreversibleMigrationException(); + } + + private function createMeal(Schema $schema): void + { + $table = $schema->createTable('acme__meal'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + ]); + $table->addColumn('name', Types::STRING, [ + 'length' => 50, + ]); + $table->setPrimaryKey(['id']); + } + + private function createMealCategory(Schema $schema): void + { + $table = $schema->createTable('acme__meal_category'); + $table->addColumn('meal_id', Types::INTEGER); + $table->addColumn('category_id', Types::INTEGER); + $table->addIndex(['meal_id']); + $table->addIndex(['category_id']); + $table->addForeignKeyConstraint('acme__meal', ['meal_id'], ['id']); + $table->addForeignKeyConstraint('acme__category', ['category_id'], ['id']); + $table->setPrimaryKey(['meal_id', 'category_id']); + } + + private function createMealAttribute(Schema $schema): void + { + $table = $schema->createTable('acme__meal_attribute'); + $table->addColumn('attribute_id', Types::INTEGER); + $table->addColumn('meal_id', Types::INTEGER); + $table->addIndex(['attribute_id']); + $table->addIndex(['meal_id']); + $table->addForeignKeyConstraint('acme__attribute', ['attribute_id'], ['id']); + $table->addForeignKeyConstraint('acme__meal', ['meal_id'], ['id']); + $table->setPrimaryKey(['attribute_id', 'meal_id']); + } + + private function createIngredient(Schema $schema): void + { + $table = $schema->createTable('acme__ingredient'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + ]); + $table->addColumn('meal_id', Types::INTEGER, [ + 'notnull' => false, + ]); + $table->addColumn('name', Types::STRING, [ + 'length' => 50, + ]); + $table->addIndex(['meal_id']); + $table->addForeignKeyConstraint('acme__meal', ['meal_id'], ['id']); + $table->setPrimaryKey(['id']); + } + + private function createCategory(Schema $schema): void + { + $table = $schema->createTable('acme__category'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + ]); + $table->addColumn('name', Types::STRING, [ + 'length' => 50, + ]); + $table->setPrimaryKey(['id']); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + private function createMenu(Schema $schema): void + { + $table = $schema->createTable('acme__menu'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + ]); + $table->addColumn('name', Types::STRING, [ + 'length' => 50, + ]); + $table->setPrimaryKey(['id']); + } + + private function createMealPage(Schema $schema): void + { + $table = $schema->createTable('acme__page'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + ]); + $table->addColumn('menu_id', Types::INTEGER, [ + 'notnull' => false, + ]); + $table->addColumn('name', Types::STRING, [ + 'length' => 50, + ]); + $table->addIndex(['menu_id']); + $table->addForeignKeyConstraint('acme__menu', ['menu_id'], ['id']); + $table->setPrimaryKey(['id']); + } + + private function createPageCategory(Schema $schema): void + { + $table = $schema->createTable('acme__page_category'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + ]); + $table->addColumn('page_id', Types::INTEGER); + $table->addColumn('category_id', Types::INTEGER, [ + 'notnull' => false, + ]); + $table->addColumn('description', Types::TEXT, [ + 'notnull' => false, + ]); + $table->addIndex(['page_id']); + $table->addIndex(['category_id']); + $table->addForeignKeyConstraint('acme__page', ['page_id'], ['id']); + $table->addForeignKeyConstraint('acme__category', ['category_id'], ['id']); + $table->setPrimaryKey(['id']); + } + + private function createAttribute(Schema $schema): void + { + $table = $schema->createTable('acme__attribute'); + $table->addColumn('id', Types::INTEGER, [ + 'autoincrement' => true, + ]); + $table->addColumn('name', Types::STRING, [ + 'length' => 50, + ]); + $table->setPrimaryKey(['id']); + } +} diff --git a/tests/Bridge/Symfony/App/Migrations/Version_2_0_0.php b/tests/Bridge/Symfony/App/Migrations/Version_2_0_0.php new file mode 100644 index 00000000..5fffcdff --- /dev/null +++ b/tests/Bridge/Symfony/App/Migrations/Version_2_0_0.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nucleos\Doctrine\Tests\Bridge\Symfony\App\Migrations; + +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; +use Nucleos\Doctrine\Migration\IdToUuidMigration; +use Psr\Log\LoggerInterface; + +final class Version_2_0_0 extends AbstractMigration +{ + private IdToUuidMigration $idToUuidMigration; + + public function __construct(Connection $connection, LoggerInterface $logger) + { + parent::__construct($connection, $logger); + + $this->idToUuidMigration = new IdToUuidMigration($this->connection, $logger); + } + + public function getDescription(): string + { + return 'UUID migration'; + } + + public function up(Schema $schema): void + { + $this->idToUuidMigration->migrate('acme__meal'); + $this->idToUuidMigration->migrate('acme__ingredient'); + $this->idToUuidMigration->migrate('acme__attribute'); + $this->idToUuidMigration->migrate('acme__category'); + $this->idToUuidMigration->migrate('acme__page'); + $this->idToUuidMigration->migrate('acme__menu'); + $this->idToUuidMigration->migrate('acme__page_category'); + } +} diff --git a/tests/Bridge/Symfony/App/config/config.php b/tests/Bridge/Symfony/App/config/config.php index 2aadb99a..810af0a3 100644 --- a/tests/Bridge/Symfony/App/config/config.php +++ b/tests/Bridge/Symfony/App/config/config.php @@ -18,7 +18,13 @@ $containerConfigurator->extension('framework', ['test' => true]); - $containerConfigurator->extension('doctrine', ['dbal' => ['url' => 'sqlite:///:memory:', 'logging' => false]]); + $containerConfigurator->extension('doctrine', ['dbal' => ['url' => 'sqlite:///%kernel.cache_dir%/data.db', 'logging' => false]]); + + $containerConfigurator->extension('doctrine_migrations', [ + 'migrations_paths' => [ + 'Nucleos\Doctrine\Tests\Bridge\Symfony\App\Migrations' => \dirname(__DIR__).'/Migrations', + ], + ]); $services = $containerConfigurator->services(); diff --git a/tests/Migration/MigrationTest.php b/tests/Migration/MigrationTest.php new file mode 100644 index 00000000..4534f723 --- /dev/null +++ b/tests/Migration/MigrationTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nucleos\Doctrine\Tests\Migration; + +use Nucleos\Doctrine\Tests\Bridge\Symfony\App\AppKernel; +use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; + +/** + * @group integration + */ +final class MigrationTest extends KernelTestCase +{ + public function testMigrateUp(): void + { + $kernel = self::createKernel(); + $kernel->boot(); + + $application = new Application($kernel); + $application->setAutoExit(false); + + $this->runCommand($application, 'doctrine:database:drop', [ + '--force' => true, + '--quiet' => true, + ]); + $this->runCommand($application, 'doctrine:database:create', [ + '--quiet' => true, + ]); + $this->runCommand($application, 'doctrine:migrations:migrate', [ + '--no-interaction' => true, + '--allow-no-migration' => true, + '-v' => true, + ]); + } + + protected static function getKernelClass(): string + { + return AppKernel::class; + } + + /** + * @param array $arguments + */ + private function runCommand(Application $application, string $command, array $arguments): void + { + $arguments['command'] =$command; + + $status = $application->run(new ArrayInput($arguments)); + + static::assertSame(Command::SUCCESS, $status, sprintf('Command "%s" failed', $command)); + } +}