Raccourcis : Contenu - rubriques - sous rubriques
EN FR

Jelix fournit un système de configuration et d'installation automatique qui permet d'exécuter des scripts lorsque vous intégrez un module dans une application, ou que vous installiez l'application sur un serveur. Si ce n'est pas déjà fait, lisez le chapitre sur les principes de fonctionnements du système d'installation, pour comprendre ce qui va suivre.

Les différents scripts

Ces scripts sont en fait des classes, stockées dans le dossier install/ de votre module. Les noms des classes et des fichiers sont normalisés.

Vous pouvez fournir plusieurs scripts :

  • configure.php pour la configuration système et locale du module
  • install.php pour l'installation du module dans une instance
  • uninstall.php pour la désinstallation du module
  • upgrade.php pour la mise à jour d'un module au niveau d'une instance
  • plusieurs scripts upgrade_xxx.php qui sont dédiés chacun à la mise à jour d'une version précise de votre module.

L'installation est paramétrable. C'est à dire que install.php et les scripts d'upgrade peuvent avoir des paramètres qui sont stockés dans la configuration de l'application. Les valeurs des paramètres peuvent être indiquées à la main par le développeur, ou demandées interactivement au développeur par le configurateur du module.

Les classes de ces scripts de configuration/installations ont accés à une API qui va permettre de faire plusieurs choses, comme lire et modifier les fichiers de configuration, faire des opérations en base de données, installer des fichiers dans l'application (JS, CSS...) etc.

Cependant, il faut noter que selon si on est en mode configuration ou installation, ces API diffèrent au niveau du comportement, ou au niveau de leur disponibilité.

Ainsi en mode configuration, il est possible de modifier les fichiers de configuration système mais pas en mode installation. En mode installation, il est possible d'accéder à la base de donnée, mais pas en mode configuration. En effet, en mode configuration système, l'application est en développement, et n'est pas considérée comme une instance. Et les paramètres d'accés à la base de données ne sont pas encore déterminés à ce moment là.

Voyons maintenant tous ces scripts en détails.

Script de configuration

Quand vous lancez la commande dev.php module:configure, le configurateur cherche un fichier configure.php dans le dossier install/ de votre module.

Dans ce fichier doit se trouver une classe de nom <monmodule>ModuleConfigurator, qui doit hériter de \Jelix\Installer\Module\Configurator.

Après avoir instancié cette classe, le configurateur de Jelix résoud les dépendances du module, c'est à dire qu'il va configurer les autres modules nécessaires à ce module, si ils ne sont pas déjà installés.

Il récupère ensuite les paramètres par défaut de l'installateur du module, en appellant la méthode getDefaultParameters(), que vous pouvez donc redéfinir pour renvoyer une liste de paramètres et leurs valeurs.

L'étape suivante est l'appel de la méthode preConfigure() des configurateurs de tous les modules à configurer. C'est l'opportunité pour vérifier des choses importantes pour votre module et d'interrompre la configuration si des prerequis ne sont pas satisfait, au moyen d'une exception.

Si aucune methode preConfigure() échoue, alors toutes les méthodes configure() sont appelées, puis c'est le tour de toutes les méthodes postConfigure(). Ces dernières sont utiles au cas vous voudriez terminer la configuration en fonction de ce que les autres modules ont modifié dans la configuration.

Une méthode particulière peut-être implémentée : localConfigure(). Elle est appelée lorsque l'utilisateur configure une instance de l'application (configuration locale donc). Elle est idéale par exemple pour demander à l'utilisateur des paramètres de connexions à une base de donnée ou autre.

Dans les méthodes configure(), postConfigure() et localConfigure(), c'est le moment de modifier les fichiers de configurations, mais aussi de copier des fichiers dans l'application.

Pour cela un objet PreConfigurationHelpers est passé à preConfigure(), et un object ConfigurationHelpers est passé à configure(), postConfigure() et localConfigure(). Il propose des objets et méthodes qui permettent d'accéder à la plupart des fichiers de configurations dans l'application, et de les modifier.

Ainsi getConfigIni() renvoi un objet permettant de modifier le fichier de configuration. Vous avez aussi des méthodes comme declareGlobalWebAssets, et vous pouvez accéder aux configurations des points d'entrées via des méthodes getEntryPointsList(), getMainEntryPoint() etc.. Voir la section dédiée plus loin qui détaille ces aspects.

Vous avez aussi un objet de type InteractiveConfigurator, renvoyé par la méthode ConfigurationHelpers::cli(), permettant de demander des informations à l'utilisateur de manière interactive (si l'option --no-interaction n'a pas été indiqué en ligne de commande).

Ces informations peuvent être des valeurs de paramètres de configurations, mais aussi des paramètres pour votre installateur qui se trouvent dans la propriété parameters de votre objet de configuration. Notez que cette propriété contient les valeurs par défaut renvoyée par getDefaultParameters(), fusionnées avec les valeurs d'une précédente configuration ou des valeurs indiquées dans le réglage installparam du module dans la configuration générale.

InteractiveConfigurator propose un certain nombre de méthodes, telle que askConfirmation(), askInformation() etc. Elles simplifient l'utilisation des objets QuestionHelper, Output et Input du composant Symfony Console utilisé.

Un exemple avec le configurateur de jAcl2Db :


class jacl2dbModuleConfigurator extends \Jelix\Installer\Module\Configurator {

    // ici on indique les paramètres d'installation et leurs valeurs par défaut
    public function getDefaultParameters()
    {
        return array(
            // parametre pour savoir si il faut créer les groupes par défaut
            'defaultgroups' => true,
            // paramètre pour savoir si il faut créer un utilisateur par défaut
            'defaultuser' => true
        );
    }

    // appelée pour la configuration système du module
    public function configure(\Jelix\Installer\Module\API\ConfigurationHelpers $helpers) {

        // on demande si il faut configurer les groupes par défaut "admins" et "users"

        $this->parameters['defaultgroups'] = $helpers->cli()
            ->askConfirmation('Do you want to setup default "admins" and "users" groups in acl2?',
                $this->parameters['defaultgroups']);

        // on demande si il faut configurer un utilisateur par défaut, "admin"
        $this->parameters['defaultuser'] = $helpers->cli()
            ->askConfirmation('Do you want to setup default "admin" user in acl2?',
                $this->parameters['defaultuser']);

        // on modifie la configuration de manière à spécifier pour jAcl2, le driver "db"
        $config = $helpers->getConfigIni();
        $driver = $config->getValue('driver','acl2');
        if ($driver != 'db') {
            $config->setValue('driver','db','acl2');
        }
    }

    // appelée pour la configuration locale du module
    public function localConfigure(\Jelix\Installer\Module\API\LocalConfigurationHelpers $helpers) {
        // c'est ici que l'on peut faire des modifications dans le profiles.ini.php
        // car localConfigure est appelé lorsqu'on installe ou met à jour une application
        // sur un serveur.
        $helpers->declareDbProfile('jacl2_profile', null, false);
    }

}

Il est possible de "déconfigurer" un module, dans le but de le supprimer, avec la commande dev.php module:unconfigure.

Dans ce cas, le configurateur de Jelix appellera la méthode unconfigure() de votre classe, dans laquelle vous pourrez retirer vos modifications dans les fichiers de configurations, supprimer les fichiers que vous avez installé etc.

Script d'installation

C'est un script, install.php, que vous placez dans le répertoire install/ du module.

Il doit contenir une classe, héritant de \Jelix\Installer\Module\Installer, et nommée <monmodule>ModuleInstaller, où <monmodule> est le nom de votre module. Ex: mainModuleInstaller pour le module main.

Note : Jelix\Installer\Module\Installer est une nouvelle classe dans Jelix 1.7, et de ce fait, la classe jInstallerModule des versions précédentes est dépréciée (même si encore utilisable). Ces deux classes n'ont pas tout à fait les mêmes méthodes.

Dans votre classe d'installation, vous devez créer une méthode install() dans laquelle vous ferez toutes les choses nécessaires à l'installation du module dans l'environnement courant : modifications de la base de données, initialisation de données etc..


<?php
class newsModuleInstaller extends \Jelix\Installer\Module\Installer {

    function install(\Jelix\Installer\Module\API\InstallHelpers $helpers) {
         $db = $helpers->database()->dbConnection();
         $db->exec('CREATE TABLE IF NOT EXISTS foo ...');
    }
} 

Vous pouvez surcharger les fonctions preInstall() et postInstall() qui sont exécutées respectivement avant et après que tous les modules soient installés. La méthode preInstall(), vous permet par exemple de préparer certains fichiers ou données, ou de vérifier les conditions requises pour l'installation. Si les conditions ne sont pas requises, vous pouvez alors émettre une exception qui stoppera le processus d'installation.


<?php
class newsModuleInstaller extends \Jelix\Installer\Module\Installer {

    function preInstall(\Jelix\Installer\Module\API\PreInstallHelpers $helpers) {
    }

    function install(\Jelix\Installer\Module\API\InstallHelpers $helpers) {
    }

    function postInstall(\Jelix\Installer\Module\API\InstallHelpers $helpers) {
    }

} 

Les paramètres $helpers contiennent un certain nombre de propriétés et de méthodes qui vous aideront à accéder à la base de données, aux fichiers de configuration etc..

Cependant ils ne sont pas tout à fait identiques. Pour install(), on y retrouve à peu près les mêmes méthodes pour accéder à la configuration (voir section suivante) que pour preInstall(), mais aussi la méthode database() renvoyant un objet DatabaseHelpers, et des méthodes pour installer des fichiers.

Accéder à une base de donnée

Si votre script d'installation du module interagit avec une base de donnée (création d'une table, modifications d'enregistrements etc), vous devez utilisez l'objet DatabaseHelpers renvoyé par $helpers->database(), qui vous fournira des méthodes pour exécuter des requêtes.

  • $helpers->database()->dbConnection(): retourne un objet jDbConnection. Ne pas appeler jDb::getConnection() directement, car en fait vous ne savez pas vraiment quel est le profil par défaut.
  • $helpers->database()->execSQLScript(): exécute un script SQL stocké dans le répertoire install/ (ou dans un des ses sous-répertoires) ou celui d'un autre module. Indiquer simplement un nom, et il chargera le script nommé {name}.{dbtype}.sql. Par exemple, si on appelle $this->execSQLScript('sql/install') et si la base de données du profil par défaut est mysql, le fichier sql/install.mysql.sql sera chargé. Il est possible d'indiquer le nom complet du script ('sql/install.sql'), mais celui-ci doit être compatible avec toutes les bases de données supportées par votre application.
  • $this->declareDbProfile() pour déclarer un nouveau profile de connexion pour jDb

dbConnection() et execSQLScript() utilisent le profil "default" pour se connecter. Un profil alternatif peut être indiqué en divers endroits (listés ici par ordre de priorité, le premier étant le plus prioritaire) :

  • appelez la méthode $helpers->database()->useDbProfile(), en lui donnant le nom du profil à utiliser.
  • Dans la propriété defaultDbProfile de votre classe d'installation, vous pouvez indiquer le profil à utiliser pour l'installation du module

Paramètres pour une installation

Il est possible que vous vouliez pouvoir avoir des paramètres d'installation, que l'utilisateur du module indiquera pendant la configuration du module.

Les paramètres d'un script d'installation peuvent être de simples booléens, ou des valeurs. Pour indiquer des paramètres, l'utilisateur doit définir une option dans la section modules du fichier de configuration de l'application. Le nom de cette option est {module}.installparam. Par exemple, pour un module news, ce sera news.installparam.

Dans ces options, il est possible d'indiquer de simples noms (ce seront des booléens), ou des noms avec des valeurs.


news.installparam = "enablecategories;defaultcategory=In the world"

Ici, les paramètres seront un booléen nommé "enablecategories", et un paramètre nommé "defaultcategory" avec la valeur "In the world". Il est possible d'imaginer ici que le script d'installation du module "news" ait la possibilité d'activer la gestion de catégories, et nous indiquerions la catégorie par défaut à créer.

Pour lire les paramètres depuis le script d'installation, vous avez la méthode getParameter. Indiquez le nom du paramètre, et elle retournera sa valeur (true pour un booléen). Si le paramètre n'existe pas dans l'option installparam , elle retourne null. Exemple :


  function install(\Jelix\Installer\Module\API\InstallHelpers $helpers) {
     if ($this->getParameter('enablecategories')) {
        // ici du code pour créer la table des catégories par exemple...
        // ...

        // création de la catégorie par défaut
        $defaultCategory = $this->getParameter('defaultcategory');
        if ($defaultCategory) {
           // là on pourrait insérer un enregistrement dans la table des catégories
           // avec le label donné dans $defaultCategory.
        }
     }
  }

Modifier les fichiers de configurations

Une application Jelix a plusieurs fichiers de configuration ini. Dans vos scripts de configuration ou d'installation, vous ne devriez pas modifier vous même ces fichiers avec les fonctions traditionnelles de manipulation de fichiers, mais vous devez utiliser les objets de type \Jelix\IniFile\IniModifierInterface que les composants de configuration/installation vous donnent.

La principale méthode à utiliser pour lire ou modifier la configuration est la méthode $helpers->getConfigIni(). Vous n'avez pas à vous préoccuper de savoir si l'objet renvoyé lit/modifie app/system/mainconfig.ini.php, var/config/localconfig.ini.php ou autre. Le système d'installation/configuration vous donne le fichier qui correspond au contexte d'utilisation (configuration système, configuration locale, installation...).

Avec l'objet que vous retourne cette méthode, vous pouvez lire et modifier des valeurs :


    $value = $helpers->getConfigIni()->getValue('disableCache', 'zones');

    $helpers->getConfigIni()->setValue('disableCache', false, 'zones');

Sachez que pendant les phases de pré-configuration et de pré-installation, il n'est pas possible de modifier les fichiers de configuration, étant donné que ces phases sont destinées à faire des vérifications, et non à modifier quoi que ce soit.

Vous avez également des méthodes pour modifier d'autres aspects de la configuration.

ConfigurationHelpers et PreConfigurationHelpers :

  • $helpers->getCoordPluginConfig() récupérer la configuration d'un plugin du coordinateur
  • $helpers->getProfilesIni() pour lire/modifier le fichier profiles.ini.php
  • $helpers->configFilePath() pour connaître le chemin du répertoire de configuration. En effet, cela peut être app/system ou var/config, selon si le module est en train d'être configurer pendant le développement, ou ajouté dans une application existante en locale. Cette méthode vous permet de ne pas vous poser de question

ConfigurationHelpers :

  • $helpers->declareGlobalWebAssets() pour définir des WebAssets
  • $helpers->removeGlobalWebAssets() pour enlever des WebAssets
  • $helpers->declareDbProfile() (seulement contexte local) pour ajouter un profile jDb
  • $helpers->removeDbProfile() (seulement contexte local) pour enlever un profile jDb

PreInstallHelpers et InstallHelpers :

  • $helpers->getCoordPluginConfig()
  • $helpers->getLocalConfigIni()
  • $helpers->getProfilesIni()

InstallHelpers :

  • $helpers->declareDbProfile()
  • $helpers->removeDbProfile()
  • $helpers->getLiveConfigIni()
  • $helpers->declareGlobalWebAssets()
  • $helpers->removeGlobalWebAssets()

Pour accéder au fichier de configuration d'un point d'entrée, vous devez récupérer l'objet représentant le point d'entrée, au moyen des méthodes $helpers->getMainEntryPoint(), $helpers->getEntryPointsList(), $helpers->getEntryPointsById() ou $helpers->getEntryPointsByType(), et d'utiliser sa méthode getConfigIni() :


    $entryPoint = $helpers->getMainEntryPoint();
    $entryPointConfig = $entryPoint->getConfigIni();
    $value = $entryPointConfig->getValue('disableCache', 'zones');

    $entryPointConfig->setValue('disableCache', false, 'zones');

Ses autres méthodes sont :

  • $entryPoint->getUrlMap() pour déclarer des urls du module dans urls.xml
  • $entryPoint->getCoordPluginConfig() pour accéder à la configuration d'un plugin
  • $entryPoint->declareWebAssets() (pas en préconfiguration)
  • $entryPoint->getType(), $entryPoint->getScriptName(), $entryPoint->getFileName() pour savoir de quel point d'entrée il s'agit.

Installer des fichiers

Votre script de configuration ou d'installation peuvent devoir copier des fichiers dans des répertoires précis de votre application. Cela peut être un fichier de configuration spécifique à votre module, ou des fichiers css et js à copier dans le répertoire www de l'application.

ConfigurationHelpers et InstallHelpers proposent des méthodes pour cet usage :

  • $helpers->copyFile() pour copier un fichier particulier, du répertoire install vers un autre endroit ou la configuration. Le premier argument est le chemin du fichier à copier, relatif au répertoire install/, le deuxième est le chemin de destination. Par défaut, cela doit être un chemin complet, mais il est possible d'utiliser des prefixes, qui indiquent un des répertoires de l'appli. Ainsi www: indique le répertoire www, config: indique app/system ou var/config suivant le contexte, ou encore var: indique le répertoire var de l'application.
  • $helpers->removeFile() qui permet de supprimer un fichier que vous avez installé avec copyFile()
  • $helpers->copyDirectoryContent() pour copier des fichiers, du répertoire install/ vers un autre endroit, typiquement vers le répertoire www/ de l'application ou la configuration. Les préfixes utilisables pour getFile() le sont aussi pour cette méthode.
  • $helpers->removeDirectoryContent() qui permet de supprimer un répertoire que vous avez installé avec copyDirectoryContent()

Scripts de mise à jour d'un module

Ces scripts ont des noms de fichiers spécifiques. Ils doivent avoir pour nom upgrade_{label}.php{label} doit être remplacé par un nom qui sera une partie du nom de la classe.

Note: Jusqu'à Jelix 1.2.5, les noms des fichiers devaient être upgrade_to_{version}_{label}.php, où {version} était un numéro de version. Ces noms restent compatibles mais ils sont obsolètes.

Ces scripts doivent être stockés dans le répertoire install/ du module. Il seront exécutés en ordre ascendant de version indiquée dans la classe d'installation (Jelix 1.2.6 ou plus) ou dans le nom de fichier (Jelix 1.2.5 et inférieur). Et seuls ceux dont la version est plus grande que la version actuelle installée du module, et plus petite ou égale à la nouvelle version du module, seront exécutés. Imaginez que vous ayez ces scripts :

  • upgrade_to_1.0_aaa.php (ancien nomage)
  • upgrade_zzz.php (déclarant la version 1.1pre.1234 dans la classe)
  • upgrade_foo.php (déclarant la version 1.1pre.1350)
  • upgrade_bar.php (déclarant la version 1.1)
  • upgrade_fff.php (déclarant la version 1.2a1)
  • upgrade_eee.php (déclarant la version 1.2)
  • upgrade_hello.php (déclarant la version 1.3)

Si la version courant du module est 1.1 et que la nouvelle version du module (indiquée par le nouveau fichier module.xml) est 1.2, alors seuls les scripts suivants seront lancés, dans cet ordre:

  • upgrade_fff.php
  • upgrade_eee.php

Un script de mise à jour contient une classe, appelée {module}ModuleUpgrader_{label}, où {module} doit être le nom du module, et {label}, le label indiqué dans le nom de fichier du script.

Puisque plusieurs scripts de mise à jour peuvent être exécutés pour le module, alors le nom de classe doit être différent. C'est pourquoi nous utilisons un label, qui doit être différent pour chaque script du module.

Tout comme les scripts d'installation, la classe devra hériter de \Jelix\Installer\Module\Installer. Vous avez donc les mêmes comportements et méthodes que le script d'installation.

Comme on l'a vu, une classe fait une mise à jour pour une version particulière. Il faut indiquer ce numéro de version dans la propriété $targetVersions (qui est un tableau), et une date au format 'yyyy-mm-dd' ou 'yyyy-mm-dd HH:ii' dans la propriété $date.


<?php
class newsModuleUpgrader_fff extends \Jelix\Installer\Module\Installer {

    public $targetVersions = array('1.2');
    public $date = '2001-06-21';

    function install(\Jelix\Installer\Module\API\InstallHelpers $helpers)  {
       // ....
    }

} 

Vous devinerez que vous pouvez indiquer plusieurs versions dans $targetVersions. Cela est utile quand vous avez plusieurs branches d'un projet, et qu'un script de mise à jour, faisant la même chose, est nécessaire dans chaque branche. Avec la date de la version, Jelix peut déterminer si, lors d'une mise à jour, quel que soit la branche, il peut exécuter le script ou non.

Exemple : vous avez un script de mise à jour pour la version 1.2.4 et 1.3.5. Si l'utilisateur met à jour depuis la version 1.2.3, ou depuis la version 1.3.4, le script sera appelé. Par contre si il met à jour depuis une version 1.2.5 vers une version 1.3.6, le script ne sera pas exécuté, puisque la version 1.2.6 était censé déjà inclure la modification apportée par la 1.2.4. Et il le sait en comparant la date des versions que l'utilisateur a installé à l'origine, celle des versions qu'il utilise actuellement, et celle des versions qu'il va installer.

Script de désinstallation

Vous pouvez fournir un script de désinstallation du module uninstall.php, qui pourra faire le nettoyage au niveau d'une instance de l'application, lorsqu'un module est retiré de l'application. Ce nettoyage peut consister à supprimer des tables d'une base de donnée par exemple ou tout autre chose qu'a effectué le script d'installation.

Lorsque vous, le développeur, décidez de retirer un module de votre application, vous devez appeler la commande dev.php module:unconfigure. Cette commande va appeler la méthode unconfigure.php du script de configuration du module. Elle va aussi copier le script de désinstallation uninstall.php du module dans un sous répertoire install/ de l'application. Vous pouvez ainsi retirer les sources du modules, sans que uninstall.php soit supprimé.

L'installateur de Jelix pourra alors appeler ce script quand il sera lancé sur une instance de l'application.

Le script de désinstallation doit contenir une classe héritant de \Jelix\Installer\Module\Uninstaller, et nommée <monmodule>ModuleUninstaller, où <monmodule> est le nom de votre module. Ex: mainModuleUninstaller pour le module main.

Cette classe peut contenir trois méthodes, preUninstall(), uninstall(), postUninstall(), acceptant le même type de paramètres que les méthodes d'une classe d'installation.


<?php
class newsModuleUninstaller extends \Jelix\Installer\Module\Uninstaller {

    function preUninstall(\Jelix\Installer\Module\API\PreInstallHelpers $helpers) {
    }

    function uninstall(\Jelix\Installer\Module\API\InstallHelpers $helpers) {
    }

    function postUninstall(\Jelix\Installer\Module\API\InstallHelpers $helpers) {
    }

}

Vous pouvez y faire les mêmes traitements que dans une classe d'installation à ceci près, qu'elle ne doit pas utiliser des fichiers du module, puisque ceux-ci ne sont plus censé exister lors de son exécution.