From b5e8a642ba5d922c4a0e6f8b6bc2d1f3a07d9a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20L=C3=A9cluse?= <laurent.lecluse@unicaen.fr> Date: Mon, 26 Aug 2024 13:56:17 +0200 Subject: [PATCH] =?UTF-8?q?-=20[Fix]=20Test=20de=20comparaison=20des=20flo?= =?UTF-8?q?at=20&=20doubles=20tenant=20compte=20des=20probl=C3=A9matiques?= =?UTF-8?q?=20d'arrondis=20de=20PHP=20-=20Dans=20le=20Table->merge,=20poss?= =?UTF-8?q?ibilit=C3=A9=20de=20d=C3=A9finir=20une=20requ=C3=AAte=20personn?= =?UTF-8?q?alis=C3=A9e=20pour=20les=20cas=20complexes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++ src/Table.php | 115 +++++++++++++++++++++++++++++--------------------- 2 files changed, 75 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0193a2..dff6d80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +branche modernisation-gestion-donnees +------------------------------------- + +- [Fix] Test de comparaison des float & doubles tenant compte des problématiques d'arrondis de PHP +- Dans le Table->merge, possibilité de définir une requête personnalisée pour les cas complexes + + 0.9.8 (22/08/2024) ------------------ diff --git a/src/Table.php b/src/Table.php index 6e86dcf..8599da0 100644 --- a/src/Table.php +++ b/src/Table.php @@ -3,7 +3,6 @@ namespace Unicaen\BddAdmin; - class Table { @@ -40,11 +39,11 @@ class Table public function getDdl(): array { if (empty($this->ddl)) { - $sTable = $this->getBdd()->table(); + $sTable = $this->getBdd()->table(); $this->ddl = $sTable->get($this->name)[$this->name]; } - if (!$this->ddl){ - throw new \Exception('La DDL de la table '.$this->name.' n\'a pas pu être calculée'); + if (!$this->ddl) { + throw new \Exception('La DDL de la table ' . $this->name . ' n\'a pas pu être calculée'); } return $this->ddl; @@ -63,7 +62,7 @@ class Table public function hasHistorique(): bool { - $ddl = $this->getDdl(); + $ddl = $this->getDdl(); $hasHisto = isset($ddl['columns']['HISTO_CREATION']) && isset($ddl['columns']['HISTO_MODIFICATION']) && isset($ddl['columns']['HISTO_DESTRUCTION']) @@ -78,7 +77,7 @@ class Table public function hasImport(): bool { - $ddl = $this->getDdl(); + $ddl = $this->getDdl(); $hasImport = isset($ddl['columns']['SOURCE_ID']) && isset($ddl['columns']['SOURCE_CODE']); @@ -101,16 +100,17 @@ class Table - public function select( array|int|null $where = null, array $options = []): array|null|SelectParser + public function select(array|int|null $where = null, array $options = []): array|null|SelectParser { /* Initialisation des entrées */ $defaultOptions = [ - 'fetch' => Bdd::FETCH_ALL, - 'types' => $this->makeTypesOptions(), - 'key' => null, - 'orderBy' => '', + 'custom-select' => null, + 'fetch' => Bdd::FETCH_ALL, + 'types' => $this->makeTypesOptions(), + 'key' => null, + 'orderBy' => '', ]; - $options = array_merge($defaultOptions, $options); + $options = array_merge($defaultOptions, $options); $ddl = $this->getDdl(); @@ -120,9 +120,14 @@ class Table if ($cols != '') $cols .= ', '; $cols .= $colDdl['name'] ?? $cname; } - $sql = "SELECT $cols FROM ".$this->name; + $sql = "SELECT $cols FROM "; + if ($options['custom-select']) { + $sql .= "(" . $options['custom-select'] . ") t"; + } else { + $sql .= $this->name; + } $params = []; - $sql .= $this->makeWhere($where, $options, $params); + $sql .= $this->makeWhere($where, $options, $params); if ($options['orderBy']) { $sql .= ' ORDER BY ' . $options['orderBy']; @@ -133,7 +138,7 @@ class Table /* Mise en forme des résultats */ $data = []; foreach ($select as $d) { - $keyValue = $this->makeKey($d, $options['key']); + $keyValue = $this->makeKey($d, $options['key']); $data[$keyValue] = $d; } @@ -150,7 +155,7 @@ class Table $options = ['types' => $this->makeTypesOptions(), 'fetch' => Bdd::FETCH_EACH]; $count = (int)$source->select('SELECT count(*) C FROM ' . $this->getName(), [], ['fetch' => Bdd::FETCH_ONE])['C']; - $r = $source->select('SELECT * FROM ' . $this->getName(), [], $options); + $r = $source->select('SELECT * FROM ' . $this->getName(), [], $options); if (!$this->getBdd()->isInCopy()) { $this->getBdd()->logBegin("Copie de la table " . $this->getName()); @@ -189,7 +194,7 @@ class Table $options = ['types' => $this->makeTypesOptions(), 'fetch' => Bdd::FETCH_EACH]; $count = (int)$this->getBdd()->select('SELECT count(*) C FROM ' . $this->getName(), [], ['fetch' => Bdd::FETCH_ONE])['C']; - $r = $this->getBdd()->select('SELECT * FROM ' . $this->getName(), [], $options); + $r = $this->getBdd()->select('SELECT * FROM ' . $this->getName(), [], $options); if (!$this->getBdd()->isInCopy()) { $this->getBdd()->logBegin("Sauvegarde de la table " . $this->getName()); @@ -237,10 +242,10 @@ class Table $this->getBdd()->logBegin("Restauration de la table " . $this->getName()); } - $buff = fopen($filename, 'r'); - $count = fgets($buff); - $count = (int)trim($count); - $data = ''; + $buff = fopen($filename, 'r'); + $count = fgets($buff); + $count = (int)trim($count); + $data = ''; $current = 0; $this->getBdd()->beginTransaction(); while (($d = fgets($buff)) !== false) { @@ -305,8 +310,8 @@ class Table if (!isset($data['SOURCE_ID'])) $data['SOURCE_ID'] = $sourceId; } - $cols = []; - $vals = []; + $cols = []; + $vals = []; $params = []; foreach ($data as $col => $val) { $transformer = isset($options['columns'][$col]['transformer']) ? $options['columns'][$col]['transformer'] : null; @@ -322,7 +327,7 @@ class Table $cols = implode(", ", $cols); $vals = implode(", ", $vals); - $sql = "INSERT INTO ".$this->name." ($cols) VALUES ($vals)"; + $sql = "INSERT INTO " . $this->name . " ($cols) VALUES ($vals)"; return $bdd->exec($sql, $params, $this->makeTypesOptions()); } @@ -349,11 +354,11 @@ class Table if (isset($options['columns'][$col]['transformer'])) { $transVal = '(' . sprintf($options['columns'][$col]['transformer'], $transVal) . ')'; } - $dataSql .= $col . '=' . $transVal; + $dataSql .= $col . '=' . $transVal; $params['new_' . $col] = $val; } - $sql = "UPDATE ".$this->name." SET $dataSql" . $this->makeWhere($where, $options, $params); + $sql = "UPDATE " . $this->name . " SET $dataSql" . $this->makeWhere($where, $options, $params); return $bdd->exec($sql, $params, $this->makeTypesOptions()); } @@ -363,7 +368,7 @@ class Table public function delete(int|string|array|null $where = null, array $options = []): bool { $params = []; - $sql = "DELETE FROM ".$this->name . $this->makeWhere($where, $options, $params); + $sql = "DELETE FROM " . $this->name . $this->makeWhere($where, $options, $params); return $this->getBdd()->exec($sql, $params); } @@ -372,7 +377,7 @@ class Table public function truncate(): bool { - $sql = "TRUNCATE TABLE ".$this->name; + $sql = "TRUNCATE TABLE " . $this->name; return $this->getBdd()->exec($sql); } @@ -385,20 +390,21 @@ class Table /* Initialisation */ $defaultOptions = [ + 'custom-select' => null, 'where' => null, 'key' => $key, 'delete' => true, 'soft-delete' => false, 'insert' => true, 'update' => true, - 'return-insert-data' => false, + 'return-insert-data' => false, 'update-cols' => [], 'update-ignore-cols' => [], 'update-only-null' => [], ]; - $options = array_merge($defaultOptions, $options); + $options = array_merge($defaultOptions, $options); - if ($options['return-insert-data']){ + if ($options['return-insert-data']) { $result['insert-data'] = []; } @@ -408,7 +414,7 @@ class Table $histoUserId = (int)$bdd->getOption('histo-user-id'); $hasHistorique = $this->hasHistorique(); - if (empty($options['where']) && $hasHistorique){ + if (empty($options['where']) && $hasHistorique) { $options['where'] = 'HISTO_DESTRUCTION IS NULL'; } @@ -441,18 +447,18 @@ class Table while ($o = $stmt->next()) { // récupération de k et n $k = $this->makeKey($o, $key); - if (array_key_exists($k, $new)){ + if (array_key_exists($k, $new)) { $n = $new[$k]; unset($new[$k]); - }else{ + } else { $n = null; } if (empty($n) && $options['soft-delete'] && $hasHistorique && $histoUserId) { // SOFT DELETE //On ne delete pas mais on historise - $n = $o; + $n = $o; $n['HISTO_DESTRUCTEUR_ID'] = $histoUserId; - $n['HISTO_DESTRUCTION'] = new \DateTime(); + $n['HISTO_DESTRUCTION'] = new \DateTime(); $this->update($n, $this->makeKeyArray($o, $k)); $result['soft-delete']++; } elseif (empty($n) && !$options['soft-delete']) { // DELETE @@ -475,7 +481,14 @@ class Table if (in_array($c, $options['update-only-null']) && $oldc !== null) $ok = false; if ($ok) { - $toUpdate[$c] = $n[$c]; + if ((is_float($newc) || is_double($newc)) + && (is_float($oldc) || is_double($oldc)) + && 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]; + } } } } @@ -487,12 +500,20 @@ class Table } /* Pour finir, insertion de tous les nouveaux éléments */ - foreach( $new as $k => $n ){ + foreach ($new as $k => $n) { if ($options['insert']) { $this->insert($n); $result['insert']++; - if ($options['return-insert-data']){ - $result['insert-data'][] = $n; + if ($options['return-insert-data']) { + $insertedData = []; + if (isset($n['ID'])) { + $insertedData['ID'] = $n['ID']; + } + foreach ($key as $null => $kc) { + $insertedData[$kc] = $n[$kc]; + } + + $result['insert-data'][$k] = $insertedData; } } } @@ -504,7 +525,7 @@ class Table - private function makeKeyArray(array $data, $key): array + private function makeKeyArray(array $data, array|string|null $key = null): array { if (!$key && $this->hasId()) { $key = 'ID'; @@ -521,7 +542,7 @@ class Table - private function makeKey(array $data, $key): string + public function makeKey(array $data, array|string|null $key): string { $keyArray = $this->makeKeyArray($data, $key); @@ -570,16 +591,16 @@ class Table if (isset($options['columns'][$c]['transformer'])) { - $transVal = ':' . $c; - $transVal = '(' . sprintf($options['columns'][$c]['transformer'], $transVal) . ')'; - $whereSql .= $c . ' = ' . $transVal; + $transVal = ':' . $c; + $transVal = '(' . sprintf($options['columns'][$c]['transformer'], $transVal) . ')'; + $whereSql .= $c . ' = ' . $transVal; $params[$c] = $v; } else { if ($v === null) { $whereSql .= $c . ' IS NULL'; } else { - $transVal = ':' . $c; - $whereSql .= $c . ' = ' . $transVal; + $transVal = ':' . $c; + $whereSql .= $c . ' = ' . $transVal; $params[$c] = $v; } } -- GitLab