Les entités Doctrine déclaraient déjà onDelete: CASCADE pour ces deux relations, mais les contraintes correspondantes étaient absentes en base. Conséquence : la suppression d'un composant pouvait laisser des documents ou des links machine orphelins. La migration nettoie les orphelins existants (avec trace dans audit_logs) puis ajoute les deux FK.
107 lines
4.0 KiB
PHP
107 lines
4.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace DoctrineMigrations;
|
|
|
|
use Doctrine\DBAL\Schema\Schema;
|
|
use Doctrine\Migrations\AbstractMigration;
|
|
|
|
final class Version20260506140000_FixComposantCascadeFKs extends AbstractMigration
|
|
{
|
|
public function getDescription(): string
|
|
{
|
|
return 'Add missing CASCADE FKs documents.composantid and machine_component_links.composantid; cleanup pre-existing orphan rows';
|
|
}
|
|
|
|
public function up(Schema $schema): void
|
|
{
|
|
// 1. Trace des suppressions à venir dans audit_logs (actor = NULL = "system").
|
|
// On copie un snapshot minimal avant DELETE pour cohérence avec les autres "delete".
|
|
$this->addSql(<<<'SQL'
|
|
INSERT INTO audit_logs (id, entitytype, entityid, action, snapshot, actorprofileid, createdat)
|
|
SELECT
|
|
'cl' || substring(md5(random()::text || clock_timestamp()::text), 1, 24),
|
|
'document',
|
|
d.id,
|
|
'delete',
|
|
json_build_object(
|
|
'id', d.id,
|
|
'name', d.name,
|
|
'filename', d.filename,
|
|
'composantId', d.composantid,
|
|
'note', 'Cleaned by FK cascade fix migration (Version20260506140000) - referenced composant no longer existed'
|
|
),
|
|
NULL,
|
|
NOW()
|
|
FROM documents d
|
|
WHERE d.composantid IS NOT NULL
|
|
AND d.composantid NOT IN (SELECT id FROM composants)
|
|
SQL);
|
|
|
|
$this->addSql(<<<'SQL'
|
|
INSERT INTO audit_logs (id, entitytype, entityid, action, snapshot, actorprofileid, createdat)
|
|
SELECT
|
|
'cl' || substring(md5(random()::text || clock_timestamp()::text), 1, 24),
|
|
'machine_component_link',
|
|
l.id,
|
|
'delete',
|
|
json_build_object(
|
|
'id', l.id,
|
|
'machineId', l.machineid,
|
|
'composantId', l.composantid,
|
|
'note', 'Cleaned by FK cascade fix migration (Version20260506140000) - referenced composant no longer existed'
|
|
),
|
|
NULL,
|
|
NOW()
|
|
FROM machine_component_links l
|
|
WHERE l.composantid IS NOT NULL
|
|
AND l.composantid NOT IN (SELECT id FROM composants)
|
|
SQL);
|
|
|
|
// 2. Nettoyage des orphelins.
|
|
$this->addSql(<<<'SQL'
|
|
DELETE FROM documents
|
|
WHERE composantid IS NOT NULL
|
|
AND composantid NOT IN (SELECT id FROM composants)
|
|
SQL);
|
|
|
|
$this->addSql(<<<'SQL'
|
|
DELETE FROM machine_component_links
|
|
WHERE composantid IS NOT NULL
|
|
AND composantid NOT IN (SELECT id FROM composants)
|
|
SQL);
|
|
|
|
// 3. Ajout idempotent des 2 FK manquantes (alignement avec les entités Doctrine).
|
|
$this->addSql(<<<'SQL'
|
|
DO $$ BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.table_constraints
|
|
WHERE constraint_name = 'fk_documents_composant' AND table_name = 'documents'
|
|
) THEN
|
|
ALTER TABLE documents ADD CONSTRAINT fk_documents_composant
|
|
FOREIGN KEY (composantid) REFERENCES composants(id) ON DELETE CASCADE;
|
|
END IF;
|
|
END $$;
|
|
SQL);
|
|
|
|
$this->addSql(<<<'SQL'
|
|
DO $$ BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.table_constraints
|
|
WHERE constraint_name = 'fk_mcl_composant' AND table_name = 'machine_component_links'
|
|
) THEN
|
|
ALTER TABLE machine_component_links ADD CONSTRAINT fk_mcl_composant
|
|
FOREIGN KEY (composantid) REFERENCES composants(id) ON DELETE CASCADE;
|
|
END IF;
|
|
END $$;
|
|
SQL);
|
|
}
|
|
|
|
public function down(Schema $schema): void
|
|
{
|
|
$this->addSql('ALTER TABLE documents DROP CONSTRAINT IF EXISTS fk_documents_composant');
|
|
$this->addSql('ALTER TABLE machine_component_links DROP CONSTRAINT IF EXISTS fk_mcl_composant');
|
|
}
|
|
}
|