Commit 3265d626 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

La source peut désormais être une API (web service)

parent 58224b3f
Loading
Loading
Loading
Loading
+212 −157
Original line number Diff line number Diff line
UnicaenDbImport
===============

Ce module a pour but de réaliser l'import de données d'une table (ou d'un select) d'une base de données source vers une 
table d'une base de données destination.
 * [Introduction](#introduction)
 * [La différence avec le module UnicaenImport ?](#la-différence-avec-le-module-unicaenimport-)
 * [Installation](#installation)
 * [Configuration](#configuration)
 * [Utilisation](#utilisation)
 * [Contraintes](#contraintes)
 * [Fonctionnement](#fonctionnement)
 * [Exemples](#exemples)
   1. [Import d'une table de données distantes](#exemple-1-importation-dune-table-de-données-distantes)
   2. [Import d'un select de données distantes](#exemple-2-importation-dun-select-de-données-distantes)
   3. [Synchronisation de données locales](#exemple-3-synchronisation-de-données-locales)
   4. [Synchronisation de données distantes](#exemple-4-synchronisation-de-données-distantes)
   5. [Synchronisation de données distantes avec récupération des clés étrangères](#exemple-5-synchronisation-de-données-distantes-avec-récupération-des-clés-étrangères)
   6. [[Bonus] Appliquer un CRON](#exemple-z-appliquer-un-cron)
 
*NB: Refonte en cours, plus d'information sur l'ancien moteur (peut être encore actuel) d'UnicaenDbImport en [cliquant ici](https://git.unicaen.fr/lib/unicaen/db-import/tree/2ceb3a7e#dans-le-moteur).*
 
 
Introduction
------------

Ce module réalise l'import et/ou la synchronisation de données *sources* vers une table d'une base de données 
*destination*. 

Concrètement :
La source peut être :
- soit une base de données (une table ou un "select"), 
- soit une API (web service).

Principe de l'*import* :
  - La table destination est vidée systématiquement (truncate).
  - Les données obtenues de la source sont insérées dans la table destination.

Principe de la *synchronisation* :

  - Si la source contient un enregistrement qui n'existe pas dans la destination, il est ajouté dans cette dernière.
  - Si la source contient un enregistrement qui existe aussi dans la destination avec les mêmes valeurs de colonnes, 
@@ -16,45 +45,25 @@ Concrètement :
  - Si la source contient un enregistrement qui existe aussi dans la destination mais marqué "supprimé", ce dernier est 
    dé-historisé.

Les enregistrements source et les enregistrements destination doivent avoir un identifiant unique en commun permettant 
Les données source et les enregistrements destination doivent avoir un identifiant unique en commun permettant 
de les rapprocher : on l'appellera "code source" (cf. paramètre de config `source_code_column`). 
**Cet identifiant doit être de type chaîne de caractères.**

__**Table des matières**__


 * [La différence avec le module UnicaenImport ?](#la-différence-avec-le-module-unicaenimport-)
 * [Installation](#installation)
 * [Configuration](#configuration)
 * [Utilisation](#utilisation)
 * [Contraintes](#contraintes)
 * [Fonctionnement](#fonctionnement)
 * [Exemples](#exemples)
   1. [Importation d'une table de données distantes](#exemple-1-importation-dune-table-de-données-distantes)
   2. [Importation d'un select de données distantes](#exemple-2-importation-dun-select-de-données-distantes)
   3. [Synchronisation de données locales](#exemple-3-synchronisation-de-données-locales)
   4. [Synchronisation de données distantes](#exemple-4-synchronisation-de-données-distantes)
   5. [Synchronisation de données distantes avec récupération des clés étrangères](#exemple-5-synchronisation-de-données-distantes-avec-récupération-des-clés-étrangères)
   6. [[Bonus] Appliquer un CRON](#exemple-z-appliquer-un-cron)
 
**Cet identifiant DOIT être de type chaîne de caractères.**

*NB: Refonte en cours, plus d'information sur l'ancien moteur (peut être encore actuel) d'UnicaenDbImport en [cliquant ici](https://git.unicaen.fr/lib/unicaen/db-import/tree/2ceb3a7e#dans-le-moteur).*

La différence avec le module UnicaenImport ?
--------------------------------------------
  
 Comme son nom ne l'indique pas, UnicaenImport fonctionne uniquement entre 
 2 bases de données **Oracle** ; et la synchronisation est faite entièrement par le SGBD (ou presque).
Comme son nom ne l'indique pas, UnicaenImport fonctionne uniquement entre 2 bases de données **Oracle**.

 UnicaenDbImport fonctionne en majeure partie en PHP tout en déléguant au maximum au SGBD ce qu'il sait bien faire 
 (`select FULL OUTER JOIN` pour le différentiel entre données source et destination, fonction pour l'alimentation du registre 
 d'import, etc.) Par conséquent, il est possible et souhaitable de l'enrichir pour implémenter une synchronisation vers 
 différentes plateformes de base de données destination. Les plateformes de base de données destination suivantes sont 
 implémentées :
UnicaenDbImport fonctionne en majeure partie en PHP, tout en déléguant au maximum au SGBD ce qu'il sait bien faire 
(`select FULL OUTER JOIN` pour le différentiel entre données source et destination, par exemple). 
Par conséquent, il est possible et souhaitable de l'enrichir pour implémenter un import/synchronisation vers 
différentes plateformes de base de données destination. 
Les plateformes de base de données destination suivantes sont implémentées :
  - PostgreSQL

*NB: En revanche toutes les plateformes de base de données source sont supportées car on se contente d'y faire un select 
 à l'aide de l'ORM Doctrine 2 pour alimenter une table intermédiaire.*
pour alimenter une table intermédiaire.*
 
 
Installation
@@ -74,7 +83,7 @@ cp -n vendor/unicaen/db-import/config/unicaen-db-import.local.php.dist config/au

- Adapter leur contenu à vos besoins.

- Configuration nécesaire en cas d'utilisation de bjyauthorize :
- Configuration nécessaire en cas d'utilisation du module unicaen/bjy-authorize :

```php
'bjyauthorize'    => [
@@ -126,8 +135,9 @@ Le module fournit donc une ligne de commande pour lancer :
    public/index.php run synchro --all
    ```

*NB: L'exécution d'une de ces commandes n'est effectif qu'une fois. Pour importer/synchroniser en permanence (dans) la base de données destination, 
il faut programmer le lancement périodique de cette commande à l'aide de CRON (cf. plus bas pour un exemple).*
*NB: L'exécution d'une de ces commandes n'est effectif qu'une fois. Pour importer/synchroniser en permanence (dans) 
la base de données destination, il faut programmer le lancement périodique de cette commande à l'aide de CRON.* 
Exemple : `*/15 6-19 * * 1-5 root /usr/bin/php /path/to/app/public/index.php run import --all 1> /tmp/zebu-cron.log 2>&1`


Contraintes
@@ -135,28 +145,8 @@ Contraintes

### Identifiant commun

L'identifiant unique commun des enregistrements (source_code_column) source et destination doit être de type **chaîne de caractères**.

### Source de type `'select'`

Dans le cas d'une *source* de type `'select'`, il est nécessaire de convertir chaque colonne en 
**chaîne de caractères** dans le `select`.

- Pour une colonne de type "date", `TO_CHAR(nom_colonne,'YYYY-MM-DD')` permet de convertir 
  en chaînes de caractères dans un format quasi universel ;
- Pour une colonne de type numérique, `nom_colonne||''` permet par exemple de convertir
  entiers et décimaux en chaînes de caractères.

Il est également nécessaire de spécifier dans la config de la *destination* la fonction de conversion à appliquer 
à chaque colonne pour la convertir en chaîne de caractères (cf. paramètre de config destination `columns_to_char`).

_Note : Peut être pas obligé de faire la convertion TO_CHAR dans le SELECT (mais quand même le faire dans le columns_to_char)._

### Source de type `'table'`
    
Dans le cas d'une *source* de type `'table'`, il est nécessaire de spécifier dans la config de la 
*destination* la fonction de conversion à appliquer à chaque colonne pour la convertir en chaîne de caractères 
(cf. paramètre de config destination `columns_to_char`).
L'identifiant unique commun des enregistrements (`source_code_column`) source et destination doit être de type 
**chaîne de caractères**.

### Table destination

@@ -169,7 +159,6 @@ ALTER TABLE TABLE_DESTINATION ADD COLUMN deleted_on TIMESTAMP(0) WITH TIME ZONE;
```



Fonctionnement
--------------

@@ -184,7 +173,7 @@ Ainsi nous effectuons le déroulement suivant :
*Schématisation du déroulement d'un import*

1. Suppression des données existantes dans _Destination_
2. Récupération des données de la _Source_ vers _Doctrine_
2. Récupération des données de la _Source_
3. Génération des requêtes SQL (insert, update, ...) depuis PHP
4. Exécution des requêtes / Récupération des données vers _Destination_

@@ -206,15 +195,17 @@ Avec une table _Source_ et une table _Destination_ toutes deux dans une base loc

### Synchronisation de données distantes

Concernant le mécanisme de synchronisation, il est possible de spécifier une table _Source_ provenant d'une base distante.
Dans ce cas, les mécanismes d'[import](#import-de-données) et de [synchro (locale)](#synchronisation-de-données-locales) seront réalisés successivement.
Concernant le mécanisme de synchronisation, il est possible de spécifier une _Source_ de type table/select provenant 
d'une base distante, ou de type API (web service).
Dans ce cas, les mécanismes d'[import](#import-de-données) et de [synchro (locale)](#synchronisation-de-données-locales) 
seront réalisés successivement.

<!--Voir le dossier documentation/ pour toutes modifications-->
![fonctionnement_synchro_distant.png](documentation/fonctionnement_synchro_distant.png)

*Schématisation du déroulement d'une synchro (distant)*

1. Déclenchement du mécanisme d'import entre la _Source_ et une table _Temporaire_
1. Déclenchement du mécanisme d'import de la _Source_ vers une table _Temporaire_
2. Déclenchement du mécanisme de synchro entre la table _Temporaire_ et la table _Destination
3. Suppression de la table _Temporaire_

@@ -240,7 +231,54 @@ En outre, on suppose avoir déclaré les configurations _Doctrine_ 'orm_A' et 'o

**Rappel :** L'ensemble des tables _Source_ et _Destination_ doivent exister au préalable.

### Exemple 1 : Importation d'une table de données distantes
Pour les exemples qui suivent, voici à quoi ressemble le fichier de config `unicaen-db-import.local.php` :
`unicaen-db-import.local.php`
```php
return [
    'import' => [
        'connections' => [
            'orm_A' => 'doctrine.connection.orm_A',
            'orm_B' => 'doctrine.connection.orm_B',
            'geo' => [
                'url'      => 'https://geo.api.gouv.fr/',
                'proxy'    => false,
                'verify'   => true,
                'user'     => null,
                'password' => null,
            ],
        ],
    ],
    'doctrine' => [
        'connection' => [
            'orm_A' => [
                'driverClass' => 'Doctrine\\DBAL\\Driver\\PDOPgSql\\Driver',
                'params' => [
                    'host'     => 'host.domain.fr',
                    'port'     => '5432',
                    'charset'  => 'utf8',
                    'user'     => '???',
                    'dbname'   => '???',
                    'password' => '???',
                ],
            ],
            'orm_B' => [
                'driverClass' => 'Doctrine\\DBAL\\Driver\\OCI8\\Driver',
                'params'      => [
                    'host'     => 'host.domain.fr',
                    'port'     => '1527',
                    'user'     => '???',
                    'password' => '???',
                    'dbname'   => '???',
                    'charset'  => 'AL32UTF8',
                ],
                'eventmanager' => 'orm_B',
            ],
        ],
];
```


### Exemple 1 : Import d'une table de données distantes

Dans de nombreux cas, on peut souhaiter importer une table de données provenant d'une base distante.
Ce peut être le cas notamment lorsque l'on souhaite s'assurer de la constante disponibilité des données.
@@ -252,18 +290,16 @@ return [
        'imports' => [
            [
                'name' => "IMPORTATION DES DONNÉES B VERS A",

                'source' => [
                    'name'               => 'TABLE UTILISATEUR DE MA BASE B',
                    'table'              => 'UTILISATEUR',
                    'connection'         => 'doctrine.connection.orm_B',
                    'connection'         => 'orm_B',
                    'source_code_column' => 'CODE',
                ],

                'destination' => [
                    'name'               => 'TABLE UTILISATEUR DE MA BASE A',
                    'table'              => 'UTILISATEUR',
                    'connection'         => 'doctrine.connection.orm_A',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'CODE',
                ],
            ],
@@ -278,10 +314,7 @@ php public/index.php run import --name "IMPORTATION DES DONNÉES B VERS A"
```





### Exemple 2 : Importation d'un select de données distantes
### Exemple 2 : Import d'un select de données distantes

Les bases distantes requêtées sont généralement bien garnies.
Pourtant il est fréquent de ne vouloir importer qu'une partie de ces données.
@@ -293,25 +326,16 @@ return [
        'imports' => [
            [
                'name' => "IMPORTATION PARTIELLE DES DONNÉES B VERS A",

                'source' => [
                    'name'               => 'TABLE CHOCOLATINE DE MA BASE B',
                    'select'             => <<<'EOT'
SELECT
ID,
NOM,
BOULANGERIE
FROM CHOCOLATINE
EOT
                    ,
                    'connection'         => 'doctrine.connection.orm_B',
                    'select'             => 'SELECT ID, NOM, BOULANGERIE FROM CHOCOLATINE',
                    'connection'         => 'orm_B',
                    'source_code_column' => 'ID',
                ],

                'destination' => [
                    'name'               => 'TABLE PAIN_AU_CHOCOLAT DE MA BASE A',
                    'table'              => 'PAIN_AU_CHOCOLAT',
                    'connection'         => 'doctrine.connection.orm_A',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'ID',
                ],
            ],
@@ -325,7 +349,46 @@ EOT
php public/index.php run import --name "IMPORTATION PARTIELLE DES DONNÉES B VERS A"
```

### Exemple 3 : Synchronisation de données locales

### Exemple 3 : Import de données issues d'une API

Dans certains cas, on peut souhaiter importer les données provenant d'une API (web service).

`unicaen-db-import.global.php`
```php
return [
    'import' => [
        'imports' => [
            [
                'name' => "WS_IMPORT_REGIONS",
                'source' => [
                    'name'               => 'API Geo',
                    'select'             => '/regions?fields=nom,code',
                    'connection'         => 'geo',
                    'source_code_column' => 'code',
                ],
                'destination' => [
                    'name'               => 'Table',
                    'table'              => 'REGION',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'CODE',
                ],
            ],
        ],
    ],
];
```

*NB: le `select` de ce type de source est la partie "requête" qui sera concaténée à l'`url` spécifiée
dans la config de la connexion.*

`Terminal du serveur`
```bash
php public/index.php run import --name "WS_IMPORT_REGIONS"
```


### Exemple 4 : Synchronisation de données locales

Dans la pratique, vous ne rencontrerez probablement pas ce cas d'exemple seul (voir [Exemple 5](#exemple-5-synchronisation-de-données-distantes-avec-récupération-des-clés-étrangères)).
Supposez donc posséder 2 tables, l'une d'elle pouvant être qualifiée de "brut"/"en vrac" (d'où proviennent les données) et l'autre "propre" (avec une historisation attendue).
@@ -338,26 +401,16 @@ return [
        'synchros' => [
            [
                'name' => "SYNCHRONISATION LOCALE DE DONNÉES DE A",

                'source' => [
                    'name'               => 'TABLE AUTRE_UTILISATEUR',
                    'select'             => <<<'EOT'
SELECT
CODE,
NOM,
PRENOM,
NAISSANCE
FROM AUTRE_UTILISATEUR
EOT
                    ,
                    'connection'         => 'doctrine.connection.orm_A',
                    'select'             => 'SELECT CODE, NOM, PRENOM, NAISSANCE FROM AUTRE_UTILISATEUR',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'CODE',
                ],

                'destination' => [
                    'name'               => 'TABLE UTILISATEUR',
                    'table'              => 'UTILISATEUR',
                    'connection'         => 'doctrine.connection.orm_A',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'CODE',
                ],
            ],
@@ -373,7 +426,10 @@ php public/index.php run synchro --name "SYNCHRONISATION LOCALE DE DONNÉES DE A

*NB: Fonctionne également en spécifiant une 'table' au lieu d'un 'select' dans la 'source'.*

### Exemple 4 : Synchronisation de données distantes

### Exemple 5 : Synchronisation de données distantes

#### Exemple 5.1 : Source de type base de données

Cet exemple sera probablement l'une des utilisations les plus récurrente d'UnicaenDbImport.
Par exemple, vous possédez une base distante contenant des utilisateurs et une base locale possédant ses propres utilisateurs.
@@ -386,31 +442,21 @@ return [
        'synchros' => [
            [
                'name' => "SYNCHRONISATION DISTANTE DE DONNÉES DE B VERS A",

                'source' => [
                    'name'               => 'TABLE UTILISATEUR DE MA BASE B',
                    'select'             => <<<'EOT'
SELECT
CODE,
NOM,
PRENOM,
NAISSANCE
FROM UTILISATEUR
EOT
                    ,
                    'connection'         => 'doctrine.connection.orm_B',
                    'select'             => 'SELECT CODE, NOM, PRENOM, NAISSANCE FROM UTILISATEUR',
                    'connection'         => 'orm_B',
                    'source_code_column' => 'CODE',
                ],
                
                'intermediate_table' => 'un_nom_au_hasard_que_je_force',    //Sinon par défaut 'tmp_nom_de_la_table', ici 'tmp_utilisateur'

                'intermediate_table_auto_drop' => true, //Supprime la table temporaire si elle existe déjà

                'destination' => [
                    'name'               => 'TABLE UTILISATEUR DE MA BASE A',
                    'table'              => 'UTILISATEUR',
                    'connection'         => 'doctrine.connection.orm_A',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'CODE',
                    
                    'intermediate_table' => 'UN_NOM_QUE_JE_FORCE', // sinon ce sera 'TMP_UTILISATEUR'
                    'intermediate_table_auto_drop' => true, // supprime la table temporaire si elle existe déjà

                ],
            ],
        ],
@@ -423,11 +469,49 @@ EOT
php public/index.php run synchro --name "SYNCHRONISATION DISTANTE DE DONNÉES DE B VERS A"
```

*NB: Une synchronisation de données distantes fait en réalité appel à la fois au mécanisme d'import et au mécanisme de synchronisation locale (voir [Fonctionnement](#fonctionnement)); d'où la présence (facultatif) des paramètres 'intermediate_table' et 'intermediate_table_auto_drop'.*
*NB: Une synchronisation de données distantes fait en réalité appel à la fois au mécanisme d'import et au mécanisme de 
     synchronisation locale (voir [Fonctionnement](#fonctionnement)) ; d'où la présence (facultative) des paramètres 
     `intermediate_table` et `intermediate_table_auto_drop`.*

*NB-2: Fonctionne également en spécifiant une 'table' au lieu d'un 'select' dans la 'source'.*

### Exemple 5 : Synchronisation de données distantes avec récupération des clés étrangères

#### Exemple 5.2 : Source de type API

`unicaen-db-import.global.php`
```php
return [
    'import' => [
        'synchros' => [
            [
                'name' => "WS_SYNCHRO_COMMUNES",
                'source' => [
                    'name'               => 'API Geo',
                    'select'             => '/departements/63/communes?fields=nom,code',
                    'connection'         => 'geo',
                    'source_code_column' => 'code',
                ],
                'destination' => [
                    'name'               => 'Table',
                    'table'              => 'REGION',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'CODE',

                    'intermediate_table_auto_drop' => true,
                ],
            ],
        ],
    ],
];
```

`Terminal du serveur`
```bash
php public/index.php run synchro --name "WS_SYNCHRO_COMMUNES"
```


### Exemple 6 : Synchronisation de données distantes avec récupération des clés étrangères

De nombreux cas d'utilisation suivront cet exemple.
Si vous observez les tables (base locale) déclarées au début de cette section [Exemples](#exemples), vous pourrez constater que les formations possèdent des clés étrangères vers les composantes (via leur ID).
@@ -456,26 +540,16 @@ return [
        'imports' => [
            [
                'name' => "IMPORTATION DE DONNÉES B VERS A",

                'source' => [
                    'name'               => 'TABLE FORMATION DE MA BASE B',
                    'select'             => <<<'EOT'
SELECT
ID,
CODE,
NOM,
COMPOSANTE_CODE
FROM FORMATION
EOT
                    ,
                    'connection'         => 'doctrine.connection.orm_B',
                    'select'             => 'SELECT ID, CODE, NOM, COMPOSANTE_CODE FROM FORMATION',
                    'connection'         => 'orm_B',
                    'source_code_column' => 'ID',
                ],

                'destination' => [
                    'name'               => 'TABLE TMP_FORMATION DE MA BASE A',
                    'table'              => 'TMP_FORMATION',
                    'connection'         => 'doctrine.connection.orm_A',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'ID',
                ],
            ],
@@ -483,22 +557,16 @@ EOT
        'synchros' => [
            [
                'name' => "SYNCHRONISATION DE DONNÉES DÉJÀ IMPORTÉE DE B VERS A",   //Autrement dit une synchro locale

                'source' => [
                    'name'               => 'TABLE SRC_FORMATION DE MA BASE A UTILISANT TMP_FORMATION',
                    'select'             => <<<'EOT'
SELECT *
FROM SRC_UTILISATEUR
EOT
                    ,
                    'connection'         => 'doctrine.connection.orm_A',
                    'select'             => 'SELECT * FROM SRC_UTILISATEUR',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'ID',
                ],

                'destination' => [
                    'name'               => 'TABLE FORMATION DE MA BASE A',
                    'table'              => 'FORMATION',
                    'connection'         => 'doctrine.connection.orm_A',
                    'connection'         => 'orm_A',
                    'source_code_column' => 'ID',

                ],
@@ -518,19 +586,6 @@ php public/index.php run synchro --name "SYNCHRONISATION DE DONNÉES DÉJÀ IMPO




### Exemple Z : Appliquer un CRON

Exemple de CRON appliqué à l'application Zebu.

```cron
# Du lundi au vendredi, entre 6h00 et 19h45, toutes les 15 minutes
*/15 6-19 * * 1-5   root    /usr/bin/php /var/www/zebu-back/public/index.php run import --all 1> /tmp/zebu-cron.log 2>&1
```




Ajouter le support d'une autre plateforme de base de données (pour développeur)
-------------------------------------------------------------------------------

@@ -560,7 +615,7 @@ return [
├── CodeGenerator.php
├── Helper
│   ├── DiffViewHelper.php
│   ├── SynchroLogHelper.php
│   ├── LogTableHelper.php
│   ├── TableHelper.php
│   └── TableValidationHelper.php
└── MySQLCommonsTrait.php
@@ -578,7 +633,7 @@ namespace UnicaenDbImport\CodeGenerator\MySQL;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use UnicaenDbImport\CodeGenerator\MySQL\Helper\DiffViewHelper as MySQLDiffViewHelper;
use UnicaenDbImport\CodeGenerator\MySQL\Helper\SynchroLogHelper as MySQLSynchroLogHelper;
use UnicaenDbImport\CodeGenerator\MySQL\Helper\LogTableHelper as MySQLLogTableHelper;
use UnicaenDbImport\CodeGenerator\MySQL\Helper\TableValidationHelper as MySQLTableValidationHelper;
use UnicaenDbImport\CodeGenerator\MySQL\Helper\TableHelper as MySQLTableHelper;

@@ -608,7 +663,7 @@ class CodeGenerator extends \UnicaenDbImport\CodeGenerator\CodeGenerator
    protected $diffViewHelper;

    /**
     * @var MySQLSynchroLogHelper
     * @var MySQLLogTableHelper
     */
    protected $synchroLogHelper;

@@ -624,7 +679,7 @@ class CodeGenerator extends \UnicaenDbImport\CodeGenerator\CodeGenerator
        $this->tableHelper = new MySQLTableHelper($this->platform);
        $this->tableValidationHelper = new MySQLTableValidationHelper($this->platform);
        $this->diffViewHelper = new MySQLDiffViewHelper($this->platform);
        $this->synchroLogHelper = new MySQLSynchroLogHelper($this->platform);
        $this->synchroLogHelper = new MySQLLogTableHelper($this->platform);
    }
    
    //...
@@ -695,7 +750,7 @@ class DiffViewHelper extends \UnicaenDbImport\CodeGenerator\Helper\DiffViewHelpe
```


- Mêmes principes pour les autres classes `Helper\SynchroLogHelper`, `Helper\TableHelper`, `Helper\TableValidationHelper`.
- Mêmes principes pour les autres classes `Helper\LogTableHelper`, `Helper\TableHelper`, `Helper\TableValidationHelper`.


- Du fait que les classes `CodeGenerator` et `*Helper` héritent déjà chacune d'une classe, un trait `MySQLCommonsTrait` 
+2 −1

File changed.

Preview size limit exceeded, changes collapsed.

+274 −1

File changed.

Preview size limit exceeded, changes collapsed.

+7 −0

File changed.

Preview size limit exceeded, changes collapsed.

+141 −83

File changed.

Preview size limit exceeded, changes collapsed.

Loading