'pdo_pgsql', 'host' => 'localhost', 'port' => 5432, 'dbname' => 'inventory', 'user' => 'ferme_user', 'password' => 'fermerecette', ]); echo "--- Audit logs with customField deletions (to:null) ---\n"; $rows = $conn->fetchAllAssociative(" SELECT al.entityid, al.entitytype, al.diff::text as diff, al.createdat FROM audit_logs al WHERE al.diff::text LIKE '%customField%' AND al.diff::text LIKE '%\"to\":null%' ORDER BY al.createdat DESC LIMIT 20 "); echo sprintf("Found %d entries\n\n", count($rows)); foreach ($rows as $r) { echo sprintf("[%s] %s %s: %s\n", $r['createdat'], $r['entitytype'], $r['entityid'], substr($r['diff'], 0, 120)); } echo "\n--- Orphaned CFValues (pointing to CFs with no ModelType) ---\n"; $rows = $conn->fetchAllAssociative(" SELECT COUNT(*) as cnt, CASE WHEN cfv.pieceid IS NOT NULL THEN 'piece' WHEN cfv.composantid IS NOT NULL THEN 'composant' WHEN cfv.productid IS NOT NULL THEN 'product' ELSE 'unknown' END as entity_type FROM custom_field_values cfv JOIN custom_fields cf ON cf.id = cfv.customfieldid WHERE cf.typecomposantid IS NULL AND cf.typepieceid IS NULL AND cf.typeproductid IS NULL GROUP BY entity_type "); foreach ($rows as $r) { echo sprintf(" %s: %d orphaned values\n", $r['entity_type'], $r['cnt']); }