Chapter: Create scripts to install the application
« Using cache | ^ Advanced development | Creating an installation wizard » |
− Table of content
Since 1.2, Jelix provides an installation system, which allows to execute scripts when you want to install a module inside an application, or to install the whole application.
How a module is installed ¶
When you install a module with the installmodule
or the installapp
command :
- jelix looks at the
modules
section inside the configuration of each entry point, and retrieve the access value of the module - It will launch the installation of the module for each entry points where the access value of the module is higher than 0
- It then looks at the
var/config/installer.ini.php
file: it checks if the module is already installed - If it is already installed, it will execute all scripts of update provided by the module, corresponding to a version between the installed version and the new version of the module
- If it is not already installed, it will execute the installation script provided by the module
- After the installation or the update, Jelix stored the new version number of the module into
installer.ini.php
.
Of course, installation scripts or scripts of update are not required.
But if you provide them, it is very important to store into the module.xml file, a good version number and the date of the release !
Why is an installation script called several time? ¶
Your installation probably needs to do some modifications specifically to each entry points. But the installation system doesn't know if your script will do it, and the installation script doesn't know in advance, how many and which entry points the application have (Remember that your module could be reuse in others applications).
This is why the installation script is executed for each entry points.
However, you probably don't want to execute the same thing for each entry points, or for the same database profile. Fortunately, you have some method to know easily if you can execute some things, without knowing the number of entry points or profile configuration.
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 jInstallerModule
, and named {module}ModuleInstaller
, where {module}
should be the name of the module. Ex: mainModuleInstaller
for the main
module.
In this 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 jInstallerModule {
function install() {
if ($this->firstDbExec()) {
$db = $this->dbConnection();
$db->exec('CREATE TABLE...');
}
}
}
You can redefine the methods preInstall
and postInstall
, which are executed respectively before and after the installation of all modules.
<?php
class newsModuleInstaller extends jInstallerModule {
function install() {
if ($this->firstDbExec()) {
$db = $this->dbConnection();
$db->exec('CREATE TABLE...');
}
}
}
jInstallerModule
contains a number of properties and method which helps you to access to the database, to the configuration file etc..
Main properties or methods ¶
Here are some of methods or properties you can use:
$this->dbConnection()
: it returns ajDbConnection
object. Don't calljDb::getConnection()
, because you don't really know which is the profile used for the module.$this->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->copyDirectoryContent()
to copy some files, from the install directory to another place, typically to thewww/
of the application$this->config
: thejIniMultifilesModifier
object corresponding to the configuration file of the current entry point. With this object, you can retrieve content of the configuration file or to set parameters.
Don't hesitate to read the reference API of jInstallerModule
and jInstallerBase
, and to look at the installation script of modules provided by Jelix. You'll certainly learn many things.
To not execute some part of your script ¶
You notice that in the example, we call the method firstDbExec
. It tells you if this is the first time that you want to access to the database, for the current database profile (some entry points can share the same database profile). Remember that your installation script is called for each entry points (read above).
You have also the method firstConfExec
to know if you did already have some changes to the current configuration file (some entry points can share the same configuration file, other than defaultconfig.ini.php
). If it returns true, you can then access to the configuration file, by retrieving the config
property, which is a jIniMultifilesModifier
object.
Then you have the method firstExec
. You pass a keyword to this method. And it tells you if you already call this method with this keyword (false) or not (true). You call this method to determine yourself, in some conditions, if you want to execut severalt time a part of your installation script.
Database profile used for the installation ¶
If your installation script interacts with a database (creating a table, modifying records in some tables etc), you have to use the method dbConnection()
or execSQLScript
to exécute queries. By default, it uses the "default" profile. An alternate profile can be indicated in several places (listed by priority, the first has the higher priority):
- In your install class, you call
useDbProfile
, by given the profile you want to use. - 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() {
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.
}
}
}
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. 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
upgrade_to_1.1pre.1234_bbb.php
upgrade_to_1.1pre.1350_ccc.php
upgrade_to_1.1_ddd.php
upgrade_to_1.2a1_eee.php
upgrade_fff.php
(new name format, with a version number 1.2, indicated into the class)upgrade_to_1.3_ggg.php
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_to_1.2a1_eee.php
upgrade_fff.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. (Jelix developers could use the version number instead of a label, but unfortunately, PHP doesn't like characters like "." or "-" in a class name).
The class should inherit from jInstallerModule
, so you have exactely same behaviors and methods as in installation script. So you must implements a method install
, you can call firstDbExec
, getParameter
etc..
For scripts with new names (jelix 1.2.6 and higher), 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 jInstallerModule {
public $targetVersions = array('1.2');
public $date = '2001-06-21';
function install() {
// ....
}
}
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.