UnicaenDbImport
- Introduction
- La différence avec le module UnicaenImport
- Installation
- Configuration
- Utilisation
- Contraintes
- Fonctionnement
- Exemples
NB: Refonte en cours, plus d'information sur l'ancien moteur (peut être encore actuel) d'UnicaenDbImport en cliquant ici.
Installation
- Ensuite, ajoutez le module à vos dépendances :
composer require unicaen/db-import
Introduction
Ce module réalise l'import et/ou la synchronisation de données issues d'une source vers une table d'une base de données destination.
La source peut être :
- soit une table ou un "select" dans une base de données,
- soit une API (web service).
La destination est forcément une table dans une base de données.
L'import et la synchronisation sont 2 mécanismes distincts.
Import
Principe de l'import :
- La table destination est vidée entièrement.
- Les données obtenues de la source sont insérées dans la table destination.
Synchronisation
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, rien n'est fait.
- Si la source contient un enregistrement qui existe aussi dans la destination mais avec des valeurs de colonnes différentes, les colonnes de la destination sont mises à jour en conséquence.
- Si la source ne contient pas un enregistrement qui existe dans la destination, l'enregistrement destination est historisé (i.e. marqué "supprimé").
- Si la source contient un enregistrement qui existe aussi dans la destination mais marqué "supprimé", ce dernier est dé-historisé.
Les données source et les données destination doivent avoir un identifiant unique en commun, permettant
de les rapprocher : on l'appellera le "code source" (cf. paramètre de config source_code_column
).
Cet identifiant commun DOIT être de type chaîne de caractères.
Afin de faciliter l'adaptation au plus grand nombre de plateforme de base de données, UnicaenDbImport s'appuie en partie sur l'ORM Doctrine 2.
Différence avec unicaen/import
Comme son nom ne l'indique pas, "unicaen/import" fonctionne uniquement entre 2 bases de données Oracle.
Le présent module "unicaen/db-import" fonctionne en majeure partie en PHP, tout en déléguant au maximum au SGBD ce que ce dernier
sait bien faire (select FULL OUTER JOIN
pour le différentiel entre données source et données destination, par exemple).
Par conséquent, il est possible de l'enrichir pour implémenter imports et synchros vers différentes plateformes de base de données destination. Les plateformes de base de données destination suivantes sont implementées :
- PostgreSQL
- Oracle
En revanche toutes les plateformes de base de données source sont supportées car on se contente d'y faire un select pour obtenir les données.
Installation
Première installation
- Installez le module :
composer require unicaen/db-import
- Ajoutez dans le
composer.json
de votre appli, la "post install command" suivante :
"scripts": {
"post-install-cmd": [
"mkdir -p public/unicaen ; cp -r vendor/unicaen/db-import/public/unicaen public/",
- Lancer les "post install commands" de votre appli pour obtenir les ressources CSS et JS du module :
composer run-script post-install-cmd
- Reportez-vous dans le répertoire
data
au script SQL correspondant à votre plateforme de base de données destination pour créer les objets nécessaires. Notamment la tableSOURCE
permettant de déclarer les différentes sources de données disponibles (ex : Apogée, Harpege, Octopus).
Mise à jour
Lorsqu'une nouvelle version du module est installée dans votre appli, n'oubliez pas de relancer les "post install commands" de votre appli pour obtenir les versions à jour des ressources CSS et JS :
composer run-script post-install-cmd
Configuration
- Récupérez les fichiers config exemples :
cp -n vendor/unicaen/db-import/config/unicaen-db-import.global.php.dist config/autoload/unicaen-db-import.global.php
cp -n vendor/unicaen/db-import/config/unicaen-db-import.local.php.dist config/autoload/unicaen-db-import.local.php
-
Adaptez leur contenu à vos besoins en lisant bien les commentaires inclus.
-
Ajoutez ce qui suit à la config du module "unicaen/bjy-authorize" si vous l'utilisez :
return [
'bjyauthorize' => [
'guards' => [
\UnicaenAuth\Guard\PrivilegeController::class => [
[
'controller' => 'UnicaenDbImport\Controller\Console',
'action' => [
'runImport',
'runSynchro',
],
'roles' => [],
],
],
],
],
//...
];
Utilisation
Le module propose deux opérations distinctes :
- Import : réalise un import "brut" des données, autrement dit une copie de données de la source vers la destination ;
- Synchro : réalise une synchronisation unidirectionnelle de la destination à partir de la source.
Le module fournit une ligne de commande pour lancer :
- un import par son nom :
php public/index.php run import --name "NOM_ETABLI_DANS_LA_CONFIG"
- tous les imports :
php public/index.php run import
- une synchro par son nom :
php public/index.php run synchro --name "NOM_ETABLI_DANS_LA_CONFIG"
- toutes les synchros :
public/index.php run synchro
NB : Chacune de ces commandes réalise l'import ou la synchronisation une seule fois.
Pour importer/synchroniser en permanence, il faut programmer le lancement périodique de la commande à l'aide de CRON
par exemple.
Ex : */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
Identifiant commun
Les données source doivent posséder un identifiant unique/discriminant (cf. paramètre de config source_code_column
)
de type chaîne de caractères.
Dans le cas d'une synchro, la table destination doit posséder aussi cet identifiant unique/discriminant permettant de rapprocher les données source et destination.
Table SOURCE
La base de données destination doit posséder une table particulière nommée SOURCE
dont le script de création est
fourni dans le répertoire data
.
Cette table permet de nommer et de référencer les différentes sources de données disponibles (ex : Apogée, Harpege, Octopus) et d'indiquer lesquelles sont importables/synchronisables. Elle contient a minima une source : l'application elle-même, source non importable/synchronisable par principe.
Dans le cas d'un import/synchro depuis une source de type API, l'attribut de config 'code'
de la source
doit correspondre au CODE
d'une source dans la table SOURCE
, sinon une erreur sera signalée.
Table destination
Colonnes pour l'historique
La table destination doit obligatoirement posséder les colonnes permettant de gérer l'historique (cycle de vie) des données :
-
created_on
: date et heure de création de la donnée -
updated_on
: date et heure de modification -
deleted_on
: date et heure de suppression (historisation) -
created_by
: id de l'auteur de la création -
updated_by
: id de l'auteur de la modification -
deleted_by
: id de l'auteur de la suppression (historisation)
Exemple en PostgreSQL :
ALTER TABLE TABLE_DESTINATION ADD COLUMN created_on TIMESTAMP(0) WITH TIME ZONE DEFAULT LOCALTIMESTAMP(0) NOT NULL;
ALTER TABLE TABLE_DESTINATION ADD COLUMN updated_on TIMESTAMP(0) WITH TIME ZONE;
ALTER TABLE TABLE_DESTINATION ADD COLUMN deleted_on TIMESTAMP(0) WITH TIME ZONE;
ALTER TABLE TABLE_DESTINATION ADD COLUMN created_by INTEGER NOT NULL;
ALTER TABLE TABLE_DESTINATION ADD COLUMN updated_by INTEGER;
ALTER TABLE TABLE_DESTINATION ADD COLUMN deleted_by INTEGER;
Si vous utilisez un autre nommage pour ces colonnes dans la table destination, il est possible de renseigner dans la config les alias pour chaque colonne. Le type des colonnes, lui, en revanche devra être respecté.
Si vous ne souhaitez pas consigner l'auteur des créations, vous devrez retirer le NOT NULL
sur la colonne created_by
.
Remarque importante : la disparition d'un enregistrement dans la source ne provoque pas sa supression physique
dans la table destination ; ce dernier est simplement "marqué comme supprimé" (historisé) à l'aide des colonnes
d'historique deleted_on
(date et heure de suppression) et deleted_by
(identifiant de l'auteur de la suppression).
source_id
et source_code
Colonnes La table destination doit obligatoirement posséder les colonnes suivantes :
-
source_id
: clé étrangère identifiant la source de la donnée, correspondant à un 'id' de la [tableSOURCE
](#Table SOURCE). -
source_code
: fameux identifiant commun permettant de rapprocher la donnée source de la donnée destination.
Exemple en PostgreSQL :
ALTER TABLE TABLE_DESTINATION ADD source_id integer NOT NULL ;
ALTER TABLE TABLE_DESTINATION ADD source_code varchar(100) ;
Fonctionnement
Import
Typiquement, il s'agit d'importer des données issues d'une base de données source (différente de celle de celle de destination) ou d'une API (web service).
Schéma du déroulement d'un import :
- Suppression totale des données existantes dans la table destination.
- Interrogation de la source pour obtenir les données sources.
- Génération des requêtes SQL d'INSERT.
- Exécution des requêtes d'INSERT dans la table destination.
Synchronisation "locale"
Ce que l'on appelle synchronisation locale consiste à synchroniser le contenu d'une table destination à partir de celui d'une table (ou d'un "select") source se trouvant dans la même base de données.
Schéma du déroulement d'une synchro :
- Création d'une vue différentielle (différences entre les données de la table/vue source et celles de la table destination).
- Préparation des opérations à réaliser sur la table destination (INSERT ou UPDATE) à partir de ce que fournit la vue différentielle.
- Réalisations des opérations dans la table destination.
Synchronisation à partir d'une source "externe"
Dans une synchronisation à partir d'une source dite "externe", la source peut être de 2 natures :
- soit une table ou un select provenant d'une autre base de données que celle de destination,
- soit une API (web service).
Quelle que soit la nature de la source, cette synchronisation se subdivisera en 2 sous-tâches successives : un import puis une synchronisation locale.
Schématisation du déroulement d'une synchro à partir d'une source "externe" :
- Import des données sources dans une table intermédiaire de la base de données destination.
- Synchronisation locale entre la table intermédiaire (devenue source) et la table destination.
- Suppression de la table temporaire.
Exemples
Pour les exemples suivants, on suppose posséder :
- Une base de donnée A (celle de notre application) contenant les tables :
-
UTILISATEUR
(int ID, str CODE, str NOM, str PRENOM, date NAISSANCE) -
AUTRE_UTILISATEUR
(str CODE, str NOM, str PRENOM, date NAISSANCE) -
COMPOSANTE
(int ID, str CODE, str NOM) -
FORMATION
(int ID, str CODE, str NOM, str COMPOSANTE_ID) -
PAIN_AU_CHOCOLAT
(int ID, str NOM, str BOULANGERIE)
-
- Une base de donnée B différente de A (par exemple Apogée) contenant les tables :
-
UTILISATEUR
(int ID, str CODE, str NOM, str PRENOM, date NAISSANCE) -
COMPOSANTE
(int ID, str CODE, str NOM, int DIRECTEUR_ID, str ADRESSE) -
FORMATION
(int ID, str CODE, str NOM, str COMPOSANTE_CODE) -
CHOCOLATINE
(int ID, str NOM, str BOULANGERIE, int POURCENT_GRAS, int NOTE)
-
En outre, on suppose avoir déclaré les connexions orm_A
et orm_B
respectivement pour les bases A
et B (dans le fichier de config config/autoload/unicaen-db-import.local.php
par exemple, inspiré du ficher de
config exemple unicaen-db-import.local.php.dist
).
Pour les exemples qui suivent, voici à quoi ressemble le fichier de config config/unicaen-db-import.local.php
:
unicaen-db-import.local.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 de données externes provenant d'une autre base
Dans de nombreux cas, on souhaite importer une table (ou une vue ou un "select") de données provenant d'une autre base que celle de destination. Ce peut être utile par exemple pour disposer de données externes sans être impacté par une indisponibilité de la base de données source (en cas de maintenance par exemple).
unicaen-db-import.global.php
return [
'import' => [
'imports' => [
[
'name' => "IMPORT_SIMPLE",
'source' => [
'code' => 'UTILISATEUR_OCTOPUS',
'table' => 'UTILISATEUR',
'connection' => 'orm_B',
'source_code_column' => 'CODE',
],
'destination' => [
'code' => 'TABLE UTILISATEUR LOCALE',
'table' => 'UTILISATEUR',
'connection' => 'orm_A',
'source_code_column' => 'CODE',
],
],
],
],
];
Ligne de commande :
php public/index.php run import --name "IMPORT_SIMPLE"
Exemple 2 : Import de données externes issues d'une API
Dans certains cas, on souhaite importer les données provenant d'une API (web service).
unicaen-db-import.global.php
return [
'import' => [
'imports' => [
[
'name' => "IMPORT_REGIONS_API",
'source' => [
'code' => 'geo_api', // DOIT correspondre à un `CODE` de la table `SOURCE`
'select' => '/regions?fields=nom,code',
'connection' => 'geo',
'source_code_column' => 'code',
],
'destination' => [
'code' => 'Table REGION',
'table' => 'REGION',
'connection' => 'orm_A',
'source_code_column' => 'CODE',
],
],
],
],
];
Dans ce type de source, le select
est la partie "requête" qui sera concaténée à l'url
de l'API spécifiée
dans la config de la connexion.
Ligne de commande :
php public/index.php run import --name "IMPORT_REGIONS_API"
Exemple 3 : Synchronisation locale de données au sein d'une même base
Exemple d'un "select" source mettant en forme des données, et d'une table destination synchronisée sur celles-ci :
unicaen-db-import.global.php
return [
'import' => [
'synchros' => [
[
'name' => "SYNCHRO_LOCALE_ROLE",
'source' => [
'code' => 'app',
'select' => 'SELECT CODE, LIBELLE, DESCRIPTION FROM SRC_ROLE',
'connection' => 'orm_A',
'source_code_column' => 'CODE',
],
'destination' => [
'code' => 'Table ROLE',
'table' => 'ROLE',
'connection' => 'orm_A',
'source_code_column' => 'CODE',
],
],
],
],
];
Ligne de commande :
php public/index.php run synchro --name "SYNCHRO_LOCALE_UTILISATEUR"
Une autre solution (préférable) consisterait à écrire une vue qui réaliserait la mise en forme en question et à utiliser
cette fois le paramètre table
(au lieu du paramètre select
).
Exemple 4 : Synchronisation à partir d'une source externe
Exemple 4.1 : Source externe de type base de données
Cet exemple sera probablement l'une des utilisations les plus fréquentes de ce module.
Par exemple, vous avez accès à une base de données contenant des utilisateurs et la base de données de votre application possédant ses propres utilisateurs. Vous souhaitez alors synchroniser vos utilisateurs avec ceux disponibles dans l'autre base.
unicaen-db-import.global.php
return [
'import' => [
'synchros' => [
[
'name' => "SYNCHRO_BDD_EXTERNE",
'source' => [
'code' => 'UTILISATEUR_OCTOPUS',
'select' => 'SELECT CODE, NOM, PRENOM, NAISSANCE FROM UTILISATEUR',
'connection' => 'orm_B',
'source_code_column' => 'CODE',
],
'destination' => [
'code' => 'Table UTILISATEUR',
'table' => 'UTILISATEUR',
'connection' => 'orm_A',
'source_code_column' => 'CODE',
'intermediate_table' => 'NOM_QUE_JE_FORCE', // sinon ce sera 'TMP_UTILISATEUR'
'intermediate_table_auto_drop' => true, // supprime la table intermédiaire si elle existe déjà
],
],
],
],
];
Ligne de commande :
php public/index.php run synchro --name "SYNCHRO_BDD_EXTERNE"
Une synchronisation de données à partir d'une autre base de données fait en réalité appel successivement au mécanisme
d'import et au mécanisme de synchronisation (voir Fonctionnement) ; d'où la présence
des paramètres facultatifs intermediate_table
et intermediate_table_auto_drop
.
Fonctionne également en spécifiant une 'table'
au lieu d'un 'select'
dans la source.
Exemple 4.2 : Source externe de type API
unicaen-db-import.global.php
return [
'import' => [
'synchros' => [
[
'name' => "SYNCHRO_COMMUNES",
'source' => [
'code' => 'geo_api', // DOIT correspondre à un `CODE` de la table `SOURCE`
'select' => '/departements/63/communes?fields=nom,code',
'connection' => 'geo',
'source_code_column' => 'code',
],
'destination' => [
'code' => 'Table locale',
'table' => 'REGION',
'connection' => 'orm_A',
'source_code_column' => 'CODE',
'intermediate_table_auto_drop' => true,
],
],
],
],
];
Terminal du serveur
php public/index.php run synchro --name "SYNCHRO_COMMUNES"
Exemple 5 : Synchronisation de données externes avec récupération des clés étrangères
De nombreux cas d'utilisation suivront cet exemple.
Si vous observez les tables exemples évoquées au début de cette section Exemples, vous pourrez constater que les formations possèdent des clés étrangères vers les composantes.
Pour gérer le cas de ces clés étrangères, il vous faudra :
- Configurer un import de la base source externe vers une table destination "intermédiaire" ;
- Créer une vue (conventionnellement préfixée par
SRC_
) puisant dans la table intermédiaire et réalisant les jointures nécessaires à l'alimentation des clés étrangères ; - Configurer un mécanisme de synchro de la vue (source) vers la table destination finale.
Voici l'exemple d'une vue SRC_FORMATION
puisant dans la table intermédiaire TMP_FORMATION
et mettant en forme les
données qui seront la source de la synchronisation vers la table finale FORMATION
:
CREATE VIEW SRC_FORMATION AS
SELECT
tmp.ID AS ID,
tmp.CODE AS CODE,
tmp.NOM AS NOM,
c.ID AS COMPOSANTE_ID
FROM
TMP_FORMATION tmp
INNER JOIN COMPOSANTE c ON tmp.COMPOSANTE_CODE = c.CODE;
unicaen-db-import.global.php
return [
'import' => [
'imports' => [
[
'name' => "IMPORT_PRÉALABLE", // Importation des données externes dans une table intermédiaire
'source' => [
'code' => 'FORMATION_FCA',
'select' => 'SELECT ID, CODE, NOM, COMPOSANTE_CODE FROM FORMATION',
'connection' => 'orm_B',
'source_code_column' => 'ID',
],
'destination' => [
'code' => 'Table TMP_FORMATION locale',
'table' => 'TMP_FORMATION',
'connection' => 'orm_A',
'source_code_column' => 'ID',
],
],
],
'synchros' => [
[
'name' => "SYNCHRO_FINALE", // Synchro des données mise en forme vers la table finale
'source' => [
'code' => 'TABLE SRC_FORMATION DE MA BASE A UTILISANT TMP_FORMATION',
'select' => 'SELECT * FROM SRC_FORMATION',
'connection' => 'orm_A',
'source_code_column' => 'ID',
],
'destination' => [
'code' => 'TABLE FORMATION DE MA BASE A',
'table' => 'FORMATION',
'connection' => 'orm_A',
'source_code_column' => 'ID',
],
],
],
],
];
Ligne de commande :
php public/index.php run import --name "IMPORT_PRÉALABLE"
php public/index.php run synchro --name "SYNCHRO_FINALE"
Dans cet exemple, la table intermédiaire TMP_FORMATION
doit être préalablement créée par vos soins.
Développement
Supporter une plateforme de base de données supplémentaire
Imaginons que l'on veuille ajouter la possibilité d'importer/synchroniser vers une table destination se trouvant sur la plateforme de base de données Oracle.
Voici ce qu'il faudra faire...
-
Ajouter un fichier de config
config/oracle.config.php
dans lequel sera spécifié :-
La classe de "code generator" (que vous devrez fournir) à utiliser pour la plateforme de base de données Oracle (clé
code_generators_mapping
). -
La factory (que vous devrez fournir) à utiliser pour instancier le "code generator" en question (clé
code_generators_factories
).Exemple :
return [ 'import' => [ 'code_generators_mapping' => [ \Doctrine\DBAL\Platforms\OraclePlatform::class => \UnicaenDbImport\CodeGenerator\Oracle\CodeGenerator::class, ], 'code_generators_factories' => [ \UnicaenDbImport\CodeGenerator\Oracle\CodeGenerator::class => \UnicaenDbImport\CodeGenerator\Oracle\CodeGeneratorFactory::class, ], ], ];
-
-
Créer un sous-répertoire
Oracle
dans le répertoiresrc/UnicaenDbImport/CodeGenerator
dans lequel il faudra créer les fichiers/classes suivants :. ├── Helper │ ├── LogTableHelper.php │ ├── TableHelper.php │ └── TableValidationHelper.php ├── CodeGenerator.php ├── CodeGeneratorFactory.php ├── HelperAbstractFactory.php
-
Respecter les contraintes suivantes pour écrire la classe
CodeGenerator
:-
Hériter de la classe abstraite
\UnicaenDbImport\CodeGenerator\CodeGenerator
. -
Instancier dans le constructeur la plateforme de base de données à laquelle sera en partie déléguée la génération de code SQL.
NB: l'instance de la plateforme de base de données injectée ici est utilisée pour générer du SQL compris par la base de données destination. Si aucune classe de plateforme ne correspond exactement à la version de la base de données destination, prenez la plus générique (ex:
MySqlPlatform
plutôt queMySQL80Platform
). -
Redéfinir si besoin les méthodes de la classe mère qui ne génèreraient pas du code SQL valide pour la plateforme de base de données (ici, Oracle).
Exemple :
namespace UnicaenDbImport\CodeGenerator\Oracle; use Doctrine\DBAL\Platforms\OraclePlatform; class CodeGenerator extends \UnicaenDbImport\CodeGenerator\CodeGenerator { public function __construct() { $this->platform = new OraclePlatform(); } public function generateSQLForIntermmediateTableDrop($tableName) { return "DROP TABLE $tableName CASCADE CONSTRAINTS ;"; } }
-
-
Respecter les contraintes suivantes pour écrire le "helper" de génération de code
Helper\TableHelper
:-
Hériter obligatoirement de la classe abstraite
\UnicaenDbImport\CodeGenerator\Helper\TableHelper
; et donc définir les méthodes abstraites de la classe mère. -
Instancier dans le constructeur la plateforme de base de données à laquelle sera en partie déléguée la génération de code SQL.
-
Redéfinir si besoin les méthodes de la classe mère qui ne génèreraient pas du code SQL valide pour la plateforme de base de données (ici, Oracle).
Exemple :
namespace UnicaenDbImport\CodeGenerator\Oracle\Helper; use Doctrine\DBAL\Platforms\OraclePlatform; class TableHelper extends \UnicaenDbImport\CodeGenerator\Helper\TableHelper { /** * @var OraclePlatform */ protected $platform; public function __construct() { $this->platform = new OraclePlatform(); } protected function generateDiffViewDeletionSQLSnippet($destinationTable) { $name = $this->generateDiffViewName($destinationTable); return "DROP VIEW $name"; } //... }
-
-
Respecter les mêmes contraintes dans les autres helpers :
Helper\LogTableHelper
,Helper\TableValidationHelper
. -
Respecter les contraintes suivantes pour écrire la factory
CodeGeneratorFactory
:-
Injecter dans le "code generator" une instance de la plateforme correspondant à la base de données destination.
NB: l'instance de la plateforme de base de données injectée ici est utilisée pour générer du SQL compris par la base de données destination. Si aucune classe de plateforme ne correspond exactement à la version de la base de données destination, prenez la plus générique (ex:
MySqlPlatform
plutôt queMySQL80Platform
) -
Injecter aussi les instances des helpers évoqués plus haut, obtenus auprès du container.
Exemple :
namespace UnicaenDbImport\CodeGenerator\Oracle; use Psr\Container\ContainerInterface; use UnicaenDbImport\Config\Config; class CodeGeneratorFactory { /** * @param ContainerInterface $container * @return CodeGenerator */ public function __invoke(ContainerInterface $container) { /** @var Config $config */ $config = $container->get(Config::class); $tableHelper = $container->get(Helper\TableHelper::class); $tableValidationHelper = $container->get(Helper\TableValidationHelper::class); $logTableHelper = $container->get(Helper\LogTableHelper::class); $codeGenerator = new CodeGenerator(); $codeGenerator->setConfig($config); $codeGenerator->setTableHelper($tableHelper); $codeGenerator->setTableValidationHelper($tableValidationHelper); $codeGenerator->setLogTableHelper($logTableHelper); return $codeGenerator; } }
-