Skip to content
Snippets Groups Projects
Commit 8e1af5cc authored by Laurent Lecluse's avatar Laurent Lecluse
Browse files

Nouveau merge avec gestion complète des opérations liées aux historiques (undelete & soft-delete)

parent 4f4d4894
No related branches found
No related tags found
No related merge requests found
Pipeline #32351 passed
...@@ -103,9 +103,9 @@ class DataManager ...@@ -103,9 +103,9 @@ class DataManager
$config['key'] ?? $idCol, $config['key'] ?? $idCol,
$config['options'] ?? [] $config['options'] ?? []
); );
if ($result['insert'] + $result['update'] + $result['delete'] > 0) { if ($result['insert'] + $result['update'] + $result['delete'] + ($result['undelete'] ?? 0) + ($result['soft-delete'] ?? 0) > 0) {
$msg = str_pad($table, 31, ' '); $msg = str_pad($table, 31, ' ');
$msg .= 'Insert: ' . $result['insert'] . ', Update: ' . $result['update'] . ', Delete: ' . $result['delete']; $msg .= 'Insert: ' . ($result['insert'] + ($result['undelete'] ?? 0)) . ', Update: ' . $result['update'] . ', Delete: ' . ($result['delete'] + ($result['soft-delete'] ?? 0));
$this->getBdd()->logMsg($msg); $this->getBdd()->logMsg($msg);
} }
} }
......
...@@ -125,7 +125,7 @@ class Table ...@@ -125,7 +125,7 @@ class Table
'case' => -1, 'case' => -1,
'types' => $this->makeTypesOptions(), 'types' => $this->makeTypesOptions(),
'key' => null, 'key' => null,
'orderBy' => '', 'order-by' => '',
]; ];
$options = array_merge($defaultOptions, $options); $options = array_merge($defaultOptions, $options);
...@@ -146,8 +146,8 @@ class Table ...@@ -146,8 +146,8 @@ class Table
$params = []; $params = [];
$sql .= $this->makeWhere($where, $options, $params); $sql .= $this->makeWhere($where, $options, $params);
if ($options['orderBy']) { if ($options['order-by']) {
$sql .= ' ORDER BY ' . $options['orderBy']; $sql .= ' ORDER BY ' . $options['order-by'];
} }
$select = $this->getBdd()->select($sql, $params, $options); $select = $this->getBdd()->select($sql, $params, $options);
...@@ -418,46 +418,104 @@ class Table ...@@ -418,46 +418,104 @@ class Table
private function mergeDiff(array &$o, array &$n, array &$options): array
{
$diff = [];
foreach ($o as $c => $ov) {
if ($options['has-historique']) {
if ($c == $options['histo-creation-column']
|| $c == $options['histo-createur-id-column']
|| $c == $options['histo-modification-column']
|| $c == $options['histo-modificateur-id-column']
|| $c == $options['histo-destruction-column']
|| $c == $options['histo-destructeur-id-column']
) {
continue; // on ignore les colonnes relatives aux historiques
}
}
$newc = $n[$c] ?? null;
$oldc = $o[$c] ?? null;
if ($newc instanceof \DateTime) $newc = $newc->format('Y-m-d H:i:s');
if ($oldc instanceof \DateTime) $oldc = $oldc->format('Y-m-d H:i:s');
if ($newc != $oldc && array_key_exists($c, $n) && $c != $options['id-column']) {
$ok = empty($options['update-cols']); // OK par défaut si une liste n'a pas été établie manuellement
if (in_array($c, $options['update-cols'])) $ok = true;
if (in_array($c, $options['update-ignore-cols'])) $ok = false;
if (in_array($c, $options['update-only-null']) && $oldc !== null) $ok = false;
if ($ok) {
if ((is_float($newc) || is_double($newc)) && (is_float($oldc) || is_double($oldc))) {
// nécessaire à cause des pb de précision des float/doubles en PHP :
// dans ce cas, on considère quand même que les 2 chiffres sont identiques => diff négligeable
$ok = (abs($newc - $oldc) > 0.0000000001);
}
}
if ($ok) {
$diff[$c] = $n[$c];
}
}
}
return $diff;
}
public function merge(array $data, $key, array $options = []): array public function merge(array $data, $key, array $options = []): array
{ {
$result = ['insert' => 0, 'update' => 0, 'delete' => 0, 'soft-delete' => 0]; $ddl = $this->getDdl();
$bdd = $this->getBdd();
/* Initialisation */ /* Initialisation des options */
$hasHistorique = $this->hasHistorique();
$defaultOptions = [ $defaultOptions = [
'custom-select' => null, 'custom-select' => null,
'where' => null, 'where' => null,
'key' => $key, 'key' => $key,
'delete' => true, 'delete' => true,
'soft-delete' => false, 'soft-delete' => true,
'undelete' => true,
'insert' => true, 'insert' => true,
'update' => true, 'update' => true,
'return-insert-data' => false, 'return-insert-data' => false,
'update-cols' => [], 'update-cols' => [],
'update-ignore-cols' => [], 'update-ignore-cols' => [],
'update-only-null' => [], 'update-only-null' => [],
'id-column' => $bdd->getOption(Bdd::OPTION_ID_COLUMN),
'has-historique' => $hasHistorique,
'histo-user-id' => null,
'histo-date' => new \DateTime(),
]; ];
if ($hasHistorique) {
$defaultOptions['histo-user-id'] = $bdd->getHistoUserId();
$defaultOptions['histo-creation-column'] = $bdd->getOption(Bdd::OPTION_HISTO_CREATION_COLUMN);
$defaultOptions['histo-createur-id-column'] = $bdd->getOption(Bdd::OPTION_HISTO_CREATEUR_ID_COLUMN);
$defaultOptions['histo-modification-column'] = $bdd->getOption(Bdd::OPTION_HISTO_MODIFICATION_COLUMN);
$defaultOptions['histo-modificateur-id-column'] = $bdd->getOption(Bdd::OPTION_HISTO_MODIFICATEUR_ID_COLUMN);
$defaultOptions['histo-destruction-column'] = $bdd->getOption(Bdd::OPTION_HISTO_DESTRUCTION_COLUMN);
$defaultOptions['histo-destructeur-id-column'] = $bdd->getOption(Bdd::OPTION_HISTO_DESTRUCTEUR_ID_COLUMN);
$result = ['insert' => 0, 'update' => 0, 'delete' => 0, 'soft-delete' => 0, 'undelete' => 0];
} else {
$result = ['insert' => 0, 'update' => 0, 'delete' => 0];
}
$options = array_merge($defaultOptions, $options); $options = array_merge($defaultOptions, $options);
if ($options['return-insert-data']) { if ($options['return-insert-data']) {
$result['insert-data'] = []; $result['insert-data'] = [];
} }
$ddl = $this->getDdl();
$bdd = $this->getBdd();
$histoUserId = $bdd->getHistoUserId(); if ($hasHistorique && (null === $options['histo-user-id'])) {
$hasHistorique = $this->hasHistorique(); throw new \Exception('L\'id de l\'utilisateur pour la gestion des historiques doit être fourni en configuration ou bien en option');
$idCol = $this->getBdd()->getOption(Bdd::OPTION_ID_COLUMN);
if (empty($options['where']) && $hasHistorique) {
$histoDestructionCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_DESTRUCTION_COLUMN);
$options['where'] = $histoDestructionCol . ' IS NULL';
} }
/* Mise en forme des nouvelles données */ /* Mise en forme des nouvelles données */
$new = []; $new = [];
foreach ($data as $d) { foreach ($data as $i => $d) {
foreach ($d as $c => $v) { foreach ($d as $c => $v) {
if (isset($ddl['columns'][$c])) { if (isset($ddl['columns'][$c])) {
if (isset($options['columns'][$c]['transformer'])) { if (isset($options['columns'][$c]['transformer'])) {
...@@ -482,73 +540,90 @@ class Table ...@@ -482,73 +540,90 @@ class Table
$selOptions['fetch'] = Bdd::FETCH_EACH; $selOptions['fetch'] = Bdd::FETCH_EACH;
$stmt = $this->select($options['where'], $selOptions); $stmt = $this->select($options['where'], $selOptions);
while ($o = $stmt->next()) { while ($o = $stmt->next()) {
// récupération de k et n // récupération de k et n & on détermine quelle action effectuer
$k = $this->makeKey($o, $key); $k = $this->makeKey($o, $key);
$action = null; // rien à faire par défaut
if (array_key_exists($k, $new)) { if (array_key_exists($k, $new)) {
$n = $new[$k]; $n = $new[$k];
unset($new[$k]); unset($new[$k]); // on retire de suite du tableau
} else { $diff = $this->mergeDiff($o, $n, $options);
$n = null; if (!empty($diff)) {
if ($options['update']) {
$action = 'update';
} }
} elseif ($hasHistorique) {
if (empty($n) && $options['soft-delete'] && $hasHistorique && $histoUserId !== null) { // SOFT DELETE if ($options['undelete'] && array_key_exists($options['histo-destruction-column'], $o) && $o[$options['histo-destruction-column']]) {
$histoDestructionCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_DESTRUCTION_COLUMN); $action = 'undelete';
$histoDestructeurIdCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_DESTRUCTEUR_ID_COLUMN);
//On ne delete pas mais on historise
$n = $o;
$n[$histoDestructionCol] = new \DateTime();
$n[$histoDestructeurIdCol] = $histoUserId;
$this->update($n, $this->makeKeyArray($o, $k));
$result['soft-delete']++;
} elseif (empty($n) && !$options['soft-delete']) { // DELETE
if ($options['delete']) {
$this->delete($this->makeKeyArray($o, $key));
$result['delete']++;
} }
} elseif ($options['update']) { // UPDATE si différent!!
$toUpdate = [];
foreach ($o as $c => $ov) {
$newc = $n[$c] ?? null;
$oldc = $o[$c] ?? null;
if ($newc instanceof \DateTime) $newc = $newc->format('Y-m-d H:i:s');
if ($oldc instanceof \DateTime) $oldc = $oldc->format('Y-m-d H:i:s');
if ($newc != $oldc && array_key_exists($c, $n) && $c != $idCol) {
$ok = empty($options['update-cols']); // OK par défaut si une liste n'a pas été établie manuellement
if (in_array($c, $options['update-cols'])) $ok = true;
if (in_array($c, $options['update-ignore-cols'])) $ok = false;
if (in_array($c, $options['update-only-null']) && $oldc !== null) $ok = false;
if ($ok) {
if ((is_float($newc) || is_double($newc)) && (is_float($oldc) || is_double($oldc))) {
if (abs($newc - $oldc) > 0.0000000001) {
// nécessaire à cause des pb de précision des float/doubles en PHP :
// dans ce cas, on considère quand même que les 2 chiffres sont identiques
$toUpdate[$c] = $n[$c];
} }
} else { } else {
$toUpdate[$c] = $n[$c]; if ($options['has-historique']) {
if (null === $o[$options['histo-destruction-column']]) {
// opération de soft-delete
if ($options['soft-delete']) {
$action = 'soft-delete';
}
} }
} else {
// opération de delete
if ($options['delete']) {
$action = 'delete';
} }
} }
} }
if (!empty($toUpdate)) {
// on effectue l'action
if ($action) {
switch ($action) {
case 'delete':
$this->delete($this->makeKeyArray($o, $key));
break;
case 'soft-delete':
$toUpdate = [
$options['histo-destruction-column'] => $options['histo-date'],
$options['histo-destructeur-id-column'] => $options['histo-user-id'],
];
$this->update($toUpdate, $this->makeKeyArray($o, $key), ['ddl' => $ddl]); $this->update($toUpdate, $this->makeKeyArray($o, $key), ['ddl' => $ddl]);
$result['update']++;
break;
case 'undelete':
$toUpdate = [
$options['histo-destruction-column'] => null,
$options['histo-destructeur-id-column'] => null,
];
$this->update($toUpdate, $this->makeKeyArray($o, $key), ['ddl' => $ddl]);
break;
case 'update':
$toUpdate = $diff;
if ($hasHistorique) {
$toUpdate[$options['histo-modification-column']] = $options['histo-date'];
$toUpdate[$options['histo-modificateur-id-column']] = $options['histo-user-id'];
} }
$this->update($toUpdate, $this->makeKeyArray($o, $key), ['ddl' => $ddl]);
break;
}
$result[$action]++;
} }
} }
/* Pour finir, insertion de tous les nouveaux éléments */ /* Pour finir, insertion de tous les nouveaux éléments */
foreach ($new as $k => $n) { foreach ($new as $k => $n) {
if ($options['insert']) { if ($options['insert']) {
if ($hasHistorique) {
$n[$options['histo-creation-column']] = $options['histo-date'];
$n[$options['histo-createur-id-column']] = $options['histo-user-id'];
$n[$options['histo-modification-column']] = $options['histo-date'];
$n[$options['histo-modificateur-id-column']] = $options['histo-user-id'];
}
$this->insert($n); $this->insert($n);
$result['insert']++; $result['insert']++;
if ($options['return-insert-data']) { if ($options['return-insert-data']) {
$insertedData = []; $insertedData = [];
if (isset($n[$idCol])) { if (isset($n[$options['id-column']])) {
$insertedData[$idCol] = $n[$idCol]; $insertedData[$options['id-column']] = $n[$options['id-column']];
} }
foreach ($key as $null => $kc) { foreach ($key as $null => $kc) {
$insertedData[$kc] = $n[$kc]; $insertedData[$kc] = $n[$kc];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment