From 18b667d24b0c1fd616007457f27c94e939332464 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 23 Jul 2026 08:53:44 -0400 Subject: [PATCH] =?UTF-8?q?CON-333=20=E2=80=94=20Implement=20soft=20synchr?= =?UTF-8?q?onization=20for=20static=20tables,=20allowing=20for=20insertion?= =?UTF-8?q?=20of=20missing=20rows=20and=20updates=20to=20existing=20record?= =?UTF-8?q?s=20without=20deletion.=20Introduce=20new=20functions=20for=20h?= =?UTF-8?q?andling=20insert=20columns=20and=20info=20row=20checks.=20Updat?= =?UTF-8?q?e=20dashboard=20to=20reflect=20non-destructive=20actions=20and?= =?UTF-8?q?=20improve=20user=20messaging=20for=20clarity.=20Increment=20ve?= =?UTF-8?q?rsion=20code.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/inc_fx_static_sync.php | 458 ++++++++++++++++++++++++------ php/inc_fx_static_sync_config.php | 14 +- php/sync_static_db.php | 157 ++++++---- 3 files changed, 488 insertions(+), 141 deletions(-) diff --git a/php/inc_fx_static_sync.php b/php/inc_fx_static_sync.php index 87e3877..5fe1824 100644 --- a/php/inc_fx_static_sync.php +++ b/php/inc_fx_static_sync.php @@ -521,24 +521,64 @@ function fxStaticSyncGetTableEngine($objDb, $strTable) { return !empty($row['ENGINE']) ? strtoupper($row['ENGINE']) : ''; } -function fxStaticSyncCopyTable($objSource, $objTarget, $strTable, array $tabDef = null) { +/** + * CON-333 — Colonnes à écrire en INSERT soft (hors PK / timestamps ignore_cols). + * Les clés métier restent incluses (elles ne sont pas dans ignore_cols). + */ +function fxStaticSyncInsertColumns(array $tabSchema, array $tabDef) { + $tabIgnore = isset($tabDef['ignore_cols']) ? $tabDef['ignore_cols'] : array(); + $tabCols = array(); + + foreach ($tabSchema['copy_cols'] as $strCol) { + if (!in_array($strCol, $tabIgnore, true)) { + $tabCols[] = $strCol; + } + } + + return $tabCols; +} + +/** CON-333 — Ligne info « poubelle » (texte = clé, créé à chaud par afficheTexte). */ +function fxStaticSyncInfoRowIsPoubelle(array $row) { + if (!isset($row['info_clef']) || !isset($row['info_texte'])) { + return false; + } + + return (string)$row['info_texte'] === (string)$row['info_clef']; +} + +/** CON-333 — Source a un vrai libellé (pas poubelle / pas vide). */ +function fxStaticSyncInfoRowHasRealTexte(array $row) { + if (!isset($row['info_clef']) || !isset($row['info_texte'])) { + return false; + } + $strTexte = trim((string)$row['info_texte']); + if ($strTexte === '') { + return false; + } + + return $strTexte !== (string)$row['info_clef']; +} + +/** + * CON-333 — Prépare le schéma + jeux de lignes source/cible pour écriture soft. + * Aucune écriture. Retourne ok=false si structure / connexion invalide. + */ +function fxStaticSyncPrepareSoftWrite($objSource, $objTarget, $strTable, array $tabDef = null) { if (!$objSource || !$objTarget) { return array('ok' => false, 'message' => 'Connexion BD invalide.'); } - + if (!$tabDef) { + return array('ok' => false, 'message' => 'Table non configurée.'); + } if (!fxStaticSyncTableExists($objSource, $strTable)) { return array('ok' => false, 'message' => 'Table absente dans la source.'); } - if (!fxStaticSyncTableExists($objTarget, $strTable)) { return array('ok' => false, 'message' => 'Table absente dans la cible — exécuter le DDL d\'abord.'); } - if (!$tabDef) { - return array('ok' => false, 'message' => 'Table non configurée.'); - } - - $tabIgnore = ($tabDef && isset($tabDef['ignore_cols'])) ? $tabDef['ignore_cols'] : array(); + $tabIgnore = isset($tabDef['ignore_cols']) ? $tabDef['ignore_cols'] : array(); $tabSchema = fxStaticSyncResolveCompareColumns($objSource, $objTarget, $strTable, $tabIgnore); if (!fxStaticSyncSchemasAligned($tabSchema)) { @@ -546,106 +586,113 @@ function fxStaticSyncCopyTable($objSource, $objTarget, $strTable, array $tabDef 'ok' => false, 'message' => 'Structures non alignées — ' . fxStaticSyncFormatSchemaDiff($tabSchema) - . '. Aligner les structures (Navicat) avant toute sync. Aucune donnée modifiée.', + . '. Aligner les structures (Navicat) avant. Aucune donnée modifiée.', ); } - $tabCopyCols = $tabSchema['copy_cols']; + $tabSourceData = fxStaticSyncLoadKeyedRows($objSource, $tabDef, $tabSchema['compare_cols']); + $tabTargetData = fxStaticSyncLoadKeyedRows($objTarget, $tabDef, $tabSchema['compare_cols']); - if (count($tabCopyCols) === 0) { - $tabFetchCheck = fxStaticSyncFetchRowsByKey($objSource, $tabDef); - if (count($tabFetchCheck['rows']) > 0) { - return array( - 'ok' => false, - 'message' => 'Aucune colonne commune entre source et cible.', - ); + if (!empty($tabSourceData['error']) && $tabSourceData['error'] !== null) { + return array('ok' => false, 'message' => 'Lecture source : ' . $tabSourceData['error']); + } + if (!empty($tabTargetData['error']) && $tabTargetData['error'] !== null + && $tabTargetData['error'] !== 'missing_table') { + return array('ok' => false, 'message' => 'Lecture cible : ' . $tabTargetData['error']); + } + + return array( + 'ok' => true, + 'schema' => $tabSchema, + 'source_rows' => $tabSourceData['rows'], + 'target_rows' => $tabTargetData['rows'], + 'source_dupes' => isset($tabSourceData['duplicate_count']) ? (int)$tabSourceData['duplicate_count'] : 0, + ); +} + +/** + * CON-333 — INSERT uniquement les clés absentes en cible. Jamais de DELETE. + * Ne touche pas aux lignes déjà présentes (même poubelles — voir repair). + */ +function fxStaticSyncApplyMissingRows($objSource, $objTarget, $strTable, array $tabDef = null) { + $tabPrep = fxStaticSyncPrepareSoftWrite($objSource, $objTarget, $strTable, $tabDef); + if (empty($tabPrep['ok'])) { + return $tabPrep; + } + + $tabInsertCols = fxStaticSyncInsertColumns($tabPrep['schema'], $tabDef); + if (count($tabInsertCols) === 0) { + return array('ok' => false, 'message' => 'Aucune colonne insérable (hors ignore_cols).'); + } + + $tabMissingRows = array(); + foreach ($tabPrep['source_rows'] as $strKey => $tabEntry) { + if (!isset($tabPrep['target_rows'][$strKey])) { + $tabMissingRows[$strKey] = $tabEntry['row']; } } - $tabFetch = fxStaticSyncFetchRowsByKey($objSource, $tabDef); - $tabRowsToCopy = $tabFetch['rows']; - $intDupes = $tabFetch['duplicate_count']; + $intMissing = count($tabMissingRows); + if ($intMissing === 0) { + return array( + 'ok' => true, + 'message' => 'Aucun manquant à ajouter.', + 'inserted' => 0, + 'skipped_extra' => count($tabPrep['target_rows']) - count(array_intersect_key($tabPrep['target_rows'], $tabPrep['source_rows'])), + ); + } - // Préparer les INSERT avant toute écriture destructive (évite une table vide si échec). + $strColList = '`' . implode('`,`', $tabInsertCols) . '`'; + $intBatchSize = 50; + $tabBatch = array(); $tabInsertBatches = array(); - $intCopied = count($tabRowsToCopy); - if (count($tabCopyCols) > 0 && count($tabRowsToCopy) > 0) { - $strColList = '`' . implode('`,`', $tabCopyCols) . '`'; - $intBatchSize = 50; - $tabBatch = array(); - - foreach ($tabRowsToCopy as $row) { - if (!is_array($row)) { + foreach ($tabMissingRows as $row) { + if (!is_array($row)) { + continue; + } + $tabVals = array(); + foreach ($tabInsertCols as $strCol) { + if ($strTable === 'info' && $strCol === 'info_creation') { + $tabVals[] = 'NOW()'; continue; } - - $tabVals = array(); - foreach ($tabCopyCols as $strCol) { - if (!array_key_exists($strCol, $row) || $row[$strCol] === null) { - $tabVals[] = 'NULL'; - } else { - $tabVals[] = "'" . $objTarget->fxEscape($row[$strCol]) . "'"; - } - } - $tabBatch[] = '(' . implode(',', $tabVals) . ')'; - - if (count($tabBatch) >= $intBatchSize) { - $tabInsertBatches[] = 'INSERT INTO `' . $strTable . '` (' . $strColList . ') VALUES ' . implode(',', $tabBatch); - $tabBatch = array(); + if (!array_key_exists($strCol, $row) || $row[$strCol] === null) { + $tabVals[] = 'NULL'; + } else { + $tabVals[] = "'" . $objTarget->fxEscape($row[$strCol]) . "'"; } } - - if (count($tabBatch) > 0) { + $tabBatch[] = '(' . implode(',', $tabVals) . ')'; + if (count($tabBatch) >= $intBatchSize) { $tabInsertBatches[] = 'INSERT INTO `' . $strTable . '` (' . $strColList . ') VALUES ' . implode(',', $tabBatch); + $tabBatch = array(); } } + if (count($tabBatch) > 0) { + $tabInsertBatches[] = 'INSERT INTO `' . $strTable . '` (' . $strColList . ') VALUES ' . implode(',', $tabBatch); + } $blnTransactional = (fxStaticSyncGetTableEngine($objTarget, $strTable) === 'INNODB'); - $blnFkDisabled = false; - - $tabFkOff = fxStaticSyncExecQuery($objTarget, 'SET FOREIGN_KEY_CHECKS=0'); - if (!$tabFkOff['ok']) { - return array('ok' => false, 'message' => 'FK checks : ' . $tabFkOff['error']); - } - $blnFkDisabled = true; if ($blnTransactional) { $tabTx = fxStaticSyncExecQuery($objTarget, 'START TRANSACTION'); if (!$tabTx['ok']) { - fxStaticSyncExecQuery($objTarget, 'SET FOREIGN_KEY_CHECKS=1'); return array('ok' => false, 'message' => 'Transaction : ' . $tabTx['error']); } } - // DELETE plutôt que TRUNCATE : compatible FK (InnoDB) avec checks désactivés. - $tabDelete = fxStaticSyncExecQuery($objTarget, 'DELETE FROM `' . $strTable . '`'); - if (!$tabDelete['ok']) { - if ($blnTransactional) { - fxStaticSyncExecQuery($objTarget, 'ROLLBACK'); - } - if ($blnFkDisabled) { - fxStaticSyncExecQuery($objTarget, 'SET FOREIGN_KEY_CHECKS=1'); - } - return array('ok' => false, 'message' => 'Vidage table : ' . $tabDelete['error']); - } - foreach ($tabInsertBatches as $strSql) { $tabInsert = fxStaticSyncExecQuery($objTarget, $strSql); if (!$tabInsert['ok']) { if ($blnTransactional) { fxStaticSyncExecQuery($objTarget, 'ROLLBACK'); - } else { - return array( - 'ok' => false, - 'message' => 'Insertion : ' . $tabInsert['error'] - . ' — la table cible peut être vide (MyISAM, pas de rollback).', - ); } - if ($blnFkDisabled) { - fxStaticSyncExecQuery($objTarget, 'SET FOREIGN_KEY_CHECKS=1'); - } - return array('ok' => false, 'message' => 'Insertion : ' . $tabInsert['error'] . ' (rollback effectué).'); + return array( + 'ok' => false, + 'message' => 'Insertion manquants : ' . $tabInsert['error'] + . ($blnTransactional ? ' (rollback — aucune ligne ajoutée).' : ''), + ); } } @@ -653,26 +700,217 @@ function fxStaticSyncCopyTable($objSource, $objTarget, $strTable, array $tabDef $tabCommit = fxStaticSyncExecQuery($objTarget, 'COMMIT'); if (!$tabCommit['ok']) { fxStaticSyncExecQuery($objTarget, 'ROLLBACK'); - if ($blnFkDisabled) { - fxStaticSyncExecQuery($objTarget, 'SET FOREIGN_KEY_CHECKS=1'); - } return array('ok' => false, 'message' => 'Commit : ' . $tabCommit['error']); } } - if ($blnFkDisabled) { - fxStaticSyncExecQuery($objTarget, 'SET FOREIGN_KEY_CHECKS=1'); - } - - $strMessage = $intCopied . ' ligne(s) copiée(s).'; - if ($intDupes > 0) { - $strMessage .= ' (' . $intDupes . ' doublon(s) ignoré(s) en source — même clé métier.)'; + $strMessage = $intMissing . ' ligne(s) ajoutée(s) (INSERT manquants uniquement, aucun DELETE).'; + if (!empty($tabPrep['source_dupes'])) { + $strMessage .= ' (' . (int)$tabPrep['source_dupes'] . ' doublon(s) clé en source ignoré(s).)'; } return array( 'ok' => true, 'message' => $strMessage, - 'rows' => $intCopied, + 'inserted' => $intMissing, + ); +} + +/** + * CON-333 — WHERE métier (toutes les colonnes keys). + */ +function fxStaticSyncSqlWhereBusinessKeys($objDb, array $row, array $tabKeys) { + $tabParts = array(); + foreach ($tabKeys as $strCol) { + if (!array_key_exists($strCol, $row) || $row[$strCol] === null) { + $tabParts[] = '`' . $strCol . '` IS NULL'; + } else { + $tabParts[] = '`' . $strCol . "`='" . $objDb->fxEscape($row[$strCol]) . "'"; + } + } + + return implode(' AND ', $tabParts); +} + +/** + * CON-333 — UPDATE des clés déjà présentes mais contenu différent (préprod = vérité textes). + * Inclut les corrections de libellés et les poubelles. Ne DELETE rien. N’insère pas les manquants. + */ +function fxStaticSyncApplyContentUpdates($objSource, $objTarget, $strTable, array $tabDef = null) { + $tabPrep = fxStaticSyncPrepareSoftWrite($objSource, $objTarget, $strTable, $tabDef); + if (empty($tabPrep['ok'])) { + return $tabPrep; + } + + $tabUpdateCols = fxStaticSyncInsertColumns($tabPrep['schema'], $tabDef); + $tabKeys = $tabDef['keys']; + $tabUpdateCols = array_values(array_filter($tabUpdateCols, function ($strCol) use ($tabKeys) { + return !in_array($strCol, $tabKeys, true); + })); + + if (count($tabUpdateCols) === 0) { + return array('ok' => false, 'message' => 'Aucune colonne de contenu à mettre à jour.'); + } + + $tabSchemaCols = $tabPrep['schema']['copy_cols']; + $intUpdated = 0; + $blnTransactional = (fxStaticSyncGetTableEngine($objTarget, $strTable) === 'INNODB'); + + if ($blnTransactional) { + $tabTx = fxStaticSyncExecQuery($objTarget, 'START TRANSACTION'); + if (!$tabTx['ok']) { + return array('ok' => false, 'message' => 'Transaction : ' . $tabTx['error']); + } + } + + foreach ($tabPrep['source_rows'] as $strKey => $tabSrcEntry) { + if (!isset($tabPrep['target_rows'][$strKey])) { + continue; + } + if ($tabPrep['target_rows'][$strKey]['hash'] === $tabSrcEntry['hash']) { + continue; + } + + $tabSrc = $tabSrcEntry['row']; + $tabTgt = $tabPrep['target_rows'][$strKey]['row']; + + $tabSets = array(); + foreach ($tabUpdateCols as $strCol) { + if (!array_key_exists($strCol, $tabSrc) || $tabSrc[$strCol] === null) { + $tabSets[] = '`' . $strCol . '`=NULL'; + } else { + $tabSets[] = '`' . $strCol . "`='" . $objTarget->fxEscape($tabSrc[$strCol]) . "'"; + } + } + if ($strTable === 'info' && in_array('info_maj', $tabSchemaCols, true)) { + $tabSets[] = '`info_maj`=NOW()'; + } + + $strSql = 'UPDATE `' . $strTable . '` SET ' . implode(',', $tabSets) + . ' WHERE ' . fxStaticSyncSqlWhereBusinessKeys($objTarget, $tabTgt, $tabKeys); + + $tabUpd = fxStaticSyncExecQuery($objTarget, $strSql); + if (!$tabUpd['ok']) { + if ($blnTransactional) { + fxStaticSyncExecQuery($objTarget, 'ROLLBACK'); + } + return array('ok' => false, 'message' => 'UPDATE corrections : ' . $tabUpd['error']); + } + $intUpdated++; + } + + if ($blnTransactional) { + $tabCommit = fxStaticSyncExecQuery($objTarget, 'COMMIT'); + if (!$tabCommit['ok']) { + fxStaticSyncExecQuery($objTarget, 'ROLLBACK'); + return array('ok' => false, 'message' => 'Commit : ' . $tabCommit['error']); + } + } + + return array( + 'ok' => true, + 'message' => $intUpdated . ' ligne(s) mise(s) à jour depuis la source (corrections / diffs, aucun DELETE).', + 'updated' => $intUpdated, + ); +} + +/** + * CON-333 — info seulement : UPDATE des poubelles cible quand la source a un vrai texte. + * N’écrase jamais un libellé déjà OK. Ne DELETE rien. + */ +function fxStaticSyncRepairInfoPoubelle($objSource, $objTarget, array $tabDef = null) { + if (!$tabDef) { + $tabDef = fxStaticSyncFindTableDef('info'); + } + if (!$tabDef || $tabDef['table'] !== 'info') { + return array('ok' => false, 'message' => 'Réparation poubelle réservée à la table info.'); + } + + $tabPrep = fxStaticSyncPrepareSoftWrite($objSource, $objTarget, 'info', $tabDef); + if (empty($tabPrep['ok'])) { + return $tabPrep; + } + + $tabUpdateCols = array( + 'info_texte', 'info_aide', 'info_description', 'info_trie', 'info_actif', + 'info_option1', 'info_option2', 'info_option3', + ); + $tabSchemaCols = $tabPrep['schema']['copy_cols']; + $tabUpdateCols = array_values(array_intersect($tabUpdateCols, $tabSchemaCols)); + + $intRepaired = 0; + $blnTransactional = (fxStaticSyncGetTableEngine($objTarget, 'info') === 'INNODB'); + + if ($blnTransactional) { + $tabTx = fxStaticSyncExecQuery($objTarget, 'START TRANSACTION'); + if (!$tabTx['ok']) { + return array('ok' => false, 'message' => 'Transaction : ' . $tabTx['error']); + } + } + + foreach ($tabPrep['source_rows'] as $strKey => $tabSrcEntry) { + if (!isset($tabPrep['target_rows'][$strKey])) { + continue; + } + $tabSrc = $tabSrcEntry['row']; + $tabTgt = $tabPrep['target_rows'][$strKey]['row']; + + if (!fxStaticSyncInfoRowIsPoubelle($tabTgt) || !fxStaticSyncInfoRowHasRealTexte($tabSrc)) { + continue; + } + + $tabSets = array(); + foreach ($tabUpdateCols as $strCol) { + if (!array_key_exists($strCol, $tabSrc) || $tabSrc[$strCol] === null) { + $tabSets[] = '`' . $strCol . '`=NULL'; + } else { + $tabSets[] = '`' . $strCol . "`='" . $objTarget->fxEscape($tabSrc[$strCol]) . "'"; + } + } + if (in_array('info_maj', $tabSchemaCols, true)) { + $tabSets[] = '`info_maj`=NOW()'; + } + + $strWhere = '`info_clef`=\'' . $objTarget->fxEscape($tabTgt['info_clef']) . '\'' + . ' AND `info_langue`=\'' . $objTarget->fxEscape($tabTgt['info_langue']) . '\'' + . ' AND `info_prg`=\'' . $objTarget->fxEscape($tabTgt['info_prg']) . '\'' + . ' AND `info_texte`=`info_clef`'; + + $strSql = 'UPDATE `info` SET ' . implode(',', $tabSets) . ' WHERE ' . $strWhere; + $tabUpd = fxStaticSyncExecQuery($objTarget, $strSql); + if (!$tabUpd['ok']) { + if ($blnTransactional) { + fxStaticSyncExecQuery($objTarget, 'ROLLBACK'); + } + return array('ok' => false, 'message' => 'UPDATE poubelle : ' . $tabUpd['error']); + } + $intRepaired++; + } + + if ($blnTransactional) { + $tabCommit = fxStaticSyncExecQuery($objTarget, 'COMMIT'); + if (!$tabCommit['ok']) { + fxStaticSyncExecQuery($objTarget, 'ROLLBACK'); + return array('ok' => false, 'message' => 'Commit : ' . $tabCommit['error']); + } + } + + return array( + 'ok' => true, + 'message' => $intRepaired . ' poubelle(s) réparée(s) depuis la source (aucun DELETE, libellés OK inchangés).', + 'repaired' => $intRepaired, + ); +} + +/** + * CON-333 — Ancien Sync destructif (DELETE + INSERT) : désactivé. + * Conservé pour ne pas casser d’appels résiduels — renvoie toujours une erreur. + */ +function fxStaticSyncCopyTable($objSource, $objTarget, $strTable, array $tabDef = null) { + return array( + 'ok' => false, + 'message' => 'CON-333 — Sync destructif désactivé (DELETE interdit). ' + . 'Utiliser « Appliquer manquants » et/ou « Réparer poubelles ».', ); } @@ -817,12 +1055,31 @@ function fxStaticSyncCompareEnvPair($objSource, $objTarget, array $tabDef) { 'missing_keys' => array(), 'extra_keys' => array(), 'diff_keys' => array(), + 'poubelle_keys' => array(), 'schema_missing_cols' => array(), 'schema_extra_cols' => array(), ); } - return fxStaticSyncCompareTable($tabSourceData, $tabTargetData, $tabSchema); + $tabCmp = fxStaticSyncCompareTable($tabSourceData, $tabTargetData, $tabSchema); + + // CON-333 — poubelles info réparables (cible brute, source OK) — jamais auto-supprimées. + $tabPoubelle = array(); + if ($tabDef['table'] === 'info') { + foreach ($tabSourceData['rows'] as $strKey => $tabSrcEntry) { + if (!isset($tabTargetData['rows'][$strKey])) { + continue; + } + $tabSrc = $tabSrcEntry['row']; + $tabTgt = $tabTargetData['rows'][$strKey]['row']; + if (fxStaticSyncInfoRowIsPoubelle($tabTgt) && fxStaticSyncInfoRowHasRealTexte($tabSrc)) { + $tabPoubelle[] = $strKey; + } + } + } + $tabCmp['poubelle_keys'] = $tabPoubelle; + + return $tabCmp; } function fxStaticSyncBuildReport($tabConnections) { @@ -891,27 +1148,44 @@ function fxStaticSyncGetDiffDetail($strTable, $strEnvId, $tabConnections) { $tabSourceData = fxStaticSyncLoadKeyedRows($objSource, $tabDef, $tabSchema['compare_cols']); $tabTargetData = fxStaticSyncLoadKeyedRows($objTarget, $tabDef, $tabSchema['compare_cols']); + $tabPoubelle = isset($tabCompare['poubelle_keys']) ? $tabCompare['poubelle_keys'] : array(); + $tabDetail = array( 'compare' => $tabCompare, 'samples' => array(), + 'note' => 'CON-333 — Les clés « en trop » en cible ne sont jamais effacées automatiquement.', ); + // Priorité d’affichage : manquants, poubelles, autres diffs, extras (revue manuelle). $tabKeysToShow = array_slice( - array_merge($tabCompare['missing_keys'], $tabCompare['diff_keys'], $tabCompare['extra_keys']), + array_merge( + $tabCompare['missing_keys'], + $tabPoubelle, + array_diff($tabCompare['diff_keys'], $tabPoubelle), + $tabCompare['extra_keys'] + ), 0, - 30 + 40 ); foreach ($tabKeysToShow as $strKey) { + $strType = 'diff'; + if (in_array($strKey, $tabCompare['extra_keys'], true)) { + $strType = 'extra'; + } elseif (in_array($strKey, $tabCompare['missing_keys'], true)) { + $strType = 'missing'; + } elseif (in_array($strKey, $tabPoubelle, true)) { + $strType = 'poubelle'; + } + $tabSample = array( 'key' => $strKey, - 'type' => in_array($strKey, $tabCompare['extra_keys'], true) ? 'extra' - : (in_array($strKey, $tabCompare['missing_keys'], true) ? 'missing' : 'diff'), + 'type' => $strType, 'source' => isset($tabSourceData['rows'][$strKey]['row']) ? $tabSourceData['rows'][$strKey]['row'] : null, 'target' => isset($tabTargetData['rows'][$strKey]['row']) ? $tabTargetData['rows'][$strKey]['row'] : null, ); - if ($tabDef['table'] === 'info' && $tabSample['type'] === 'diff') { + if ($tabDef['table'] === 'info' && ($strType === 'diff' || $strType === 'poubelle')) { $tabSample['source_texte'] = isset($tabSample['source']['info_texte']) ? $tabSample['source']['info_texte'] : ''; $tabSample['target_texte'] = isset($tabSample['target']['info_texte']) ? $tabSample['target']['info_texte'] : ''; } diff --git a/php/inc_fx_static_sync_config.php b/php/inc_fx_static_sync_config.php index 8259b9f..d4054f5 100644 --- a/php/inc_fx_static_sync_config.php +++ b/php/inc_fx_static_sync_config.php @@ -128,6 +128,18 @@ function fxStaticSyncTableDefinitions() { 'keys' => array('reg_id'), 'ignore_cols' => array(), ), - + // CON-333 — seeds traçabilité fiche (MSIN-4464) ; log runtime exclu. + array( + 'table' => 'inscriptions_fiche_audit_settings', + 'label' => 'Audit fiche — réglages', + 'keys' => array('setting_id'), + 'ignore_cols' => array('setting_updated_at'), + ), + array( + 'table' => 'inscriptions_fiche_audit_fields', + 'label' => 'Audit fiche — champs', + 'keys' => array('field_key'), + 'ignore_cols' => array('field_updated_at'), + ), ); } diff --git a/php/sync_static_db.php b/php/sync_static_db.php index 149ca85..3a8c394 100644 --- a/php/sync_static_db.php +++ b/php/sync_static_db.php @@ -1,8 +1,8 @@ - Sync tables statiques + Sync tables statiques (soft) — CON-333