Quick links: Content - sections - sub sections
EN FR

Jelix provides a configuration and installation system, which allows to execute scripts when you integrate a module into your application, or when you install your application on a server. See how it works to understand next sections.

All kind of scripts

These scripts are in fact some classes, stored into the directory install/ of the module. Names of classes and files are normalized.

You can provide several kind of scripts:

  • configure.php To set the system configuration and the local configuration of the module
  • install.php to install data of the module at the instance level
  • uninstall.php to uninstall data of the module at the instance level
  • upgrade.php to upgrade data of the module at the instance level
  • several scripts upgrade_xxx.php that are dedicated to a specific version of the module.

The installation can have parameters. install.php and upgrade scripts can have some parameters that are stored into the configuration. Parameters values can be indicated by hand, or asked interactively to the developer by the configuration script of the module.

Classes of these scripts have access to an API which helps the developer to read and write configuration files, do tasks on a database, install some files etc.

However, these APIs are a bit different, depending on the configuration/installation step.

So in at the configuration step (configure.php script), it is possible to modify configuration files of the application in app/system, but not in installation mode (install.php). install.php can only modify local configuration (localconfig.ini.php).

In the installation mode, it is possible to access to the database, but not in the configuration mode. Because this is a step done before to install the application on a server, so there is no database.

Configuration script

When you launch the command php dev.php module:configure, the configurator searches the file configure.php in the directory install/ of your module.

In this file, it should have a class with the name <mymodule>ModuleConfigurator, which should inherits from \Jelix\Installer\Module\Configurator.

After instanciating this class, the Jelix configurator solve dependencies of the module, and then configure other modules that the current module needs, if they are not configured.

Then it retrieves default parameters of the module installer, by calling the method getDefaultParameters(), that you can redefine to indicate the list of parameters and their default values.

The next step is the call of the method preConfigure() of configurators of module that are needed to configure. It it the opportunity in this method, to check things that are important for the module, and to throw an exception if requirements does not exist.

When no method preConfigure() fail, then all methods configure() are called, and then all methods postConfigure() are called. This last method is useful when you want to finish the configuration after the configuration of other modules.

An other specific method can be implemented: localConfigure(). It is called when the user configure an instance of the application (local configuration). It could ask connection parameters for example.

An object PreConfigurationHelpers is given to preConfigure(), and an object ConfigurationHelpers is given to configure(), postConfigure() and localConfigure(). It brings some methods allowing to do many thing.

The first purpose is to access to configuration files of the application and to modify them. getConfigIni() returns an object allowing to modify the configuration file that is relevant for the current context. You have also some methods like declareGlobalWebAssets, getEntryPointsList(), getMainEntryPoint() etc.. See section below that explains all of them.

An other useful method is ConfigurationHelpers::cli() that returns an object InteractiveConfigurator, allowing to ask interactively informations to the user (except when the option --no-interaction has been given on the command line).

These informations may be values for the configuration, but also values for parameters of the module installer. They are stored into the property parameters. It contains default values returns by getDefaultParameters() merged with current values (stored into the installparam option for the module in main configuration).

InteractiveConfigurator has some methods like askConfirmation(), askInformation() etc. In fact it eases the use of object QuestionHelper, Output et Input of the Symfony Console component.

An example with the configurator of jAcl2Db:


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

    // here, default installation parameters
    public function getDefaultParameters()
    {
        return array(
            // parameter to know if default groups should be created
            'defaultgroups' => true,
            // parameter to know if a default user should be created
            'defaultuser' => true
        );
    }

    // called during the framework configuration (system configuration)
    public function configure(\Jelix\Installer\Module\API\ConfigurationHelpers $helpers) {

        // we ask if default groups "admins" and "users" should be created

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

        // we ask if a default user "admin" should be created
        $this->parameters['defaultuser'] = $helpers->cli()
            ->askConfirmation('Do you want to setup default "admin" user in acl2?',
                $this->parameters['defaultuser']);

        // we modify the configuration of jAcl2 to setup the "db" driver
        $config = $helpers->getConfigIni();
        $driver = $config->getValue('driver','acl2');
        if ($driver != 'db') {
            $config->setValue('driver','db','acl2');
        }
    }

    // called during the local configuration (on an application instance)
    public function localConfigure(\Jelix\Installer\Module\API\LocalConfigurationHelpers $helpers) {
        // we can do modification here on the profiles.ini.php, because
        // localConfigure is called when we install or update an application on a server
        $helpers->declareDbProfile('jacl2_profile', null, false);
    }
}

It is possible to "de-configure" a module, in order to delete it. Use the command php dev.php module:unconfigure.

In this case, Jelix will call the method unconfigure() of your class, in which you can remove modification made in configuration files, remove files you installed etc.

An installation script

This is a file, install.php, that you store into the install/ directory of the module.

It should contain a class, inheriting from \Jelix\Installer\Module\Installer, and named <mymodule>ModuleInstaller, where <mymodule> should be the name of the module. Ex: mainModuleInstaller for the main module.

Note: Jelix\Installer\Module\Installer is a new class in Jelix 1.7, and the jInstallerModule class is now deprecated. These two classes have not the same methods.

In your new class, you need to create a method install() where you'll do all things to install the module: database modifications, file copies, configuration changes 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 ...');
    }
}

You can redefine the methods preInstall() and postInstall(), which are executed respectively before and after the installation of all modules. In preInstall() you can prepare some data or files, or you can check that conditions to install the module are met. It not, you can create an exception which will stop the whole 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) {
    }

}

$helpers parameters have some properties and methods which help you to access to the database, the configuration files etc.

However they are not identical. For install(), there is almost same methods to access to the configuration (see next section), as for preInstall(), but it have too a method database() giving a DatabaseHelpers object, and some other methods to install some files.

Access to a database

If your installation script interacts with a database (creating a table, modifying records in some tables etc), you have to use the object DatabaseHelpers given by the method $helpers->database(). It has some methods to execute some requests.

  • $helpers->database()->dbConnection(): returns a jDbConnection object. Don't call jDb::getConnection() directly, because you may don't know the default profile.
  • $helpers->database()->execSQLScript(): it executes a SQL script stored into the install/ directory (or in one of its sub directory). Indicates a simple name, and it will load the script {name}.{dbtype}.sql. for example, if you call $this->execSQLScript('sql/install') and if the database of the default profile is mysql, it will load the file sql/install.mysql.sql. You can indicate the full name of the sql script, but it should be compatible to all databases supported by your application.
  • $this->declareDbProfile() to declare a new connection profile

dbConnection() and execSQLScript() are using the same profile "default" for the connection. An alternate profile can be indicated at several places (listed by priority, the first is the highest priority):

  • call the method $helpers->database()->useDbProfile(), by giving the profile name.
  • In the property defaultDbProfile of your install class, you can indicate the default profile to use for the installation of the module

Parameters for an installation

You may want to execute the installation with some parameters given by the user of your module.

Parameters for an installation script can be simple booleans, or some values. To indicate parameters, the user have to set an option in the modules section of the configuration file of the application. The name of this option is {module}.installparam. For example, for a news module, it will be news.installparam.

In this option, you can indicates simple names (it will be some booleans), or some names and values.


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

Here, parameters will be a boolean named "enablecategories", and a parameter named "defaultcategory" with the value "In the world". We can imagine here that the installation script of the module "news" have the possibility to enable a "categories" management, and we could indicate the name of the default category to create.

To read parameters from the installation script, you have the getParameter method. Indicates the name of the parameter, and it will return its value (true for a boolean). If the parameter does not exists in the installparam option, it returns @@null@. Example:


  function install(\Jelix\Installer\Module\API\InstallHelpers $helpers) {
     if ($this->getParameter('enablecategories')) {
        // here some code to create the categories table for example...
        // ...

        // now create the default category
        $defaultCategory = $this->getParameter('defaultcategory');
        if ($defaultCategory) {
           // here we could insert a record in the categories table
           // with the label given into $defaultCategory.
        }
     }
  }

Modifying configuration files

A Jelix application has several ini files. You should not modify these files yourself in the installation script, but you should use objects like \Jelix\IniFile\IniModifierArray that the install component gives to you.

See the documentation of this library jelix/Inifile for details.

The main method to use to read or modify the configuration is $helpers->getConfigIni(). You don't need to know if the given object read or modify app/system/mainconfig.ini.php, or var/config/localconfig.ini.php or an other file. The installation/configuration system gives you the right file corresponding to the context (system configuration, local configuration, installation...).

With the given object, you can read or write some values as in this example:


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

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

During pre-configuration or pre-installation, it is not possible to modify files, as these steps are only to check things.

You have also methods to access to other configuration files.

In ConfigurationHelpers and PreConfigurationHelpers classes:

  • $helpers->getCoordPluginConfig() to retrieve the configuration of a coordinator plugin
  • $helpers->getProfilesIni() to read/modify the profiles.ini.php file
  • $helpers->configFilePath() to know the path of the current configuration directory. Indeed, it may be app/system or var/config, depending on the context: configuration during the development, configuration of the module on an application instance etc..

In ConfigurationHelpers:

  • $helpers->declareGlobalWebAssets() to define some WebAssets
  • $helpers->removeGlobalWebAssets() to remove some WebAssets
  • $helpers->declareDbProfile() (only on the local configuration) to add a jDb Profile
  • $helpers->removeDbProfile() (only on the local configuration) to remove a jDb Profile

In PreInstallHelpers et InstallHelpers:

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

In InstallHelpers:

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

To acces to the configuration file of an entry point, you should retrieve the object representing the entry point, with methods $helpers->getMainEntryPoint(), $helpers->getEntryPointsList(), $helpers->getEntryPointsById() or $helpers->getEntryPointsByType(), and you should use its method getConfigIni():


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

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

Its other methods are:

  • $entryPoint->getUrlMap() to read/modify URL mapping for the entry point.
  • $entryPoint->getCoordPluginConfig() to retrieve the configuration of a coordinator plugin
  • $entryPoint->declareWebAssets() to define some WebAssets for the entry point
  • $entryPoint->getType(), $entryPoint->getScriptName(), $entryPoint->getFileName() to know which is the entry point.

Installing some files

Your script for configuration or installation could copy some files into specific directories of the application. It could be a configuration file dedicated to the module, or some css/js files to copy into the www directory.

ConfigurationHelpers and InstallHelpers provides some methods to do it:

  • $helpers->copyFile() to copy a file, from the install/ directory to an other directory of your project. The first parameter is the path of the file to copy, relative to the install/ directory. The second parameter is the target path. The target path can be an absolute path, or a prefixed path. Prefixes can be www: indicating the www/ directory, config: indicating app/system or var/config depending on the context.
  • $helpers->removeFile() allowing to delete a file that you installed with copyFile()
  • $helpers->copyDirectoryContent() to copy content of a directory, from the install directory to another place, typically to the www/ of the application. It works like $helpers->copyFile()
  • $helpers->removeDirectoryContent() qui permet de supprimer un répertoire que vous avez installé avec copyDirectoryContent()

Scripts to update a module

These scripts have specific file names: upgrade_{label}.php where {label} is a name which will be part of the name of the class.

Note: In jelix 1.2.5 and lower, the filename could be upgrade_to_{version}_{label}.php, where {version} should be replaced by a version number. This format is now deprecated.

These scripts should be stored into the install/ directory of the module. They will be executed in the ascendant order of the version indicated into the filename. And only those for which the version is higher than the current installed version of the module, and lower and equal than the new version of the module. Imagine that you have these scripts (with deprecated format of names):

  • upgrade_to_1.0_aaa.php (old name)
  • upgrade_zzz.php (declaring version 1.1pre.1234 in the class)
  • upgrade_foo.php (declaring version 1.1pre.1350)
  • upgrade_bar.php (declaring version 1.1)
  • upgrade_fff.php (declaring version 1.2a1)
  • upgrade_eee.php (declaring version 1.2)
  • upgrade_hello.php (declaring version 1.3)

If the current version of the module is 1.1 and the new version of the module (indicated by the new module.xml file) is 1.2, then only these scripts will be executed, in this order:

  • upgrade_fff.php
  • upgrade_eee.php

A script for update should contain a class, named {module}ModuleUpgrader_{label}, where {module} should be the module name, and {label}, the label indicated in the filename of the script.

Because several scripts for update can be executed for the module, then class name must be different (else PHP won't like it). This is why we use a label, which should be different for each script of a module.

The class should inherit from \Jelix\Installer\Module\Installer, so you have exactly same behaviors and methods as in installation script.

As we saw, a class is doing an update for a specific version. You must indicate the version number into the property $targetVersions (which is an array), and a date in the property $date with the format 'yyyy-mm-dd' or 'yyyy-mm-dd HH:ii'.


<?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)  {
       // ....
    }

}

You'll guess that you can indicate several versions in $targetVersions. It is useful when you have several branch in a project, and when an update script should be executed for several branch. With the date of the release, Jelix can determinate if, during an update, it can execute the script or not.

For instance, you have a script for an update for versions 1.24 and 1.35. If the user update from the version 1.2.3 or from the version 1.3.4, the script will be called. If he update from the version 1.2.5 to the version 1.3.6, the script won't be called because the 1.2.6 version contains modifications brought by the 1.2.5 version.

Script to uninstall

You can provide a uninstall script for your module, in the install/uninstall.php file. It is executed when the module is disabled or does not exists anymore into the application. It could remove some file, remove some table or data from the database etc.

Whe you (as developer), you decide to remove a module from the application, you should execute the command dev.php module:unconfigure. This command will call the method unconfigure.php of the configuration script of the module. It will also copy the script uninstall.php into a specific directory of the application (outside the module). You can then remove the source code of the module, and keep uninstall.php until all instances of the application will be upgraded. The installer of jelix of an instance could call this script.

The uninstall script must contain a class inheriting from \Jelix\Installer\Module\Uninstaller, and named <monmodule>ModuleUninstaller, where <monmodule> is the name of the module. Ex: mainModuleUninstaller for the module main.

This class may contain three methods, preUninstall(), uninstall(), postUninstall(), each of them accepting same kind of parameters as install classes.


<?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) {
    }

}

You can do same processing as in an install class. However it mustn't rely on files of the module, as it may be called when the source code of the module is not in the application anymore.