diff --git a/php/inc_fx_static_sync.php b/php/inc_fx_static_sync.php index 6338f41..9e930a5 100644 --- a/php/inc_fx_static_sync.php +++ b/php/inc_fx_static_sync.php @@ -1013,6 +1013,88 @@ function fxStaticSyncRepairInfoPoubelle($objSource, $objTarget, array $tabDef = ); } +/** + * CON-333 — info seulement : retirer les « en trop » qui sont des poubelles (texte = clé). + * Les vrais libellés présents seulement en cible sont CONSERVÉS (pas de DELETE). + */ +function fxStaticSyncRemoveInfoExtraPoubelle($objSource, $objTarget, array $tabDef = null) { + if (!$tabDef) { + $tabDef = fxStaticSyncFindTableDef('info'); + } + if (!$tabDef || $tabDef['table'] !== 'info') { + return array('ok' => false, 'message' => 'Réservé à info.'); + } + + $tabPrep = fxStaticSyncPrepareSoftWrite($objSource, $objTarget, 'info', $tabDef); + if (empty($tabPrep['ok'])) { + return $tabPrep; + } + + $tabToDelete = array(); + $intKeptReal = 0; + foreach ($tabPrep['target_rows'] as $strKey => $tabEntry) { + if (isset($tabPrep['source_rows'][$strKey])) { + continue; + } + $row = $tabEntry['row']; + if (fxStaticSyncInfoRowIsPoubelle($row)) { + $tabToDelete[] = $row; + } else { + $intKeptReal++; + } + } + + $intDel = count($tabToDelete); + if ($intDel === 0) { + return array( + 'ok' => true, + 'message' => 'Aucune poubelle en trop à retirer. ' + . $intKeptReal . ' vrai(s) libellé(s) seulement en cible — conservé(s) (pas de DELETE).', + 'deleted' => 0, + 'kept_real' => $intKeptReal, + ); + } + + $blnTransactional = (fxStaticSyncGetTableEngine($objTarget, 'info') === 'INNODB'); + if ($blnTransactional) { + $tabTx = fxStaticSyncExecQuery($objTarget, 'START TRANSACTION'); + if (!$tabTx['ok']) { + return array('ok' => false, 'message' => 'Transaction : ' . $tabTx['error']); + } + } + + $intDeleted = 0; + foreach ($tabToDelete as $row) { + $strSql = 'DELETE FROM `info` WHERE ' + . fxStaticSyncSqlWhereBusinessKeys($objTarget, $row, $tabDef['keys']) + . ' AND `info_texte`=`info_clef` LIMIT 1'; + $tabDel = fxStaticSyncExecQuery($objTarget, $strSql); + if (!$tabDel['ok']) { + if ($blnTransactional) { + fxStaticSyncExecQuery($objTarget, 'ROLLBACK'); + } + return array('ok' => false, 'message' => 'DELETE poubelle : ' . $tabDel['error']); + } + $intDeleted++; + } + + 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' => $intDeleted . ' poubelle(s) en trop retirée(s). ' + . $intKeptReal . ' vrai(s) libellé(s) seulement en cible — conservé(s) volontairement.', + 'deleted' => $intDeleted, + 'kept_real' => $intKeptReal, + ); +} + /** * CON-333 — Retirer les lignes « en trop » (catalogue accès v2). * info : jamais. Rôles : refuse si encore utilisés dans inscriptions_eve_acces. @@ -1516,6 +1598,25 @@ function fxStaticSyncCompareEnvPair($objSource, $objTarget, array $tabDef) { } $tabCmp['poubelle_keys'] = $tabPoubelle; + // CON-333 — en trop info qui sont des poubelles (retirables) vs vrais libellés (à garder). + $tabPoubExtra = array(); + $tabRealExtra = array(); + if ($tabDef['table'] === 'info') { + foreach ($tabTargetData['rows'] as $strKey => $tabTgtEntry) { + if (isset($tabSourceData['rows'][$strKey])) { + continue; + } + $tabTgt = $tabTgtEntry['row']; + if (fxStaticSyncInfoRowIsPoubelle($tabTgt)) { + $tabPoubExtra[] = $strKey; + } else { + $tabRealExtra[] = $strKey; + } + } + } + $tabCmp['poubelle_extra_keys'] = $tabPoubExtra; + $tabCmp['real_extra_keys'] = $tabRealExtra; + return $tabCmp; } diff --git a/php/sync_static_db.php b/php/sync_static_db.php index 8a485db..8af65e9 100644 --- a/php/sync_static_db.php +++ b/php/sync_static_db.php @@ -60,10 +60,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { if (!fxStaticSyncValidateCsrf($_POST['csrf'] ?? '')) { fxStaticSyncSetFlash('Jeton CSRF invalide.', 'bad'); - } elseif (!in_array($strAction, array('apply_missing', 'apply_content', 'apply_all', 'remove_extras'), true)) { + } elseif (!in_array($strAction, array('apply_missing', 'apply_content', 'apply_all', 'remove_extras', 'remove_info_poubelle_extras'), true)) { fxStaticSyncSetFlash( 'Action refusée. Sync destructif désactivé (CON-333). ' - . 'Utiliser Appliquer manquants / corrections / Retirer en trop (catalogues).', + . 'Utiliser Appliquer manquants / corrections / Retirer en trop / Retirer poubelles info.', 'bad' ); } else { @@ -99,6 +99,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $tabResult = fxStaticSyncApplyMissingRows($objSource, $objTarget, $strTable, $tabDef); } elseif ($strAction === 'remove_extras') { $tabResult = fxStaticSyncRemoveExtras($objSource, $objTarget, $strTable, $tabDef); + } elseif ($strAction === 'remove_info_poubelle_extras') { + if ($tabDef['table'] !== 'info') { + $tabResult = array('ok' => false, 'message' => 'Réservé à info.'); + } else { + $tabResult = fxStaticSyncRemoveInfoExtraPoubelle($objSource, $objTarget, $tabDef); + } } else { $tabResult = fxStaticSyncApplyContentUpdates($objSource, $objTarget, $strTable, $tabDef); } @@ -195,8 +201,9 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
info. Catalogues accès v2 (rôles / matrice / permissions) :
- manquants + corrections, et Retirer en trop si besoin — sauf rôle encore utilisé en accès promoteur.
+ On n’efface jamais un vrai libellé info seulement en cible.
+ Les poubelles info en trop (texte = clé) : bouton dédié pour les retirer.
+ Catalogues accès v2 : Retirer en trop (sauf rôle encore utilisé).