fix(db) : ajoute les FK CASCADE manquantes documents.composantId et machine_component_links.composantId
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.
This commit is contained in:
106
migrations/Version20260506140000_FixComposantCascadeFKs.php
Normal file
106
migrations/Version20260506140000_FixComposantCascadeFKs.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user