# Mécanique de migration

Lors d'une mise à jour d'un module, il est parfois nécessaire d'utiliser des scripts pour effectuer des opérations de migrations ou des traitements spécifiques.

# Enregistrement d'un script de migration

Le lancement de ces scripts de migration est commandé dans le fichier info.xml du module par l'utilisation d'une directive <process command="./programs/RunMigrationScript.php>"/> dans la section <post-upgrade>.

  • Exemple de déclaration type pour le lancement de scripts de migration :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<module xmlns="https://platform.anakeen.com/4/schemas/app/1.0" name="mon-module" vendor="Anakeen" version="1.0.2">
    <post-install>
        [...]
</post-install>
<post-upgrade>
    <process command="./programs/RunMigrationScript.php --file=./vendor/Anakeen/Hub/Migration/resetHubConfigurationField.xml">
        <label>Apply Migrate HubGenericConfiguration Rules</label>
    </process>
    [...]
</post-upgrade>
</module>

# Syntaxe d'un script de migration

Un script de migration Anakeen Platform est déterminé par trois éléments principaux qui représentent une <migration:action> : précondition/condition, processus et vérification.
Ces éléments sont caractérisés par les balises <migration:condition>, <migration:process> et <migration:check> respectivement.

  • Exemple :
<?xml version="1.0" ?>
<migration:config xmlns:migration="https://platform.anakeen.com/4/schemas/migration/1.0">
    <migration:action id="hubGenericConfiguration" label="Remove hge_component_libname field from HubGenericConfiguration">
        <migration:condition logical-operator="and">
            <migration:sql-assert-not-empty label="verify hge_component_libname field exists"><![CDATA[
                select * from docattr where id='hge_component_libname';
            ]]></migration:sql-assert-not-empty>
            <migration:sql-assert-not-empty label="verify hge_component_txtname field exists"><![CDATA[
                  select * from docattr where id='hge_component_txtname';
              ]]></migration:sql-assert-not-empty>
        </migration:condition>
        <migration:process>
            <migration:sql-query label="Remove hge_component_libname field"><![CDATA[
                delete from docattr where id='hge_component_libname';
            ]]></migration:sql-query>
        </migration:process>
        <migration:check>
            <migration:sql-assert-empty label="verify hge_component_libname field has been removed"><![CDATA[
                select * from docattr where id='hge_component_libname';
            ]]></migration:sql-assert-empty>
        </migration:check>
    </migration:action>
</migration:config>

# Déroulement du script de migration

Avant d'exécuter un script de migration, celui-ci va vérifier que toutes les conditions décrites dans la balise <migration:condition> soient bien respectées.
Une transaction est déposée sur la base de données.
Si celles-ci sont validées, alors le script passe à l'exécution du processus de migration (<migration:process>).
Lorsque la migration est terminée, le script lance une vérification (<migration:check>) des conditions de fin de migration.
Si le test est positif la transaction est commitée, sinon un rollback est fait.

# Validation des conditions

Il existe différents moyens de validation des conditions :

  • migration:sql-assert-false (LabelStringType)

    Vérifie que la requête SQL retourne faux.

  • migration:sql-assert-true (LabelStringType)

    Vérifie que la requête SQL retourne true

  • migration:sql-assert-not-empty (LabelStringType)

    Vérifie que le retour de requête n'est pas vide.

  • migration:sql-assert-empty (LabelStringType)

    Vérifie que le retour de requête est vide.

  • migration:php-assert-code-return-false (phpCodeType)

    Vérifie que l'exécution du code PHP retourne false.

  • migration:php-assert-code-return-true (phpCodeType)

    Vérifie que l'exécution du code PHP retourne true.

  • migration:php-assert-true (phpMethodType)

    Vérifie que le retour de la méthode PHP est valué à true.

  • migration:php-assert-false (phpMethodType)

    Vérifie que le retour de la méthode PHP est valué à false.

# Processus de migration

Il existe différents processus de migration :

  • migration:bash-code :

    Script de commande CLI.
    Attributs :

    • label (string) : Libellé du processus (obligatoire),
    • stop-on-error (boolean) : Indique l'arrêt du processus en cas d'erreur.

Exemple : Rechargement des routes de configuration

<migration:bash-code label="Reload routes configuration"><![CDATA[
#!/bin/bash
./ank.php --system --reloadConfig
]]></migration:bash-code>
  • migration:sql-queryType

    Utilisation de requête SQL sur la base de données.
    Attributs :

    • label (string) : Libellé du processus (obligatoire),
    • stop-on-error (boolean) : Indique l'arrêt du processus en cas d'erreur.

Exemple : suppression du Smart Field hge_component_libname

<?xml version="1.0" ?>
<migration:config xmlns:migration="https://platform.anakeen.com/4/schemas/migration/1.0">
    <migration:action id="hubGenericConfiguration" label="Remove hge_component_libname field from HubGenericConfiguration">
        <migration:condition>
            <migration:sql-assert-not-empty label="verify hge_component_libname field exists"><![CDATA[
                select * from docattr where id='hge_component_libname';
            ]]></migration:sql-assert-not-empty>
        </migration:condition>
        <migration:process>
            <migration:sql-query label="Remove hge_component_libname field"><![CDATA[
                delete from docattr where id='hge_component_libname';
            ]]></migration:sql-query>
        </migration:process>
        <migration:check>
            <migration:sql-assert-empty label="verify hge_component_libname field has been removed"><![CDATA[
                select * from docattr where id='hge_component_libname';
            ]]></migration:sql-assert-empty>
        </migration:check>
    </migration:action>
</migration:config>

Avertissements

Si la vérification post processus n'est pas validée, alors la requête SQL est annulée.

  • migration:php

    Utilisation de méthodes PHP.
    Attributs :

    • label (string) : Libellé du processus (obligatoire),
    • stop-on-error (boolean) : Indique l'arrêt du processus en cas d'erreur,
    • callable (callableType) : Méthode appelée durant l'exécution du processus (obligatoire).

Exemple :

<?xml version="1.0" ?>
<migration:config xmlns:migration="https://platform.anakeen.com/4/schemas/migration/1.0">
    <migration:action id="hubGenericConfiguration" label="Remove hge_component_libname field from HubGenericConfiguration">
        <migration:condition>
            <migration:sql-assert-not-empty label="verify hge_component_libname field exists"><![CDATA[
                select * from docattr where id='hge_component_libname';
            ]]></migration:sql-assert-not-empty>
        </migration:condition>
        <migration:process>
           <migration:php label="Use MyMethod" callable="My\MyMethod::MyMethod()"/>
        </migration:process>
        <migration:check>
            <migration:sql-assert-empty label="verify hge_component_libname field has been removed"><![CDATA[
                select * from docattr where id='hge_component_libname';
            ]]></migration:sql-assert-empty>
        </migration:check>
    </migration:action>
</migration>
  • migration:php-code

    Utilisation d'instructions PHP.
    Attributs :

    • load-context (boolean) : Indique le chargement du contexte,
    • stop-on-error (boolean) : Indique l'arrêt du processus en cas d'erreur,

Exemple : Ajout d'un historique pour indiquer que le Smart Element a été migré

<?xml version="1.0" ?>
<migration:config xmlns:migration="https://platform.anakeen.com/4/schemas/migration/1.0">
    <migration:action id="hubGenericConfiguration" label="Remove hge_component_libname field from HubGenericConfiguration">
        <migration:condition>
            <migration:sql-assert-not-empty label="verify bill_author_display field exists">
                select * from docattr where id='bill_author_display';
            </migration:sql-assert-not-empty>
        </migration:condition>
        <migration:process>
            <migration:php-code><![CDATA[
                <?php
                    use Anakeen\Search\SearchElements;
                    use Anakeen\Search\Filters\Contains;
                    use SmartStructure\Fields\Devbill as devbill;

                    $s = new SearchElements("DEVBILL");
                    $s->addFilter(new Contains(devbill::bill_author_display, "Jean"));
                    $res = $s->search()->getResults();
                    foreach ($res as $r) {
                        $r->addHistoryEntry("end of migration revision");
                    }
                ?>
            ]]></migration:php-code>
        </migration:process>
        <migration:check>
            <migration:php-assert-code-return-true label="verify bill_author_display field exists"><![CDATA[
                <?php
                    use Anakeen\Search\SearchElements;
                    use Anakeen\Search\Filters\Contains;
                    use SmartStructure\Fields\Devbill as devbill;

                    $s = new SearchElements("DEVBILL");
                    $s->addFilter(new Contains(devbill::bill_author_display, "Jean"));
                    $res = $s->search()->getResults();
                    foreach ($res as $r) {
                        $histo = $r->getHisto(false);
                        foreach ($histo as $h) {
                            if (strcmp($h["comment"], "end of migration revision") === 0) {
                                return true;
                            } else {
                                return false;
                            }
                        }
                    }
                ?>
            ]]></migration:php-assert-code-return-true>
        </migration:check>
    </migration:action>
</migration>