Enhance database synchronization functions and improve schema validation
This commit introduces new functions for resolving and comparing database schema columns, allowing for better handling of structural discrepancies during synchronization. The `fxStaticSyncCopyTable` function is updated to check for schema alignment before proceeding with data copying, providing clearer error messages when structures do not match. Additionally, the synchronization process is refined to allow for read-only operations towards production environments, enhancing safety and user feedback. Overall, these changes aim to improve the robustness and clarity of the database synchronization workflow.
This commit is contained in:
@ -39,6 +39,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
||||
if (!$tabDef || !$tabEnv || !empty($tabEnv['is_source'])) {
|
||||
$strFlash = 'Paramètres invalides.';
|
||||
$strFlashType = 'bad';
|
||||
} elseif (!fxStaticSyncWriteAllowed($strEnvId)) {
|
||||
$strFlash = 'Sync désactivée vers client prod — comparaison seule.';
|
||||
$strFlashType = 'bad';
|
||||
} else {
|
||||
$tabConnections = fxStaticSyncOpenConnections();
|
||||
$objSource = $tabConnections['dev_preprod'];
|
||||
@ -48,10 +51,18 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
||||
$strFlash = 'Connexion BD impossible.';
|
||||
$strFlashType = 'bad';
|
||||
} else {
|
||||
$tabResult = fxStaticSyncCopyTable($objSource, $objTarget, $strTable);
|
||||
$tabResult = fxStaticSyncCopyTable($objSource, $objTarget, $strTable, $tabDef);
|
||||
if ($tabResult['ok']) {
|
||||
$tabVerify = fxStaticSyncCompareEnvPair($objSource, $objTarget, $tabDef);
|
||||
$strFlash = $tabDef['label'] . ' → ' . $tabEnv['label'] . ' : ' . $tabResult['message'];
|
||||
$strFlashType = !empty($tabResult['skipped_cols']) ? 'info' : 'ok';
|
||||
if ($tabVerify['status'] === 'ok') {
|
||||
$strFlash .= ' Vérification : aligné.';
|
||||
$strFlashType = 'ok';
|
||||
} else {
|
||||
$strFlash .= ' ATTENTION — après sync, statut : '
|
||||
. fxStaticSyncStatusLabel($tabVerify['status']) . '.';
|
||||
$strFlashType = 'bad';
|
||||
}
|
||||
} else {
|
||||
$strFlash = $tabDef['label'] . ' → ' . $tabEnv['label'] . ' — échec : ' . $tabResult['message'];
|
||||
$strFlashType = 'bad';
|
||||
@ -87,6 +98,8 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
|
||||
.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: #fff3cd; border: 1px solid #ffecb5; padding: 12px 14px; border-radius: 6px; margin-bottom: 16px; font-size: 0.9rem; }
|
||||
.warn-box strong { color: #856404; }
|
||||
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; }
|
||||
@ -94,6 +107,7 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
|
||||
.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; }
|
||||
.count { font-size: 0.82rem; color: #444; margin-top: 4px; }
|
||||
.btn { display: inline-block; margin-top: 6px; padding: 4px 10px; font-size: 0.82rem; border: 1px solid #888; background: #fff; border-radius: 4px; cursor: pointer; text-decoration: none; color: #222; }
|
||||
@ -111,10 +125,15 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
|
||||
<body>
|
||||
|
||||
<h1>Sync tables statiques</h1>
|
||||
<div class="warn-box">
|
||||
<strong>Attention — opération destructive.</strong>
|
||||
Sync = <code>DELETE</code> puis recopie complète depuis dev préprod.
|
||||
Ne pas utiliser vers client prod (bouton désactivé).
|
||||
Si le statut indique <em>Structures non alignées</em>, aligner les structures via Navicat — aucune sync possible tant que ce n'est pas réglé.
|
||||
</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 <strong>client prod</strong>.
|
||||
Le bouton Sync écrase la table cible avec la source.
|
||||
Comparaison vers dev prod, client préprod et client prod (lecture seule pour prod).
|
||||
</p>
|
||||
|
||||
<?php if ($strFlash !== '') { ?>
|
||||
@ -122,9 +141,10 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
|
||||
<?php } ?>
|
||||
|
||||
<div class="legend">
|
||||
<span class="ss-ok">Aligné</span>
|
||||
<span class="ss-ok">Données alignées</span>
|
||||
<span class="ss-warn">Manque ou contenu différent</span>
|
||||
<span class="ss-bad">Lignes en trop</span>
|
||||
<span class="ss-schema">Structures non alignées</span>
|
||||
<span class="ss-muted">Table absente / connexion</span>
|
||||
</div>
|
||||
|
||||
@ -168,11 +188,20 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
|
||||
<div class="count">
|
||||
<?php echo (int)$tabCmp['target_count']; ?> / <?php echo (int)$tabCmp['source_count']; ?> ligne(s)
|
||||
</div>
|
||||
<?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') { ?>
|
||||
<form method="post" style="display:inline;" onsubmit="return confirm('Écraser <?php echo ssEsc($tabDef['table']); ?> sur <?php echo ssEsc($tabEnv['label']); ?> avec la source dev préprod ?');">
|
||||
<?php if ($tabCmp['status'] !== 'no_connection' && $tabCmp['status'] !== 'schema_mismatch' && fxStaticSyncWriteAllowed($strEnvId)) { ?>
|
||||
<form method="post" style="display:inline;" onsubmit="return confirm('DESTRUCTIF : effacer <?php echo ssEsc($tabDef['table']); ?> sur <?php echo ssEsc($tabEnv['label']); ?> (<?php echo ssEsc($tabEnv['config']['db'] ?? ''); ?>) et recopier depuis dev préprod ?');">
|
||||
<input type="hidden" name="action" value="sync">
|
||||
<input type="hidden" name="csrf" value="<?php echo ssEsc($strCsrf); ?>">
|
||||
<input type="hidden" name="table" value="<?php echo ssEsc($tabDef['table']); ?>">
|
||||
@ -198,6 +227,15 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
|
||||
Manquantes : <?php echo count($tabCmp['missing_keys']); ?> —
|
||||
Différences : <?php echo count($tabCmp['diff_keys']); ?> —
|
||||
En trop : <?php echo count($tabCmp['extra_keys']); ?>
|
||||
<?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 !== '') { ?>
|
||||
<br><?php echo ssEsc($strSchemaDiff); ?>
|
||||
<?php } } ?>
|
||||
<a class="btn" href="sync_static_db.php" style="margin-left:12px;">Fermer</a>
|
||||
</p>
|
||||
<?php if (!empty($tabDetail['samples'])) { ?>
|
||||
|
||||
Reference in New Issue
Block a user