Chapter: Create scripts to install the application
« Using cache | ^ Advanced development | Creating an installation wizard » |
− Table of content
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 moduleinstall.php
to install data of the module at the instance leveluninstall.php
to uninstall data of the module at the instance levelupgrade.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. install_1_6.php
andupgrade_1_6.php
if you want to provide installer/upgrader for application based on Jelix 1.6 and lower. See the Jelix 1.6 documentation to know how to write such installers.
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 ajDbConnection
object. Don't calljDb::getConnection()
directly, because you may don't know the default profile.$helpers->database()->execSQLScript()
: it executes a SQL script stored into theinstall/
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 filesql/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 theinstall/
directory to an other directory of your project. The first parameter is the path of the file to copy, relative to theinstall/
directory. The second parameter is the target path. The target path can be an absolute path, or a prefixed path. Prefixes can bewww:
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 withcopyFile()
$helpers->copyDirectoryContent()
to copy content of a directory, from the install directory to another place, typically to thewww/
of the application. It works like$helpers->copyFile()
$helpers->removeDirectoryContent()
qui permet de supprimer un répertoire que vous avez installé aveccopyDirectoryContent()
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.