fix(custom-fields) : prevent data loss on ModelType save + restoration scripts
Backend: match existing CustomField by name as fallback when ID is not provided, preventing deletion and recreation of field definitions (which cascade-deletes values). Includes restoration/migration scripts for prod: - restore-custom-field-values.php: restores piece values from audit logs - migrate-orphaned-custom-fields.php: migrates values from orphaned CFs - fix-prod-all.php: combined fix (migrate + restore + cleanup) - fix-prod-recreate-and-migrate.php: full fix (recreate missing CFs + migrate + restore) - check-prod-*.php: diagnostic scripts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -192,10 +192,12 @@ class SkeletonStructureService
|
||||
['orderIndex' => 'ASC']
|
||||
);
|
||||
|
||||
// Index existing by ID for matching
|
||||
$existingById = [];
|
||||
// Index existing by ID and by name for matching
|
||||
$existingById = [];
|
||||
$existingByName = [];
|
||||
foreach ($existingFields as $cf) {
|
||||
$existingById[$cf->getId()] = $cf;
|
||||
$existingById[$cf->getId()] = $cf;
|
||||
$existingByName[$cf->getName()] = $cf;
|
||||
}
|
||||
|
||||
$processedIds = [];
|
||||
@@ -204,11 +206,13 @@ class SkeletonStructureService
|
||||
// Normalize both formats to a common shape
|
||||
$normalized = $this->normalizeCustomFieldData($fieldData, $i);
|
||||
|
||||
// Try to match an existing field by ID
|
||||
// Try to match an existing field by ID first, then by name as fallback
|
||||
$existingField = null;
|
||||
$fieldId = $fieldData['customFieldId'] ?? $fieldData['id'] ?? null;
|
||||
if ($fieldId && isset($existingById[$fieldId])) {
|
||||
$existingField = $existingById[$fieldId];
|
||||
} elseif (isset($existingByName[$normalized['name']]) && !isset($processedIds[$existingByName[$normalized['name']]->getId()])) {
|
||||
$existingField = $existingByName[$normalized['name']];
|
||||
}
|
||||
|
||||
if ($existingField) {
|
||||
|
||||
Reference in New Issue
Block a user