425 lines
21 KiB
PHP
425 lines
21 KiB
PHP
<?php
|
||
|
||
/**
|
||
* CON-333 — Tableau de bord sync tables statiques (soft).
|
||
* Source : devinscription_preprod. Aucun DELETE — insert manquants + réparation poubelles info.
|
||
*/
|
||
|
||
require_once('inc_start_time.php');
|
||
require_once('inc_fonctions.php');
|
||
require_once('inc_fx_messages.php');
|
||
require_once('inc_fx_static_sync.php');
|
||
|
||
if (empty($_SESSION['usa_id'])) {
|
||
fxAdminRequireSuperadmLogin();
|
||
}
|
||
|
||
if (!fxAdminStaticSyncAllowed()) {
|
||
header('HTTP/1.1 403 Forbidden');
|
||
echo 'Accès refusé.';
|
||
exit;
|
||
}
|
||
|
||
set_time_limit(300);
|
||
|
||
function ssEsc($str) {
|
||
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
|
||
}
|
||
|
||
function ssSoftActionLabel($strType) {
|
||
if ($strType === 'extra') {
|
||
return 'en trop (cible seulement — ne pas effacer auto)';
|
||
}
|
||
if ($strType === 'missing') {
|
||
return 'manque en cible';
|
||
}
|
||
if ($strType === 'poubelle') {
|
||
return 'poubelle réparable';
|
||
}
|
||
|
||
if ($strType === 'diff') {
|
||
return 'contenu différent — Appliquer corrections';
|
||
}
|
||
|
||
return 'contenu différent';
|
||
}
|
||
|
||
$strCsrf = fxStaticSyncEnsureCsrfToken();
|
||
$strFlash = '';
|
||
$strFlashType = 'info';
|
||
|
||
$tabPopFlash = fxStaticSyncPopFlash();
|
||
if (is_array($tabPopFlash)) {
|
||
$strFlash = $tabPopFlash['message'];
|
||
$strFlashType = $tabPopFlash['type'];
|
||
}
|
||
|
||
// CON-333 — actions soft : apply_missing | apply_content (préprod = vérité textes).
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||
$strAction = trim($_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)) {
|
||
fxStaticSyncSetFlash(
|
||
'Action refusée. Sync destructif désactivé (CON-333). '
|
||
. 'Utiliser Appliquer manquants / corrections / Retirer en trop (catalogues).',
|
||
'bad'
|
||
);
|
||
} else {
|
||
$strTable = trim($_POST['table'] ?? '');
|
||
$strEnvId = trim($_POST['env'] ?? '');
|
||
$tabEnv = fxStaticSyncFindEnvDef($strEnvId);
|
||
|
||
if (!$tabEnv || !empty($tabEnv['is_source'])) {
|
||
fxStaticSyncSetFlash('Paramètres invalides.', 'bad');
|
||
} else {
|
||
$tabConnections = fxStaticSyncOpenConnections();
|
||
$objSource = $tabConnections['dev_preprod'];
|
||
$objTarget = $tabConnections[$strEnvId];
|
||
|
||
if (!$objSource || !$objTarget) {
|
||
fxStaticSyncSetFlash(
|
||
'Connexion BD impossible — ' . fxStaticSyncFormatConnectionError($tabEnv),
|
||
'bad'
|
||
);
|
||
} elseif ($strAction === 'apply_all') {
|
||
$tabResult = fxStaticSyncApplyAllSoft($objSource, $objTarget, $strEnvId);
|
||
$strMsg = $tabEnv['label'] . ' — ' . $tabResult['message'];
|
||
if (!empty($tabResult['lines'])) {
|
||
$strMsg .= "\n" . implode("\n", $tabResult['lines']);
|
||
}
|
||
fxStaticSyncSetFlash($strMsg, !empty($tabResult['ok']) ? 'ok' : 'bad');
|
||
} else {
|
||
$tabDef = fxStaticSyncFindTableDef($strTable);
|
||
if (!$tabDef) {
|
||
fxStaticSyncSetFlash('Paramètres invalides.', 'bad');
|
||
} else {
|
||
if ($strAction === 'apply_missing') {
|
||
$tabResult = fxStaticSyncApplyMissingRows($objSource, $objTarget, $strTable, $tabDef);
|
||
} elseif ($strAction === 'remove_extras') {
|
||
$tabResult = fxStaticSyncRemoveExtras($objSource, $objTarget, $strTable, $tabDef);
|
||
} else {
|
||
$tabResult = fxStaticSyncApplyContentUpdates($objSource, $objTarget, $strTable, $tabDef);
|
||
}
|
||
|
||
if ($tabResult['ok']) {
|
||
$tabVerify = fxStaticSyncCompareEnvPair($objSource, $objTarget, $tabDef);
|
||
$strMsg = $tabDef['label'] . ' → ' . $tabEnv['label'] . ' : ' . $tabResult['message'];
|
||
$intExtra = count($tabVerify['extra_keys']);
|
||
$intMiss = count($tabVerify['missing_keys']);
|
||
$intDiff = count($tabVerify['diff_keys']);
|
||
$strMsg .= ' Après : manque ' . $intMiss
|
||
. ', contenu diff. ' . $intDiff
|
||
. ', en trop (conservés) ' . $intExtra . '.';
|
||
if ($intMiss === 0 && $intDiff === 0 && $tabVerify['status'] === 'ok') {
|
||
fxStaticSyncSetFlash($strMsg, 'ok');
|
||
} elseif ($intMiss === 0 && $intDiff === 0) {
|
||
fxStaticSyncSetFlash($strMsg . ' Écarts restants = revue manuelle (pas de DELETE).', 'ok');
|
||
} else {
|
||
fxStaticSyncSetFlash($strMsg, 'ok');
|
||
}
|
||
} else {
|
||
fxStaticSyncSetFlash(
|
||
$tabDef['label'] . ' → ' . $tabEnv['label'] . ' — échec : ' . $tabResult['message'],
|
||
'bad'
|
||
);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
header('Location: sync_static_db.php#sync-result');
|
||
exit;
|
||
}
|
||
|
||
$tabConnections = fxStaticSyncOpenConnections();
|
||
$tabEnvs = fxStaticSyncEnvironmentDefinitions();
|
||
$tabReport = fxStaticSyncBuildReport($tabConnections);
|
||
|
||
$strDetailTable = trim($_GET['detail_table'] ?? '');
|
||
$strDetailEnv = trim($_GET['detail_env'] ?? '');
|
||
$tabDetail = null;
|
||
|
||
if ($strDetailTable !== '' && $strDetailEnv !== '') {
|
||
$tabDetail = fxStaticSyncGetDiffDetail($strDetailTable, $strDetailEnv, $tabConnections);
|
||
}
|
||
|
||
?><!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Sync tables statiques (soft) — CON-333</title>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; margin: 20px; background: #f4f6f8; color: #222; }
|
||
h1 { font-size: 1.4rem; margin: 0 0 8px; }
|
||
.sub { color: #555; margin-bottom: 20px; font-size: 0.95rem; }
|
||
.flash { padding: 10px 14px; border-radius: 6px; margin-bottom: 16px; white-space: pre-wrap; word-break: break-word; }
|
||
.flash-ok { background: #d4edda; border: 1px solid #b7dfc3; }
|
||
.flash-bad { background: #f8d7da; border: 1px solid #f1b8be; }
|
||
.flash-info { background: #e8f0fe; border: 1px solid #c5d7fb; }
|
||
.warn-box { background: #e8f5e9; border: 1px solid #a5d6a7; padding: 12px 14px; border-radius: 6px; margin-bottom: 16px; font-size: 0.9rem; }
|
||
.warn-box strong { color: #1b5e20; }
|
||
.proc { background: #fff; border: 1px solid #ccc; padding: 12px 14px; border-radius: 6px; margin-bottom: 16px; font-size: 0.9rem; }
|
||
.proc ol { margin: 8px 0 0; padding-left: 22px; }
|
||
.proc li { margin-bottom: 4px; }
|
||
table { width: 100%; border-collapse: collapse; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
|
||
th, td { border: 1px solid #ddd; padding: 8px 10px; vertical-align: top; font-size: 0.9rem; }
|
||
th { background: #eef2f7; text-align: left; }
|
||
.ss-ok { background: #d4edda; color: #155724; }
|
||
.ss-warn { background: #fff3cd; color: #856404; }
|
||
.ss-bad { background: #f8d7da; color: #721c24; }
|
||
.ss-muted { background: #e9ecef; color: #495057; }
|
||
.ss-schema { background: #fde2e2; color: #7f1d1d; border: 1px solid #f5c2c2; }
|
||
.badge { display: inline-block; padding: 3px 8px; border-radius: 4px; font-size: 0.82rem; font-weight: 600; max-width: 100%; line-height: 1.35; }
|
||
.count { font-size: 0.82rem; color: #444; margin-top: 4px; }
|
||
.count-hint { font-size: 0.78rem; color: #666; }
|
||
.btn { display: inline-block; margin-top: 6px; margin-right: 4px; padding: 4px 10px; font-size: 0.82rem; border: 1px solid #888; background: #fff; border-radius: 4px; cursor: pointer; text-decoration: none; color: #222; }
|
||
.btn:hover { background: #f0f0f0; }
|
||
.btn-soft { border-color: #2e7d32; color: #1b5e20; }
|
||
.btn-content { border-color: #1565c0; color: #0d47a1; }
|
||
.btn-remove { border-color: #c62828; color: #b71c1c; }
|
||
.btn-repair { border-color: #ef6c00; color: #e65100; }
|
||
.detail-box { margin-top: 24px; background: #fff; padding: 16px; border: 1px solid #ccc; border-radius: 6px; }
|
||
.detail-box h2 { margin-top: 0; font-size: 1.1rem; }
|
||
.detail-list { margin: 0; padding-left: 18px; }
|
||
.detail-list li { margin-bottom: 8px; }
|
||
.legend { margin: 16px 0; font-size: 0.85rem; }
|
||
.legend span { display: inline-block; margin-right: 12px; padding: 2px 8px; border-radius: 4px; }
|
||
code { background: #f1f1f1; padding: 1px 4px; border-radius: 3px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>Sync tables statiques — mode soft (CON-333)</h1>
|
||
<div class="warn-box">
|
||
<strong>Aucun DELETE.</strong>
|
||
On n’efface jamais <code>info</code>. Catalogues accès v2 (rôles / matrice / permissions) :
|
||
manquants + corrections, et <strong>Retirer en trop</strong> si besoin — sauf rôle encore utilisé en accès promoteur.
|
||
</div>
|
||
|
||
<div class="proc">
|
||
<strong>Test complet (un environnement à la fois)</strong>
|
||
<ol>
|
||
<li>Rafraîchir cette page (nouveau code déployé).</li>
|
||
<li>Cliquer <em>TOUT APPLIQUER</em> sous la colonne voulue (commencer par <strong>Dev prod</strong>).</li>
|
||
<li>Lire le message vert/rouge en haut : succès ou échec + détail table par table.</li>
|
||
<li>Recharger : Manque=0 et Diff=0 partout = OK. « En trop » peut rester (normal, on n’efface pas).</li>
|
||
<li>Lignes SAUTÉES (structure / table absente) = à corriger en Navicat, puis re-cliquer.</li>
|
||
</ol>
|
||
<form method="post" style="margin-top:12px;" onsubmit="return confirm('CON-333 — TOUT APPLIQUER sur Dev prod ?\nToutes les tables : manquants + corrections.\nAucun DELETE.');">
|
||
<input type="hidden" name="action" value="apply_all">
|
||
<input type="hidden" name="csrf" value="<?php echo ssEsc($strCsrf); ?>">
|
||
<input type="hidden" name="env" value="dev_prod">
|
||
<button type="submit" class="btn btn-content" style="font-weight:700;padding:8px 14px;">TOUT APPLIQUER → Dev prod</button>
|
||
</form>
|
||
</div>
|
||
|
||
<p class="sub">
|
||
Source de vérité : <strong>dev préprod</strong> (<code><?php echo ssEsc($arrConDatabasePreProd['db'] ?? ''); ?></code>).
|
||
Comparaison vers dev prod, client préprod et client prod.
|
||
</p>
|
||
|
||
<div id="sync-result"></div>
|
||
<?php if ($strFlash !== '') { ?>
|
||
<div class="flash flash-<?php echo ssEsc($strFlashType); ?>"><?php echo ssEsc($strFlash); ?></div>
|
||
<?php } ?>
|
||
|
||
<div class="legend">
|
||
<span class="ss-ok">Données alignées</span>
|
||
<span class="ss-warn">Il en manque X</span>
|
||
<span class="ss-bad">Il y en a X en trop</span>
|
||
<span class="ss-warn">Contenu différent</span>
|
||
<span class="ss-schema">Structures non alignées</span>
|
||
<span class="ss-muted">Table absente / connexion</span>
|
||
</div>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Table</th>
|
||
<th>Source<br><small><?php echo ssEsc($tabEnvs['dev_preprod']['config']['db'] ?? ''); ?></small></th>
|
||
<?php foreach ($tabEnvs as $strEnvId => $tabEnv) {
|
||
if (!empty($tabEnv['is_source'])) {
|
||
continue;
|
||
} ?>
|
||
<th><?php echo ssEsc($tabEnv['label']); ?><br><small><?php echo ssEsc($tabEnv['config']['db'] ?? ''); ?></small></th>
|
||
<?php } ?>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($tabReport as $tabRow) {
|
||
$tabDef = $tabRow['def']; ?>
|
||
<tr>
|
||
<td>
|
||
<strong><?php echo ssEsc($tabDef['label']); ?></strong><br>
|
||
<code><?php echo ssEsc($tabDef['table']); ?></code>
|
||
</td>
|
||
<td class="ss-muted">
|
||
<span class="badge"><?php echo (int)$tabRow['source_count']; ?> ligne(s)</span>
|
||
<?php if (!empty($tabRow['source_dupes'])) { ?>
|
||
<div class="count-hint"><?php echo (int)$tabRow['source_dupes']; ?> doublon(s) clé en source</div>
|
||
<?php } ?>
|
||
</td>
|
||
<?php foreach ($tabEnvs as $strEnvId => $tabEnv) {
|
||
if (!empty($tabEnv['is_source'])) {
|
||
continue;
|
||
}
|
||
$tabCmp = isset($tabRow['envs'][$strEnvId]) ? $tabRow['envs'][$strEnvId] : null;
|
||
if (!$tabCmp) {
|
||
continue;
|
||
}
|
||
$strClass = fxStaticSyncStatusClass($tabCmp['status']);
|
||
$strLabel = fxStaticSyncStatusLabel($tabCmp['status'], $tabCmp);
|
||
$intMissing = isset($tabCmp['missing_keys']) ? count($tabCmp['missing_keys']) : 0;
|
||
$intExtra = isset($tabCmp['extra_keys']) ? count($tabCmp['extra_keys']) : 0;
|
||
$intDiff = isset($tabCmp['diff_keys']) ? count($tabCmp['diff_keys']) : 0;
|
||
$blnCanRemoveExtras = !empty($tabDef['allow_remove_extras']);
|
||
$blnCanWrite = ($tabCmp['status'] !== 'no_connection' && $tabCmp['status'] !== 'schema_mismatch'
|
||
&& $tabCmp['status'] !== 'missing_table' && $tabCmp['status'] !== 'error');
|
||
?>
|
||
<td class="<?php echo ssEsc($strClass); ?>">
|
||
<span class="badge"><?php echo ssEsc($strLabel); ?></span>
|
||
<div class="count">
|
||
Cible <?php echo (int)$tabCmp['target_count']; ?> · Source <?php echo (int)$tabCmp['source_count']; ?>
|
||
</div>
|
||
<?php if ($blnCanWrite) { ?>
|
||
<div class="count-hint">
|
||
Manque <?php echo (int)$intMissing; ?>
|
||
· Diff <?php echo (int)$intDiff; ?>
|
||
· En trop <?php echo (int)$intExtra; ?>
|
||
</div>
|
||
<?php } ?>
|
||
<?php if ($tabCmp['status'] === 'schema_mismatch') {
|
||
$tabSchemaDiff = array(
|
||
'missing_in_target' => isset($tabCmp['schema_missing_cols']) ? $tabCmp['schema_missing_cols'] : array(),
|
||
'extra_in_target' => isset($tabCmp['schema_extra_cols']) ? $tabCmp['schema_extra_cols'] : array(),
|
||
);
|
||
$strSchemaDiff = fxStaticSyncFormatSchemaDiff($tabSchemaDiff);
|
||
if ($strSchemaDiff !== '') { ?>
|
||
<div class="count"><?php echo ssEsc($strSchemaDiff); ?></div>
|
||
<?php } } ?>
|
||
<?php if ($tabCmp['status'] !== 'ok' && $tabCmp['status'] !== 'no_connection') { ?>
|
||
<a class="btn" href="?detail_table=<?php echo urlencode($tabDef['table']); ?>&detail_env=<?php echo urlencode($strEnvId); ?>">Détails</a>
|
||
<?php } ?>
|
||
<?php if ($tabCmp['status'] === 'no_connection') {
|
||
$strConnErr = fxStaticSyncConnectError($tabEnv['config']['db'] ?? '');
|
||
if ($strConnErr !== '') { ?>
|
||
<div class="count-hint"><?php echo ssEsc($strConnErr); ?></div>
|
||
<?php } } ?>
|
||
<?php if ($blnCanWrite && $intMissing > 0) { ?>
|
||
<form method="post" style="display:inline;" onsubmit="return confirm('CON-333 — Ajouter <?php echo (int)$intMissing; ?> ligne(s) manquante(s) dans <?php echo ssEsc($tabEnv['label']); ?> ?\nAucun DELETE.');">
|
||
<input type="hidden" name="action" value="apply_missing">
|
||
<input type="hidden" name="csrf" value="<?php echo ssEsc($strCsrf); ?>">
|
||
<input type="hidden" name="table" value="<?php echo ssEsc($tabDef['table']); ?>">
|
||
<input type="hidden" name="env" value="<?php echo ssEsc($strEnvId); ?>">
|
||
<button type="submit" class="btn btn-soft">Appliquer manquants (<?php echo (int)$intMissing; ?>)</button>
|
||
</form>
|
||
<?php } ?>
|
||
<?php if ($blnCanWrite && $intDiff > 0) { ?>
|
||
<form method="post" style="display:inline;" onsubmit="return confirm('CON-333 — Écraser <?php echo (int)$intDiff; ?> ligne(s) en cible avec le contenu préprod ?\nLes clés en trop en cible ne sont pas touchées. Aucun DELETE.');">
|
||
<input type="hidden" name="action" value="apply_content">
|
||
<input type="hidden" name="csrf" value="<?php echo ssEsc($strCsrf); ?>">
|
||
<input type="hidden" name="table" value="<?php echo ssEsc($tabDef['table']); ?>">
|
||
<input type="hidden" name="env" value="<?php echo ssEsc($strEnvId); ?>">
|
||
<button type="submit" class="btn btn-content">Appliquer corrections (<?php echo (int)$intDiff; ?>)</button>
|
||
</form>
|
||
<?php } ?>
|
||
<?php if ($blnCanWrite && $blnCanRemoveExtras && $intExtra > 0) { ?>
|
||
<form method="post" style="display:inline;" onsubmit="return confirm('CON-333 — Retirer <?php echo (int)$intExtra; ?> en trop dans <?php echo ssEsc($tabEnv['label']); ?> ?\nCatalogue accès v2 seulement.\nLes rôles encore utilisés (inscriptions_eve_acces) ne seront PAS effacés.');">
|
||
<input type="hidden" name="action" value="remove_extras">
|
||
<input type="hidden" name="csrf" value="<?php echo ssEsc($strCsrf); ?>">
|
||
<input type="hidden" name="table" value="<?php echo ssEsc($tabDef['table']); ?>">
|
||
<input type="hidden" name="env" value="<?php echo ssEsc($strEnvId); ?>">
|
||
<button type="submit" class="btn btn-remove">Retirer en trop (<?php echo (int)$intExtra; ?>)</button>
|
||
</form>
|
||
<?php } ?>
|
||
</td>
|
||
<?php } ?>
|
||
</tr>
|
||
<?php } ?>
|
||
</tbody>
|
||
</table>
|
||
|
||
<?php if (is_array($tabDetail) && !empty($tabDetail['compare'])) {
|
||
$tabCmp = $tabDetail['compare'];
|
||
$tabDef = fxStaticSyncFindTableDef($strDetailTable);
|
||
$tabEnv = fxStaticSyncFindEnvDef($strDetailEnv);
|
||
$intMissing = count($tabCmp['missing_keys']);
|
||
$intExtra = count($tabCmp['extra_keys']);
|
||
$intDiff = count($tabCmp['diff_keys']);
|
||
$tabMissingSamples = isset($tabDetail['samples_missing']) ? $tabDetail['samples_missing'] : array();
|
||
$tabDiffSamples = isset($tabDetail['samples_diff']) ? $tabDetail['samples_diff'] : array();
|
||
$tabExtraSamples = isset($tabDetail['samples_extra']) ? $tabDetail['samples_extra'] : array();
|
||
?>
|
||
<div class="detail-box">
|
||
<h2>Détails — <?php echo ssEsc($tabDef['label'] ?? $strDetailTable); ?> → <?php echo ssEsc($tabEnv['label'] ?? $strDetailEnv); ?></h2>
|
||
<p>
|
||
Manque <strong><?php echo (int)$intMissing; ?></strong>
|
||
· Contenu différent <strong><?php echo (int)$intDiff; ?></strong>
|
||
· En trop en cible <strong><?php echo (int)$intExtra; ?></strong>
|
||
<a class="btn" href="sync_static_db.php" style="margin-left:12px;">Fermer</a>
|
||
</p>
|
||
<?php if (!empty($tabDetail['note'])) { ?>
|
||
<p class="count-hint"><?php echo ssEsc($tabDetail['note']); ?></p>
|
||
<?php } ?>
|
||
<?php if (!empty($tabDetail['extra_context'])) { ?>
|
||
<p class="warn-box" style="margin-top:10px;"><?php echo ssEsc($tabDetail['extra_context']); ?></p>
|
||
<?php } ?>
|
||
|
||
<?php if (count($tabExtraSamples) > 0) { ?>
|
||
<h3 style="margin-top:18px;font-size:1rem;">En trop en cible (<?php echo (int)$intExtra; ?>) — explications</h3>
|
||
<ul class="detail-list">
|
||
<?php foreach ($tabExtraSamples as $tabSample) { ?>
|
||
<li>
|
||
<strong><?php echo ssEsc(fxStaticSyncFormatKeyPreview($tabSample['key'])); ?></strong>
|
||
<br><?php echo ssEsc(isset($tabSample['explain']) ? $tabSample['explain'] : ssSoftActionLabel('extra')); ?>
|
||
<?php if ($tabDef['table'] === 'info' && !empty($tabSample['target_texte'])) { ?>
|
||
<br>Texte cible : <em><?php echo ssEsc($tabSample['target_texte']); ?></em>
|
||
<?php } ?>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
<?php if ($intExtra > count($tabExtraSamples)) { ?>
|
||
<p class="count-hint">Affichage limité à <?php echo count($tabExtraSamples); ?> / <?php echo (int)$intExtra; ?>.</p>
|
||
<?php } ?>
|
||
<?php } ?>
|
||
|
||
<?php if (count($tabMissingSamples) > 0) { ?>
|
||
<h3 style="margin-top:18px;font-size:1rem;">Manquants (<?php echo (int)$intMissing; ?>)</h3>
|
||
<ul class="detail-list">
|
||
<?php foreach ($tabMissingSamples as $tabSample) { ?>
|
||
<li>
|
||
<strong><?php echo ssEsc(fxStaticSyncFormatKeyPreview($tabSample['key'])); ?></strong>
|
||
— <?php echo ssEsc(isset($tabSample['explain']) ? $tabSample['explain'] : 'manque'); ?>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
<?php } ?>
|
||
|
||
<?php if (count($tabDiffSamples) > 0) { ?>
|
||
<h3 style="margin-top:18px;font-size:1rem;">Contenu différent (<?php echo (int)$intDiff; ?>)</h3>
|
||
<ul class="detail-list">
|
||
<?php foreach ($tabDiffSamples as $tabSample) { ?>
|
||
<li>
|
||
<strong><?php echo ssEsc(fxStaticSyncFormatKeyPreview($tabSample['key'])); ?></strong>
|
||
— <?php echo ssEsc(isset($tabSample['explain']) ? $tabSample['explain'] : 'diff'); ?>
|
||
<?php if ($tabDef['table'] === 'info') { ?>
|
||
<br>Source : <em><?php echo ssEsc($tabSample['source_texte'] ?? ''); ?></em>
|
||
<br>Cible : <em><?php echo ssEsc($tabSample['target_texte'] ?? ''); ?></em>
|
||
<?php } ?>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
<?php } ?>
|
||
|
||
<?php if ($intMissing === 0 && $intDiff === 0 && $intExtra === 0) { ?>
|
||
<p>Aucun écart à afficher.</p>
|
||
<?php } ?>
|
||
</div>
|
||
<?php } ?>
|
||
|
||
</body>
|
||
</html>
|