From 2bf110e99682b9f50cb2f54038b4de79bffcb6e0 Mon Sep 17 00:00:00 2001 From: "Javi H. Gil" Date: Tue, 28 Jul 2026 12:15:38 +0200 Subject: [PATCH] Add MediaVersion unique index and prevent duplications on migrations --- .../entities/MediaVersion.orm.xml | 4 + src/Command/TypesMigrationCommand.php | 8 ++ src/Migrations/Version20260728113500.php | 81 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 src/Migrations/Version20260728113500.php diff --git a/config/doctrine-mapping/entities/MediaVersion.orm.xml b/config/doctrine-mapping/entities/MediaVersion.orm.xml index 583a02b..f344337 100644 --- a/config/doctrine-mapping/entities/MediaVersion.orm.xml +++ b/config/doctrine-mapping/entities/MediaVersion.orm.xml @@ -7,6 +7,10 @@ + + + + diff --git a/src/Command/TypesMigrationCommand.php b/src/Command/TypesMigrationCommand.php index 619d8cc..196bf39 100644 --- a/src/Command/TypesMigrationCommand.php +++ b/src/Command/TypesMigrationCommand.php @@ -9,6 +9,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Throwable; class TypesMigrationCommand extends Command { @@ -45,6 +46,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln(''); } catch (InvalidTypeException $e) { $output->writeln(sprintf('Media "%s" has an error. Type "%s" is invalid', $media->getName(), $media->getType())); + } catch (Throwable $e) { + $output->writeln(sprintf( + 'Media "%s" of type "%s" could not be migrated: %s', + $media->getName(), + $media->getType(), + $e->getMessage(), + )); } } diff --git a/src/Migrations/Version20260728113500.php b/src/Migrations/Version20260728113500.php new file mode 100644 index 0000000..9b3a32e --- /dev/null +++ b/src/Migrations/Version20260728113500.php @@ -0,0 +1,81 @@ +connection->getDatabasePlatform() instanceof PostgreSQLPlatform) { + $this->addSql( + <<<'SQL' + DELETE FROM media_version AS mv_duplicate + USING media_version AS keeper + WHERE keeper.media_id = mv_duplicate.media_id + AND keeper.version = mv_duplicate.version + AND ( + (mv_duplicate.url IS NULL AND keeper.url IS NOT NULL) + OR ( + (mv_duplicate.url IS NULL) = (keeper.url IS NULL) + AND mv_duplicate.id < keeper.id + ) + ) + SQL, + ); + $this->addSql(sprintf( + 'CREATE UNIQUE INDEX %s ON media_version (media_id, version)', + self::UNIQUE_INDEX, + )); + + return; + } + + $this->addSql( + <<<'SQL' + DELETE mv_duplicate + FROM media_version AS mv_duplicate + INNER JOIN media_version AS keeper + ON keeper.media_id = mv_duplicate.media_id + AND keeper.version = mv_duplicate.version + AND ( + (mv_duplicate.url IS NULL AND keeper.url IS NOT NULL) + OR ( + (mv_duplicate.url IS NULL) = (keeper.url IS NULL) + AND mv_duplicate.id < keeper.id + ) + ) + SQL, + ); + $this->addSql(sprintf( + 'CREATE UNIQUE INDEX %s ON media_version (media_id, version)', + self::UNIQUE_INDEX, + )); + } + + public function down(Schema $schema): void + { + if ($this->connection->getDatabasePlatform() instanceof PostgreSQLPlatform) { + $this->addSql(sprintf('DROP INDEX %s', self::UNIQUE_INDEX)); + + return; + } + + $this->addSql(sprintf( + 'DROP INDEX %s ON media_version', + self::UNIQUE_INDEX, + )); + } +}