Commit 432155ab authored by Laurent Lecluse's avatar Laurent Lecluse
Browse files

Nouvel outil Comparator

parent 81a86e5f
Loading
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
1.4.0 (16/04/2025)
------------------

- [Nouvel outil Comparator](doc/tools/comparator.md)


1.3.1 (25/03/2025)
------------------

+78 −0
Original line number Diff line number Diff line
# Comparator

Le comparator permet de lister les différences entre deux requêtes et de les afficher en HTML le cas échéant.

Exemple d'usage du comparator :

```php

/**
 * @var $container  \Psr\Container\ContainerInterface
 */

$bdd = $container->get(\Unicaen\BddAdmin\Bdd::class);
$comparator = new \Unicaen\BddAdmin\Tools\Comparator($bdd);


$sql1 = "SELECT * FROM v_contrat_main_old";

$sql2 = "SELECT * FROM v_contrat_main";

$keyCols = ['CONTRAT_ID']; // liste de colonnes permettant d'établir la correspondance entre les deux requêtes

$ignoreCols = [ // on peut ignorer des colonnes pour lesquelles il y a des différences qu'on estime "normales" ou qui sont à étudier pour + tard
    'FORMULE_RESULTAT_ID', // colonne supprimée
    'totalDiviseParDix',   // colonne supprimée
    'tauxId',              // colonne supprimée
    'tauxMajoreId',        // colonne supprimée

    'heuresPeriodeEssai',   // nouvelle colonne
    'heuresPrimePrecarite', // nouvelle colonne

    'horodatage',          // dates générées à partir de NOW => pas de pb

    'date_creation',         // formatage pourri ancienne => Ok maintenant
    'date_contrat_lie',      // formatage pourri ancienne => Ok maintenant
    'tauxHoraireDate',       // formatage pourri ancienne => Ok maintenant
    'tauxMajoreHoraireDate', // colonne vide avant

    'heuresFormation', // toutes vides ancienne vue

    'enteteAutresHeures',  // problèmes trouvés dans ancienne vue v_contrat_main
    'legendeAutresHeures', // problèmes trouvés dans ancienne vue v_contrat_main

    'pays_nationalite', // colonnes vides dans ancienne, car on ne prenait en compte que les données perso sans tenir compte de la table intervenant

    'serviceTotalPaye', // le nouvel calcul met le taux de CP à 0 pour les enseignements, pas l'ancienne vue

    /* à contrôler + finement */
    'titreCourt', // lié au pb parentalité des avenants ??
    'totalHETD',  // arrondis à retester ?
    //avenant1	contrat1	modifieComplete	n	titre reste => avenants qui se transforment en contrat et vice versa ??
    // contrats concernés : 2479, 40336, 36972, 36028, 19628, 1912, 1854

];

$onlyCols = [ // On peut cibler sur certaines collonnes uniquement afin de ne pas être noyé dans les différences à examiner
    //'hetdContrat'
];

// On injecte tout ça dans le comparator
$comparator->setQuery1($sql1);
$comparator->setQuery2($sql2);
$comparator->setKeyColumns($keyCols);
$comparator->setIgnoreColumns($ignoreCols);
$comparator->setOnlyColumns($onlyCols);
// limit est à 1000 par défaut, mais il est redéfini ici à titre d'exemple
$comparator->setLimit(1000);

// On lance l'outil qui nous retourne un array en résultat
$result = $comparator->run();

// on peut transformer cet array en HTML pour affichage
echo $comparator->html($result);
```

Et voici un exemple de résultat :

![Capture d'écran](comparator.png)
 No newline at end of file
+70.8 KiB
Loading image diff...
+304 −0
Original line number Diff line number Diff line
<?php

namespace Unicaen\BddAdmin\Tools;

use Unicaen\BddAdmin\Bdd;
use Unicaen\BddAdmin\BddAwareTrait;

class Comparator
{
    use BddAwareTrait;

    private string $query1;

    private string $query2;

    private array $keyColumns = [];

    private array $onlyColumns = [];

    private array $ignoreColumns = [];

    private int $limit = 1000;



    public function __construct(Bdd $bdd)
    {
        $this->bdd = $bdd;
    }



    public function getQuery1(): string
    {
        return $this->query1;
    }



    public function setQuery1(string $query1): Comparator
    {
        $this->query1 = $query1;
        return $this;
    }



    public function getQuery2(): string
    {
        return $this->query2;
    }



    public function setQuery2(string $query2): Comparator
    {
        $this->query2 = $query2;
        return $this;
    }



    public function getKeyColumns(): array
    {
        return $this->keyColumns;
    }



    public function setKeyColumns(array $keyColumns): Comparator
    {
        $this->keyColumns = $keyColumns;
        return $this;
    }



    public function getOnlyColumns(): array
    {
        return $this->onlyColumns;
    }



    public function setOnlyColumns(array $onlyColumns): Comparator
    {
        $this->onlyColumns = $onlyColumns;
        return $this;
    }



    public function getIgnoreColumns(): array
    {
        return $this->ignoreColumns;
    }



    public function setIgnoreColumns(array $ignoreColumns): Comparator
    {
        $this->ignoreColumns = $ignoreColumns;
        return $this;
    }



    public function getLimit(): int
    {
        return $this->limit;
    }



    public function setLimit(int $limit): Comparator
    {
        $this->limit = $limit;
        return $this;
    }



    public function run(): array
    {
        $diffCols = [];

        $cols = [];
        $data = [];

        $count1 = 0;
        $count2 = 0;

        $p1    = $this->getBdd()->selectEach($this->getQuery1());
        $first = true;
        while ($line = $p1->next()) {
            $count1++;
            if ($first) {
                $cols = array_keys($line);
            }
            $k = $this->key($line);
            if (!array_key_exists($k, $data)) {
                $data[$k] = ['key' => $this->keyArray($line)];
            }
            foreach ($line as $col => $value) {
                if (in_array($col, $this->keyColumns) || in_array($col, $this->ignoreColumns)) {
                    unset($line[$col]);
                }
                if (!empty($this->onlyColumns) && !in_array($col, $this->onlyColumns)) {
                    unset($line[$col]);
                }
                if ($value == null) {
                    unset($line[$col]);
                }
            }
            $data[$k][1] = $line;
            $first       = false;
        }

        $p2    = $this->getBdd()->selectEach($this->getQuery2());
        $first = true;
        while ($line = $p2->next()) {
            $count2++;
            if ($first) {
                foreach ($line as $col => $null) {
                    if (!in_array($col, $cols)) {
                        $cols[] = $col;
                    }
                }
            }
            $k = $this->key($line);
            if (!array_key_exists($k, $data)) {
                $data[$k] = ['key' => $this->keyArray($line)];
            }
            foreach ($line as $col => $value) {
                if (in_array($col, $this->keyColumns) || in_array($col, $this->ignoreColumns)) {
                    unset($line[$col]);
                }
                if (!empty($this->onlyColumns) && !in_array($col, $this->onlyColumns)) {
                    unset($line[$col]);
                }
                if ($value == null) {
                    unset($line[$col]);
                }
            }
            $data[$k][2] = $line;
            $first       = false;
        }

        foreach ($data as $k => $vs) {
            foreach ($cols as $col) {
                $v1 = isset($vs[1][$col]) ? $vs[1][$col] : null;
                $v2 = isset($vs[2][$col]) ? $vs[2][$col] : null;

                if ($v1 == $v2) {
                    unset($data[$k][1][$col]);
                    unset($data[$k][2][$col]);
                } else {
                    if (!in_array($col, $diffCols)) {
                        $diffCols[] = $col;
                    }
                }
            }

            if (empty($data[$k][1]) && empty($data[$k][2])) {
                unset($data[$k]);
            }
        }

        sort($diffCols);

        return [
            'diffCols' => $diffCols,
            'data'     => $data,
            'count1'   => $count1,
            'count2'   => $count2,
        ];
    }



    private function key(array $data): string
    {
        $key = '';
        foreach ($this->keyColumns as $col) {
            if ($key != '') $key .= '-';
            if (isset($data[$col])) {
                $key .= $data[$col];
            }
        }

        return $key;
    }



    private function keyArray(array $data): array
    {
        $key = [];
        foreach ($this->keyColumns as $col) {
            $key[$col] = isset($data[$col]) ? $data[$col] : null;
        }
        return $key;
    }



    public function html(array $result): string
    {
        if (!array_key_exists('diffCols', $result) || !array_key_exists('data', $result)) {
            throw new \Exception('Le tableau de données doit être un retour de Comparator->run');
        }

        $diffCols = $result['diffCols'];
        $data     = $result['data'];
        $r = '';
        if (count($data) > 0) {
            $r .= '';
            $r .= '<table class="table table-bordered table-xs">';
            $r .= '<thead>';
            $r .= '<tr>';
            foreach ($this->keyColumns as $col) {
                $r .= '<th rowspan="2">' . $col . '</th>';
            }
            foreach ($diffCols as $col) {
                $r .= '<th colspan="2" style="border-left-width: 2px">' . $col . '</th>';
            }
            $r .= '</tr>';
            $r .= '<tr>';
            foreach ($diffCols as $col) {
                $r .= '<th style="text-align: center;border-left-width: 2px">1</th>';
                $r .= '<th style="text-align: center">2</th>';
            }
            $r     .= '</tr>';
            $r     .= '</thead>';
            $r     .= '<tbody>';
            $count = 0;
            foreach ($data as $k => $v) {
                $count++;
                if ($count > $this->limit) {
                    break;
                }
                $r .= '<tr>';
                foreach ($this->keyColumns as $col) {
                    $r .= '<th>' . $v['key'][$col] . '</th>';
                }
                foreach ($diffCols as $col) {
                    $r .= '<td style="border-left-width: 2px">' . (isset($v[1][$col]) ? $v[1][$col] : '') . '</td>';
                    $r .= '<td>' . (isset($v[2][$col]) ? $v[2][$col] : '') . '</td>';
                }
                $r .= '</tr>';
            }
            $r .= '</tbody>';
            $r .= '</table>';
        }else{
            echo 'Aucune différence notée!!!<br />';
        }
        if (count($data) > $this->limit){
            $r .= $this->limit.' lignes affichées sur '.count($data).' au total présentant des différences<br />';
        }
        $r .= $result['count1'].' lignes issues de la requête 1<br />';
        $r .= $result['count2'].' lignes issues de la requête 2<br />';
        return $r;
    }
}