Files
Inventory/migrations/Version20260506140000_FixComposantCascadeFKs.php
Matthieu 3ff89d43ed 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.
2026-05-06 16:34:26 +02:00

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');
}
}