Chapitre: Créer des scripts d'installation automatiques
« Utiliser le cache | ^ Développement avancé | Créer un wizard d'installation » |
− Table des matières
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 moduleinstall.php
pour l'installation du module dans une instanceuninstall.php
pour la désinstallation du moduleupgrade.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. install_1_6.php
etupgrade_1_6.php
pour rendre votre module compatible avec l'ancienne API de Jelix 1.6. Voir la documentation de Jelix 1.6 pour savoir comment les construire.
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 objetjDbConnection
. Ne pas appelerjDb::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épertoireinstall/
(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 fichiersql/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. Ainsiwww:
indique le répertoire www,config:
indique app/system ou var/config suivant le contexte, ou encorevar:
indique le répertoire var de l'application.$helpers->removeFile()
qui permet de supprimer un fichier que vous avez installé aveccopyFile()
$helpers->copyDirectoryContent()
pour copier des fichiers, du répertoire install/ vers un autre endroit, typiquement vers le répertoirewww/
de l'application ou la configuration. Les préfixes utilisables pourgetFile()
le sont aussi pour cette méthode.$helpers->removeDirectoryContent()
qui permet de supprimer un répertoire que vous avez installé aveccopyDirectoryContent()
Scripts de mise à jour d'un module ¶
Ces scripts ont des noms de fichiers spécifiques. Ils doivent avoir pour nom
upgrade_{label}.php
où {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.