Commit d4abcb93 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Possibilité d'autoriser/interdire l'opération 'undelete' (déhistorisation) sur...

Possibilité d'autoriser/interdire l'opération 'undelete' (déhistorisation) sur certains enregistrements à l'aide d'une colonne dans la table destination ; possibilité d'autoriser l'opération 'update' (mise à jour) même sur un enregistrement historisé à l'aide d'une colonne dans la table destination.
parent 009688d5
Loading
Loading
Loading
Loading
+39 −1
Original line number Diff line number Diff line
@@ -235,8 +235,46 @@ return [
                    // Nom de la colonne dans la table destination contenant l'identifiant unique
                    'source_code_column' => 'COD_PAY',

                    // Filtre SQL éventuel permettant de restreindre les données destinations concernées
                    // Nom de la colonne à prendre en compte dans la table destination pour autoriser/interdire
                    // l'opération 'undelete' (déhistorisation) sur un enregistrement.
                    //
                    // On peut être amené à interdire l'opération 'undelete' lorsqu'on a historisé à dessein des enregistrements
                    // dans la table destination et qu'on ne veut pas les voir réapparaître/déhistorisés lors de la synchro.
                    //
                    // Attention : Si l'opération 'undelete' est globalement interdite (via le flag de la table SOURCE), il ne sera pas
                    // possible de forcer son autorisation en utilisant cette colonne. En revanche, si l'opération est globalement
                    // autorisée il sera possible de forcer son interdiction.
                    //
                    // Valeurs autorisées : chaîne de caractères ou `null`.
                    // Si aucun nom de colonne n'est spécifié, l'opération 'undelete' est autorisée pour tous les enregistrements.
                    // Si un nom de colonne est spécifié, l'opération ne sera possible sur un enregistrement que si
                    // cette colonne contient `true` (ou 1) le concernant.
                    //
                    //'undelete_enabled_column' => 'synchro_undelete_enabled',

                    // Nom de la colonne à prendre en compte dans la table destination pour autoriser/interdire
                    // l'opération 'update' (mise à jour) sur un enregistrement historisé.
                    //
                    // Par défaut lors d'une synchro, un enregistrement est historisé dans la destination parce qu'absent
                    // de la source de données, donc ça n'a pas de sens de vouloir le mettre à jour...
                    // Donc cette option de config s'utilise conjointement à l'option 'undelete_enabled_column'
                    // permettant de maintenir historisé certains enregistrements.
                    //
                    // Attention : Si l'opération 'update' est globalement interdite (via le flag de la table SOURCE), il ne sera pas
                    // possible de forcer son autorisation en utilisant cette colonne. En revanche, si l'opération est globalement
                    // autorisée il sera possible de forcer son interdiction.
                    //
                    // Valeurs autorisées : chaîne de caractères ou `null`.
                    // Si aucun nom de colonne n'est spécifié, le fonctionnement classique de la synchro s'applique :
                    // l'opération 'update' ne peut être appliquée que sur les enregistrements non historisés.
                    // Si un nom de colonne est spécifié, l'opération 'update' pourra s'appliquer sur un enregistrement
                    // historisé si cette colonne contient `true` (ou 1) le concernant.
                    //
                    //'update_if_deleted_enabled_column' => 'synchro_update_if_deleted_enabled',

                    // Filtre SQL permettant de restreindre les données destinations concernées
                    // (les noms de colonnes doivent être préfixés par l'alias de la table destination 'd')
                    //
                    //'where' => "d.TEM_OUV_DRT_SSO_PAY = 'N'",

                    // Stratégie à utiliser pour générer les valeurs dans la colonne ID (clé primaire).
+5 −1
Original line number Diff line number Diff line
@@ -325,6 +325,8 @@ abstract class CodeGenerator implements CodeGeneratorInterface
        $sourceCodeColumn = $source->getSourceCodeColumn();
        $columns = $source->getColumns();
        $includeIdColumn = $destination->getIdColumnStrategy() === DestinationInterface::ID_STRATEGY_IDENTITY;
        $undeleteEnabledColumn = $destination->getUndeleteEnabledColumn();
        $updateOnDeletedEnabledColumn = $destination->getUpdateOnDeletedEnabledColumn();

        // les éventuelles colonnes d'historique dans les données sources seront écrasées :
        $columns = array_diff($columns, [
@@ -344,7 +346,9 @@ abstract class CodeGenerator implements CodeGeneratorInterface
            $destinationTable,
            $sourceCodeColumn,
            $columns,
            $includeIdColumn);
            $includeIdColumn,
            $undeleteEnabledColumn,
            $updateOnDeletedEnabledColumn);
    }

    /**
+38 −10
Original line number Diff line number Diff line
@@ -69,6 +69,8 @@ EOT;
     * @param string $sourceCodeColumn
     * @param array $columns
     * @param bool $includeIdColumn
     * @param ?string $undeleteEnabledColumn
     * @param ?string $updateOnDeletedEnabledColumn
     * @return string
     */
    public function generateSQLForDiffViewCreationOrUpdate(string $diffViewName,
@@ -76,7 +78,9 @@ EOT;
                                                           string $destinationTable,
                                                           string $sourceCodeColumn,
                                                           array  $columns,
                                                           bool   $includeIdColumn): string
                                                           bool   $includeIdColumn,
                                                           ?string $undeleteEnabledColumn,
                                                           ?string $updateOnDeletedEnabledColumn): string
    {
        $res = '';
        if ($sql = $this->generateSQLForViewDropBeforeUpdate($diffViewName)) {
@@ -89,7 +93,9 @@ EOT;
                $destinationTable,
                $sourceCodeColumn,
                $columns,
                $includeIdColumn)) . PHP_EOL;
                $includeIdColumn,
                $undeleteEnabledColumn,
                $updateOnDeletedEnabledColumn)) . PHP_EOL;

        return $res;
    }
@@ -184,13 +190,17 @@ EOT;
     * @param string $sourceCodeColumn
     * @param array $columns
     * @param bool $includeIdColumn
     * @param ?string $undeleteEnabledColumn
     * @param ?string $updateOnDeletedEnabledColumn
     * @return string
     */
    protected function generateDiffViewBodySelectSQLSnippet(string $diffSourceTableName,
                                                            string $destinationTable,
                                                            string $sourceCodeColumn,
                                                            array $columns,
                                                            bool $includeIdColumn): string
                                                            bool $includeIdColumn,
                                                            ?string $undeleteEnabledColumn,
                                                            ?string $updateOnDeletedEnabledColumn): string
    {
        if (!$includeIdColumn) {
            $columns = array_diff($columns, ['ID', 'id']);
@@ -231,6 +241,7 @@ EOT;
        );

        $now = $this->platform->getNowExpression();
        $true = $this->platformSupportsBooleanType() ? 'true' : 1;

        $deletedOnColumn = $this->config->getHistoColumnAliasForDeletedOn();

@@ -241,24 +252,41 @@ EOT;
        // (et non pas de façon exhaustive en une seule fois).
        $requiredValueForSynchroOperationEnabled = $this->platformSupportsBooleanType() ? 'true' : 1;

        // Faut-il prendre en compte une colonne autorisant ou non l'opération 'undelete' sur les enregistrements.
        $andUndeleteOperationAllowedCondition = '';
        if ($undeleteEnabledColumn) {
            $andUndeleteOperationAllowedCondition = "and d.$undeleteEnabledColumn = $true";
        }

        // Faut-il prendre en compte une colonne autorisant l'update sur les enregistrements historisés ?
        $andDeletedOnCondition = "and (d.$deletedOnColumn IS NULL or d.$deletedOnColumn > $now) ";
        if ($updateOnDeletedEnabledColumn) {
            // une valeur 'true' (çàd update autorisée même si historisé) dans cette colonne désactive la condition d'historisation
            $andDeletedOnCondition = "and (d.$updateOnDeletedEnabledColumn = $true or (d.$deletedOnColumn IS NULL or d.$deletedOnColumn > $now)) ";
        }

        return <<<EOT
with diff as (
    SELECT
        coalesce(s.$sourceCodeColumn, d.$sourceCodeColumn) $sourceCodeColumn,
        coalesce(s.source_id, d.source_id) source_id,

        case 
        case         -- NB : l'ordre des when est important ! --
        when src.synchro_insert_enabled = $requiredValueForSynchroOperationEnabled and 
             (s.$sourceCodeColumn IS NOT NULL AND d.$sourceCodeColumn IS NULL) 
             s.$sourceCodeColumn IS NOT NULL AND d.$sourceCodeColumn IS NULL
             then '$insert'
        when src.synchro_update_enabled = $requiredValueForSynchroOperationEnabled and 
             (s.$sourceCodeColumn IS NOT NULL AND d.$sourceCodeColumn IS NOT NULL and (d.$deletedOnColumn IS NULL or d.$deletedOnColumn > $now)) 
             then '$update'
        when src.synchro_undelete_enabled = $requiredValueForSynchroOperationEnabled and 
             (s.$sourceCodeColumn IS NOT NULL AND d.$sourceCodeColumn IS NOT NULL and (d.$deletedOnColumn IS NOT NULL and d.$deletedOnColumn <= $now)) 
             s.$sourceCodeColumn IS NOT NULL AND d.$sourceCodeColumn IS NOT NULL and 
             d.$deletedOnColumn IS NOT NULL and d.$deletedOnColumn <= $now 
             $andUndeleteOperationAllowedCondition
             then '$undelete'
        when src.synchro_update_enabled = $requiredValueForSynchroOperationEnabled and 
             s.$sourceCodeColumn IS NOT NULL AND d.$sourceCodeColumn IS NOT NULL  
             $andDeletedOnCondition
             then '$update'
        when src.synchro_delete_enabled = $requiredValueForSynchroOperationEnabled and 
             (s.$sourceCodeColumn IS NULL AND d.$sourceCodeColumn IS NOT NULL and (d.$deletedOnColumn IS NULL or d.$deletedOnColumn > $now)) 
             s.$sourceCodeColumn IS NULL AND d.$sourceCodeColumn IS NOT NULL and 
             (d.$deletedOnColumn IS NULL or d.$deletedOnColumn > $now)
             then '$delete' 
        end as operation,

+20 −0
Original line number Diff line number Diff line
@@ -110,6 +110,16 @@ class Destination implements DestinationInterface
            ->notEmpty()
            ->string();

        if ($this->config->offsetExists($key = 'undelete_enabled_column'))
            (new AssertionChain($this->config->get($key), "Une string ou null est requis pour la clé suivante: $key"))
                ->nullOr()
                ->string();

        if ($this->config->offsetExists($key = 'update_on_deleted_enabled_column'))
            (new AssertionChain($this->config->get($key), "Une string ou null est requis pour la clé suivante: $key"))
                ->nullOr()
                ->string();

        Assert::true($this->config->offsetExists($key = 'id_strategy'), "La nouvelle clé de config $key est obligatoire");
        (new AssertionChain($this->config->get($key), "Les valeurs autorisées pour la clé $key sont les suivantes : " .
            implode(' ; ', $a = DestinationInterface::ID_STRATEGIES) . " ; null"))
@@ -153,6 +163,16 @@ class Destination implements DestinationInterface
        return $this->config->get('source_code_column');
    }

    public function getUndeleteEnabledColumn(): ?string
    {
        return $this->config->get('undelete_enabled_column');
    }

    public function getUpdateOnDeletedEnabledColumn(): ?string
    {
        return $this->config->get('update_on_deleted_enabled_column');
    }

    public function getColumns(): array
    {
        return $this->config->get('columns');
+15 −0
Original line number Diff line number Diff line
@@ -68,6 +68,21 @@ interface DestinationInterface
     */
    public function getSourceCodeColumn(): string;

    /**
     * Retourne le nom de la colonne éventuelle dans la table destination permettant d'autoriser ou on l'opération 'undelete'.
     *
     * @return string|null Exemple : 'synchro_undelete_enabled'
     */
    public function getUndeleteEnabledColumn(): ?string;

    /**
     * Retourne le nom de la colonne éventuelle dans la table destination permettant d'autoriser ou non l'opération 'update'
     * sur les enregistrements historisés.
     *
     * @return string|null Exemple : 'synchro_update_on_deleted_enabled'
     */
    public function getUpdateOnDeletedEnabledColumn(): ?string;

    /**
     * Retourne les noms des colonnes de la table destination concernées par l'import.
     *