CON-333 — Add functionality to remove excess "poubelle" entries from the info table during synchronization. Introduce a new action for users to trigger this process, ensuring that only unnecessary entries are deleted while preserving valid labels. Update user interface messaging to clarify the operation and its implications. Increment version code.

This commit is contained in:
2026-07-23 09:28:14 -04:00
parent 88a8010a18
commit 5b6faf93f9
2 changed files with 126 additions and 4 deletions

View File

@ -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). * CON-333 — Retirer les lignes « en trop » (catalogue accès v2).
* info : jamais. Rôles : refuse si encore utilisés dans inscriptions_eve_acces. * 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; $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; return $tabCmp;
} }

View File

@ -60,10 +60,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if (!fxStaticSyncValidateCsrf($_POST['csrf'] ?? '')) { if (!fxStaticSyncValidateCsrf($_POST['csrf'] ?? '')) {
fxStaticSyncSetFlash('Jeton CSRF invalide.', 'bad'); 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( fxStaticSyncSetFlash(
'Action refusée. Sync destructif désactivé (CON-333). ' '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' 'bad'
); );
} else { } else {
@ -99,6 +99,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$tabResult = fxStaticSyncApplyMissingRows($objSource, $objTarget, $strTable, $tabDef); $tabResult = fxStaticSyncApplyMissingRows($objSource, $objTarget, $strTable, $tabDef);
} elseif ($strAction === 'remove_extras') { } elseif ($strAction === 'remove_extras') {
$tabResult = fxStaticSyncRemoveExtras($objSource, $objTarget, $strTable, $tabDef); $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 { } else {
$tabResult = fxStaticSyncApplyContentUpdates($objSource, $objTarget, $strTable, $tabDef); $tabResult = fxStaticSyncApplyContentUpdates($objSource, $objTarget, $strTable, $tabDef);
} }
@ -195,8 +201,9 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
<h1>Sync tables statiques — mode soft (CON-333)</h1> <h1>Sync tables statiques — mode soft (CON-333)</h1>
<div class="warn-box"> <div class="warn-box">
<strong>Aucun DELETE.</strong> <strong>Aucun DELETE.</strong>
On nefface jamais <code>info</code>. Catalogues accès v2 (rôles / matrice / permissions) : On nefface jamais un <strong>vrai</strong> libellé <code>info</code> seulement en cible.
manquants + corrections, et <strong>Retirer en trop</strong> si besoin — sauf rôle encore utilisé en accès promoteur. Les <strong>poubelles</strong> info en trop (texte = clé) : bouton dédié pour les retirer.
Catalogues accès v2 : Retirer en trop (sauf rôle encore utilisé).
</div> </div>
<div class="proc"> <div class="proc">
@ -275,6 +282,8 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
$intMissing = isset($tabCmp['missing_keys']) ? count($tabCmp['missing_keys']) : 0; $intMissing = isset($tabCmp['missing_keys']) ? count($tabCmp['missing_keys']) : 0;
$intExtra = isset($tabCmp['extra_keys']) ? count($tabCmp['extra_keys']) : 0; $intExtra = isset($tabCmp['extra_keys']) ? count($tabCmp['extra_keys']) : 0;
$intDiff = isset($tabCmp['diff_keys']) ? count($tabCmp['diff_keys']) : 0; $intDiff = isset($tabCmp['diff_keys']) ? count($tabCmp['diff_keys']) : 0;
$intPoubExtra = isset($tabCmp['poubelle_extra_keys']) ? count($tabCmp['poubelle_extra_keys']) : 0;
$intRealExtra = isset($tabCmp['real_extra_keys']) ? count($tabCmp['real_extra_keys']) : 0;
$blnCanRemoveExtras = !empty($tabDef['allow_remove_extras']); $blnCanRemoveExtras = !empty($tabDef['allow_remove_extras']);
$blnCanWrite = ($tabCmp['status'] !== 'no_connection' && $tabCmp['status'] !== 'schema_mismatch' $blnCanWrite = ($tabCmp['status'] !== 'no_connection' && $tabCmp['status'] !== 'schema_mismatch'
&& $tabCmp['status'] !== 'missing_table' && $tabCmp['status'] !== 'error'); && $tabCmp['status'] !== 'missing_table' && $tabCmp['status'] !== 'error');
@ -289,6 +298,9 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
Manque <?php echo (int)$intMissing; ?> Manque <?php echo (int)$intMissing; ?>
· Diff <?php echo (int)$intDiff; ?> · Diff <?php echo (int)$intDiff; ?>
· En trop <?php echo (int)$intExtra; ?> · En trop <?php echo (int)$intExtra; ?>
<?php if ($tabDef['table'] === 'info' && $intExtra > 0) { ?>
<br>dont poubelles <?php echo (int)$intPoubExtra; ?> · vrais textes <?php echo (int)$intRealExtra; ?>
<?php } ?>
</div> </div>
<?php } ?> <?php } ?>
<?php if ($tabCmp['status'] === 'schema_mismatch') { <?php if ($tabCmp['status'] === 'schema_mismatch') {
@ -335,6 +347,15 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
<button type="submit" class="btn btn-remove">Retirer en trop (<?php echo (int)$intExtra; ?>)</button> <button type="submit" class="btn btn-remove">Retirer en trop (<?php echo (int)$intExtra; ?>)</button>
</form> </form>
<?php } ?> <?php } ?>
<?php if ($blnCanWrite && $tabDef['table'] === 'info' && $intPoubExtra > 0) { ?>
<form method="post" style="display:inline;" onsubmit="return confirm('CON-333 — Retirer <?php echo (int)$intPoubExtra; ?> poubelle(s) info en trop ?\nSeules les lignes texte=clé absentes de la préprod.\nLes <?php echo (int)$intRealExtra; ?> vrais libellés seulement en cible restent.');">
<input type="hidden" name="action" value="remove_info_poubelle_extras">
<input type="hidden" name="csrf" value="<?php echo ssEsc($strCsrf); ?>">
<input type="hidden" name="table" value="info">
<input type="hidden" name="env" value="<?php echo ssEsc($strEnvId); ?>">
<button type="submit" class="btn btn-remove">Retirer poubelles en trop (<?php echo (int)$intPoubExtra; ?>)</button>
</form>
<?php } ?>
</td> </td>
<?php } ?> <?php } ?>
</tr> </tr>