Commit 18dd60ce authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

[FIX] Le générateur SQL de la destination était utilisé aussi pour interroger...

[FIX] Le générateur SQL de la destination était utilisé aussi pour interroger la source, désormais la source a le sien propre.
parent e64c2b24
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ Changelog
7.2.0
-----
- Suppression de la dépendance avec unicaen/app, et avec laminas/laminas-dependency-plugin.
- [FIX] Le générateur SQL de la destination était utilisé aussi pour interroger la source, désormais la source a le sien propre.

7.1.0
-----
+35 −9
Original line number Diff line number Diff line
@@ -17,7 +17,8 @@ abstract class AbstractDatabaseService
{
    protected CodeGeneratorPluginManager $codeGeneratorPluginManager;
    protected array $codeGeneratorsConfig;
    protected CodeGenerator $codeGenerator;
    protected CodeGenerator $codeGeneratorForSource;
    protected CodeGenerator $codeGeneratorForDestination;
    /** @var CodeGenerator[] */
    protected array $cachedCodeGenerators = [];

@@ -46,6 +47,8 @@ abstract class AbstractDatabaseService
    public function setSource(SourceInterface $source): void
    {
        $this->source = $source;

        $this->initCodeGeneratorFromSource();
    }

    public function setDestination(DestinationInterface $destination): void
@@ -55,10 +58,28 @@ abstract class AbstractDatabaseService
        $this->initCodeGeneratorFromDestination();
    }

    /**
     * Détermine, selon la plateforme de bdd source, le générateur de code SQL à utiliser.
     *
     * @throws \UnicaenDbImport\Service\Exception\DatabaseServiceException
     */
    public function initCodeGeneratorFromSource(): CodeGenerator
    {
        try {
            $platformClass = get_class($this->source->getConnection()->getDatabasePlatform());
        } catch (Exception $e) {
            throw DatabaseServiceException::error(
                "Impossible de déterminer la plateforme de la base de données source", $e);
        }

        $this->codeGeneratorForSource = $this->initCodeGeneratorForPlatform($platformClass);

        return $this->codeGeneratorForSource;
    }

    /**
     * Détermine, selon la plateforme de bdd destination, le générateur de code SQL à utiliser.
     *
     * @return CodeGenerator
     * @throws \UnicaenDbImport\Service\Exception\DatabaseServiceException
     */
    public function initCodeGeneratorFromDestination(): CodeGenerator
@@ -70,6 +91,13 @@ abstract class AbstractDatabaseService
                "Impossible de déterminer la plateforme de la base de données destination", $e);
        }

        $this->codeGeneratorForDestination = $this->initCodeGeneratorForPlatform($platformClass);

        return $this->codeGeneratorForDestination;
    }

    protected function initCodeGeneratorForPlatform(string $platformClass): CodeGenerator
    {
        if (! isset($this->cachedCodeGenerators[$platformClass])) {
            try {
                Assertion::keyExists($this->codeGeneratorsConfig, $platformClass);
@@ -84,23 +112,21 @@ abstract class AbstractDatabaseService
            $this->cachedCodeGenerators[$platformClass] = $codeGenerator;
        }

        $this->codeGenerator = $this->cachedCodeGenerators[$platformClass];

        return $this->codeGenerator;
        return $this->cachedCodeGenerators[$platformClass];
    }

    /**
     * @throws \UnicaenDbImport\Service\Exception\DatabaseServiceException
     */
    protected function assertTableExists(string $tableName, Connection $connection, ?string $message = null)
    protected function assertTableExistsInDestination(string $tableName, ?string $message = null): void
    {
        $sql = $this->codeGenerator->generateSQLForTableExistenceCheck($tableName);
        $sql = $this->codeGeneratorForDestination->generateSQLForTableExistenceCheck($tableName);
        try {
            $result = $this->queryExecutor->fetchAll($sql, $connection);
            $result = $this->queryExecutor->fetchAll($sql, $this->destination->getConnection());
        } catch (Exception $e) {
            throw DatabaseServiceException::error("Erreur lors du test d'existence de la table '$tableName'", $e);
        }
        $exists = $this->codeGenerator->convertTableExistenceCheckResultToBoolean($result);
        $exists = $this->codeGeneratorForDestination->convertTableExistenceCheckResultToBoolean($result);
        if (!$exists) {
            throw DatabaseServiceException::error(sprintf(
                $message ?: "La table '%s' nécessaire au fonctionnement est introuvable dans la base destination. ",
+31 −29
Original line number Diff line number Diff line
@@ -28,17 +28,17 @@ class DatabaseService extends AbstractDatabaseService
        $sourceCodeColumn = $this->destination->getSourceCodeColumn();

        // test if table exists
        $this->assertTableExists($table, $connection, "La table destination '%s' est introuvable. ");
        $this->assertTableExistsInDestination($table, "La table destination '%s' est introuvable. ");

        // id column validation
        $columnCount = 0;
        $sql = $this->codeGenerator->generateSQLForIdColumnValidationInTable($table, $columnCount);
        $sql = $this->codeGeneratorForDestination->generateSQLForIdColumnValidationInTable($table, $columnCount);
        try {
            $result = $this->queryExecutor->fetchAll($sql, $connection);
        } catch (Exception $e) {
            throw DatabaseServiceException::error("Erreur lors de la validation de la colonne id dans la table destination '$table'", $e);
        }
        $exception = $this->codeGenerator->convertIdColumnValidationBadResultToException($table, $result, $columnCount);
        $exception = $this->codeGeneratorForDestination->convertIdColumnValidationBadResultToException($table, $result, $columnCount);
        if ($exception !== null) {
            throw DatabaseServiceException::error("La table '$table' n'est pas une table de destination valide. ", $exception);
        }
@@ -46,13 +46,13 @@ class DatabaseService extends AbstractDatabaseService
        if ($this->destination->getIdColumnStrategy() === DestinationInterface::ID_STRATEGY_SEQUENCE) {
            // existence de la sequence pour la colonne id
            $idColumnSequence = $this->destination->getIdColumnSequence();
            $sql = $this->codeGenerator->generateSQLForSequenceExistenceCheck($table, $idColumnSequence);
            $sql = $this->codeGeneratorForDestination->generateSQLForSequenceExistenceCheck($table, $idColumnSequence);
            try {
                $result = $this->queryExecutor->fetchAll($sql, $connection);
            } catch (Exception $e) {
                throw DatabaseServiceException::error("Erreur lors du test d'existence de la séquence dans la table destination '$table'", $e);
            }
            $exception = $this->codeGenerator->convertSequenceExistenceCheckResultToException($idColumnSequence, $result);
            $exception = $this->codeGeneratorForDestination->convertSequenceExistenceCheckResultToException($idColumnSequence, $result);
            if ($exception !== null) {
                throw DatabaseServiceException::error("La sequence '$idColumnSequence' est introuvable. ", $exception);
            }
@@ -60,26 +60,26 @@ class DatabaseService extends AbstractDatabaseService

        // histo columns validation
        $columnCount = 0;
        $sql = $this->codeGenerator->generateSQLForHistoColumnsValidationInTable($table, $columnCount);
        $sql = $this->codeGeneratorForDestination->generateSQLForHistoColumnsValidationInTable($table, $columnCount);
        try {
            $result = $this->queryExecutor->fetchAll($sql, $connection);
        } catch (Exception $e) {
            throw DatabaseServiceException::error("Erreur lors de la validation des colonne d'historique dans la table destination '$table'", $e);
        }
        $exception = $this->codeGenerator->convertHistoColumnsValidationBadResultToException($table, $result, $columnCount);
        $exception = $this->codeGeneratorForDestination->convertHistoColumnsValidationBadResultToException($table, $result, $columnCount);
        if ($exception !== null) {
            throw DatabaseServiceException::error("La table '$table' n'est pas une table de destination valide. ", $exception);
        }

        // source columns validation
        $columnCount = 0;
        $sql = $this->codeGenerator->generateSQLForSourceColumnsValidationInTable($table, $sourceCodeColumn, $columnCount);
        $sql = $this->codeGeneratorForDestination->generateSQLForSourceColumnsValidationInTable($table, $sourceCodeColumn, $columnCount);
        try {
            $result = $this->queryExecutor->fetchAll($sql, $connection);
        } catch (Exception $e) {
            throw DatabaseServiceException::error("Erreur lors de la validation des colonne de source dans la table destination '$table'", $e);
        }
        $exception = $this->codeGenerator->convertSourceColumnsValidationBadResultToException($table, $sourceCodeColumn, $result, $columnCount);
        $exception = $this->codeGeneratorForDestination->convertSourceColumnsValidationBadResultToException($table, $sourceCodeColumn, $result, $columnCount);
        if ($exception !== null) {
            throw DatabaseServiceException::error("La table '$table' n'est pas une table de destination valide. ", $exception);
        }
@@ -95,16 +95,18 @@ class DatabaseService extends AbstractDatabaseService
     */
    public function validateSourceTable()
    {
        $connection = $this->destination->getConnection();
        $tableName = self::SOURCE_TABLE_NAME;

        // test if table exists
        $this->assertTableExists($tableName, $connection);
        $this->assertTableExistsInDestination($tableName);
    }

    /**
     * Vérifie dans la table SOURCE qu'il existe bien une source ayant le 'code' spécifié.
     *
     * ATTENTION : on parle bien ici de la table nommée `SOURCE` qui doit exister dans la base de données destination,
     * et non pas de la table contenant les données sources de l'import/synchro.
     *
     * @throws \UnicaenDbImport\Service\Exception\DatabaseServiceException
     */
    public function validateCodeExistsInSourceTable(string $code)
@@ -114,13 +116,13 @@ class DatabaseService extends AbstractDatabaseService
        $column = self::SOURCE_TABLE_CODE_COLUMN;

        // test if value exists in table
        $sql = $this->codeGenerator->generateSQLForValueExistenceCheckInTable($column, $code, $tableName);
        $sql = $this->codeGeneratorForDestination->generateSQLForValueExistenceCheckInTable($column, $code, $tableName);
        try {
            $result = $this->queryExecutor->fetchAll($sql, $connection);
        } catch (Exception $e) {
            throw DatabaseServiceException::error("Erreur lors du test d'existence de la valeur '$code' dans la table '$tableName'", $e);
        }
        $exists = $this->codeGenerator->convertValueExistenceCheckInTableResultToBoolean($result);
        $exists = $this->codeGeneratorForDestination->convertValueExistenceCheckInTableResultToBoolean($result);
        if (!$exists) {
            throw DatabaseServiceException::error("Vous devez déclarer une source dans la table '$tableName' dont le $column est '$code'.");
        }
@@ -132,7 +134,7 @@ class DatabaseService extends AbstractDatabaseService
    public function checkIntermediateTableNotExists(string $intermediateTable)
    {
        try {
            $this->assertTableExists($intermediateTable, $this->destination->getConnection());
            $this->assertTableExistsInDestination($intermediateTable);
        } catch (DatabaseServiceException $e) {
            // :-) la table n'existe pas
            return;
@@ -149,7 +151,7 @@ class DatabaseService extends AbstractDatabaseService
     */
    public function createIntermediateTable($intermediateTable)
    {
        $sql = $this->codeGenerator->generateSQLForIntermediateTableCreation($this->source, $this->destination, $intermediateTable);
        $sql = $this->codeGeneratorForDestination->generateSQLForIntermediateTableCreation($this->source, $this->destination, $intermediateTable);
        try {
            $this->queryExecutor->exec($sql, $this->destination->getConnection());
        } catch (Exception $e) {
@@ -162,7 +164,7 @@ class DatabaseService extends AbstractDatabaseService
     */
    public function dropIntermediateTable($intermediateTable)
    {
        $sql = $this->codeGenerator->generateSQLForIntermmediateTableDrop($intermediateTable);
        $sql = $this->codeGeneratorForDestination->generateSQLForIntermmediateTableDrop($intermediateTable);
        try {
            $this->queryExecutor->exec($sql, $this->destination->getConnection());
        } catch (Exception $e) {
@@ -192,7 +194,7 @@ class DatabaseService extends AbstractDatabaseService
            );
        }

        $sql = $this->codeGenerator->generateSQLForClearTable($table);
        $sql = $this->codeGeneratorForDestination->generateSQLForClearTable($table);
        $sql .= " WHERE source_id = (SELECT id FROM source WHERE code = '$sourceId')";
        try {
            $this->queryExecutor->exec($sql, $this->destination->getConnection());
@@ -250,7 +252,7 @@ class DatabaseService extends AbstractDatabaseService
            $preparedRow = $this->prepareSourceDataRow($row);
            $columnsValues = $this->prepareDestinationData($preparedRow);

            $insertsSQL = $this->codeGenerator->generateSQLForInsertOneRowIntoTable($tableName, $columnsValues, $sourceCode, $idColumnStrategy, $idColumnSequence);
            $insertsSQL = $this->codeGeneratorForDestination->generateSQLForInsertOneRowIntoTable($tableName, $columnsValues, $sourceCode, $idColumnStrategy, $idColumnSequence);
            try {
                $n = $this->queryExecutor->exec($insertsSQL, $this->destination->getConnection());
            } catch (Exception $e) {
@@ -372,10 +374,10 @@ class DatabaseService extends AbstractDatabaseService
    public function recreateDiffView(?string $intermediateTable = null): void
    {
        $destinationTable = $this->destination->getTable();
        $diffViewName = $this->codeGenerator->generateDiffViewName($destinationTable);
        $diffViewName = $this->codeGeneratorForDestination->generateDiffViewName($destinationTable);

        try {
            $sql = $this->codeGenerator->generateSQLForDiffViewCreation($this->source, $this->destination, $diffViewName, $intermediateTable);
            $sql = $this->codeGeneratorForDestination->generateSQLForDiffViewCreation($this->source, $this->destination, $diffViewName, $intermediateTable);
        } catch (Exception $e) {
            throw DatabaseServiceException::error("Erreur lors de la génération du SQL de création de la vue différentielle '$diffViewName'", $e);
        }
@@ -392,7 +394,7 @@ class DatabaseService extends AbstractDatabaseService
     */
    public function fetchDiffView(): array
    {
        $sql = $this->codeGenerator->generateSQLForDiffViewSelect($this->source, $this->destination);
        $sql = $this->codeGeneratorForDestination->generateSQLForDiffViewSelect($this->source, $this->destination);

        try {
            return $this->queryExecutor->fetchAll($sql, $this->destination->getConnection());
@@ -406,7 +408,7 @@ class DatabaseService extends AbstractDatabaseService
     */
    public function fetchDiffViewFound(): bool
    {
        $sql = $this->codeGenerator->generateSQLForDiffViewSelect($this->source, $this->destination);
        $sql = $this->codeGeneratorForDestination->generateSQLForDiffViewSelect($this->source, $this->destination);
        $sql = 'select count(*) as found from (' . $sql . ' limit 1) tmp';

        try {
@@ -424,7 +426,7 @@ class DatabaseService extends AbstractDatabaseService
     */
    public function fetchDiffViewCount(): int
    {
        $sql = $this->codeGenerator->generateSQLForDiffViewSelect($this->source, $this->destination);
        $sql = $this->codeGeneratorForDestination->generateSQLForDiffViewSelect($this->source, $this->destination);
        $sql = 'select count(*) as nb from (' . $sql . ') tmp';

        try {
@@ -453,7 +455,7 @@ class DatabaseService extends AbstractDatabaseService
//            ->andWhere("io.enabled = 1")
//            ->addOrderBy('io.operation, io.tableName, io.columnName');
//        $importObservRows = $qb->getQuery()->getResult(Query::HYDRATE_ARRAY);
        $sql = $this->codeGenerator->generateSQLForSelectingInImportObservTable($this->destination->getTable());
        $sql = $this->codeGeneratorForDestination->generateSQLForSelectingInImportObservTable($this->destination->getTable());
        try {
            $importObservRows = $this->queryExecutor->fetchAll($sql, $this->destination->getConnection());
        } catch (Exception $e) {
@@ -461,7 +463,7 @@ class DatabaseService extends AbstractDatabaseService
        }

        if (!empty($importObservRows)) {
            $sql = $this->codeGenerator->generateSQLForInsertionIntoImportObservResult($this->destination, $importObservRows);
            $sql = $this->codeGeneratorForDestination->generateSQLForInsertionIntoImportObservResult($this->destination, $importObservRows);
            try {
                $this->queryExecutor->exec($sql, $this->destination->getConnection());
            } catch (Exception $e) {
@@ -505,7 +507,7 @@ class DatabaseService extends AbstractDatabaseService
        $sqls = [];
        foreach (Operation::OPERATIONS as $operation) {
            $sqls[$operation] =
                $this->codeGenerator->generateSQLForDestinationUpdate($operation, $this->source, $this->destination);
                $this->codeGeneratorForDestination->generateSQLForDestinationUpdate($operation, $this->source, $this->destination);
        }

        return $sqls;
@@ -519,7 +521,7 @@ class DatabaseService extends AbstractDatabaseService
     */
    public function fetchSource(): array
    {
        $selectSql = $this->codeGenerator->generateSQLForSelectFromSource($this->source);
        $selectSql = $this->codeGeneratorForSource->generateSQLForSelectFromSource($this->source);

        try {
            return $this->queryExecutor->fetchAll($selectSql, $this->source->getConnection());
@@ -536,7 +538,7 @@ class DatabaseService extends AbstractDatabaseService
     */
    public function fetchSourceFirstRow(): ?array
    {
        $selectSql = $this->codeGenerator->generateSQLForSelectFromSource($this->source);
        $selectSql = $this->codeGeneratorForSource->generateSQLForSelectFromSource($this->source);

        try {
            return $this->queryExecutor->fetch($selectSql, $this->source->getConnection());
@@ -551,7 +553,7 @@ class DatabaseService extends AbstractDatabaseService
    public function fetchSourceTableColumnNames(): array
    {
        $sourceTableName = $this->source->getTable();
        $selectSql = $this->codeGenerator->generateSQLForSelectSourceTableColumnsInformation($sourceTableName);
        $selectSql = $this->codeGeneratorForSource->generateSQLForSelectSourceTableColumnsInformation($sourceTableName);

        try {
            $result = $this->queryExecutor->fetchAll($selectSql, $this->source->getConnection());
+3 −3
Original line number Diff line number Diff line
@@ -17,14 +17,14 @@ class ImportLogDatabaseService extends AbstractDatabaseService
        $importLogTable = $this->destination->getLogTable();

        try {
            $this->assertTableExists($importLogTable, $connection);
            $this->assertTableExistsInDestination($importLogTable);
            return;
        } catch (DatabaseServiceException $e) {
            // la table n'existe pas
        }

        // create table
        $sql = $this->codeGenerator->generateSQLForImportLogTableCreation($this->destination->getLogTable());
        $sql = $this->codeGeneratorForDestination->generateSQLForImportLogTableCreation($this->destination->getLogTable());
        try {
            $this->queryExecutor->exec($sql, $connection);
        } catch (Exception $e) {
@@ -40,7 +40,7 @@ class ImportLogDatabaseService extends AbstractDatabaseService
    {
        $importLogTable = $this->destination->getLogTable();

        $sql = $this->codeGenerator->generateSQLForInsertResultIntoLogTable($result, $importLogTable);
        $sql = $this->codeGeneratorForDestination->generateSQLForInsertResultIntoLogTable($result, $importLogTable);
        try {
            $this->queryExecutor->exec($sql, $this->destination->getConnection());
        } catch (Exception $e) {