====== Add a plugin installation procedure ======
===== Introduction =====
Sometimes, a plugin may need additional parameters, or to modify a database schema. This step is covered by the automatic installation procedure. In fact, this procedure is semi-automatic and leaves great flexibility for the developer to make a specific installation and update procedure.
===== The _install.php file =====
The whole installation and automatic update procedure is handled by the **_install.php** file in your plugin. If such a file exists, it will be called everytime the user goes in his/her blog admin dashboard.
This file contains some PHP code indicating its status in three different ways:
* **return true**: The plugin was installed
* **return**: Nothing to do, no message (to be used when there is nothing necessary)
* **throw new Exception**('error message'): if any error occurs
Let's see a simple example. Our plugin is called //toto// and is going to save its version in the versions table.
plugins->moduleInfo('toto','version');
# We read the plugin version in the versions table
$i_version = $core->getVersion('toto');
# The version in the table is greater or equal to
# the module one, we do not do anything since this
# one is already installed.
if (version_compare($i_version,$m_version,'>=')) {
return;
}
# The install procedure really starts here
$core->setVersion('toto',$m_version);
?>
The name passed to **moduleInfo** is not necessarily the plugin name defined in **_define.php**: it is the directory name where is stored your plugin!
===== Create new preferences =====
Your plugin may need preferences to work. It is a good idea to use the automatic installation to create them.
Here is an example of automatic installation adding a global preference:
plugins->moduleInfo('toto','version');
$i_version = $core->getVersion('toto');
if (version_compare($i_version,$m_version,'>=')) {
return;
}
# Setting creation (if it exists, it will be kept)
$core->blog->settings->addNamespace('toto');
$settings->toto->put('toto_setting',true,'boolean','toto setting',false,true);
$core->setVersion('toto',$m_version);
?>
addNamespace() parameter must only contain digits or characters without accents.
Allowed: [a-zA-Z][a-zA-Z0-9]
The $type parameter of put can be 'string', 'integer', 'float', 'boolean' or 'null'.
If $type is 'null' and the setting already exists, the current type will be kept.
Else, the 'string' type will be applied.
Please check the [[.:settings|settings]] documentation to use those parameters after installation.
===== Modify the database schema =====
One of the most interesting features of the installation system is to allow you to easily modify database schema. You can create new tables, add fields in an existing table, create indexes or references.
==== UDBS ====
UDBS stands for "Universal DataBase Schema". This system defines a database schema then compares it to the existing one to update it if required.
Since UDBS is compatible with multiple database types, it has a few limits:
* You cannot delete a field. UDBS only creates or updates.
* UDBS can rename an index or changes its related fields, but not both at the same time (it will create a new index).
* Only some data types are allowed.
==== Allowed data types ====
Since it has to be compatible with MySQL, PostgreSQL and SQLite, UDBS only works with the following data types:
| **smallint** | 2 bytes signed integer |
| **integer** | 4 bytes signed integer |
| **bigint** | 8 bytes signed integer |
| **real** | 4 bytes float |
| **float** | 8 bytes float |
| **numeric** | Exact numerical value |
| **date** | Calendar date (day, month, year) |
| **time** | Hour of the day |
| **timestamp** | Date and hour |
| **char** | A fixed length string of n characters |
| **varchar** | A variable length string of n characters |
| **text** | A variable length text |
==== dbStruct object instance ====
By creating an instance of **dbStruct** you can define a schema (completely or partially).
$s = new dbStruct($core->con,$core->prefix);
The class takes a connection object and the prefixes we want to use. In the previous and following examples, we are using the objects that come with Dotclear.
==== Define a table ====
**dbStruct** and **dbStructTable** provide very useful features.
* Most of the methods return **$this** so they can be chained together.
* Any call to a non-existing property of **dbStruct** will have the same effect as creating a **dbStructTable** object if it does not exist and retrieve the instance.
* Any call to a non-existing method of **dbStructTable** will have the same effect as calling the **field** method which adds a field in the table.
Here is a classic example that does not use the advanced properties of **dbStruct**:
$s = new dbStruct($core->con,$core->prefix);
$t = $s->table('mytable');
$t->field('field1','varchar',255,false,"'-'");
$t->field('field2','smallint',0,true);
In this example, we define the **mytable** table in which we add two fields:
* **field1**, a 255 characters long, not null varchar with default value '-'
* **field2**, a smallint that can be null and with no default value.
This example works perfectly well, but here is another way of how to achieve exactly the same result:
$s = new dbStruct($core->con,$core->prefix);
$s->mytable
->field1('varchar',255,false,"'-'")
->field2('smallint',0,true)
;
Much better, no?
==== Add an index ====
To add an index to your schema extension:
$s->mytable->index('idx_mytable_field1','btree','field2');
The **index** method takes the following parameters: The index name, the type ("btree" only) and at least one field name. You can add more fields as additional parameters of the method.
==== Add a primary key to a table ====
$s->mytable->primary('pk_mytable','field1');
Just like **index** method, this method can take more than two parameters if the key is made of several table fields.
==== Add a unique key ====
$s->mytable->unique('uk_mytable','field2');
Just like **index** method, this method can take more than two parameters if the key is made of several table fields.
==== Add a reference to another table ====
The references indicante if the field of a table is linked to the field of another one. They ensure data integrity and automate some processes such as deleting or updating. They are also called "foreign keys".
$s->category->reference('fk_category_blog','blog_id','blog','blog_id','cascade','cascade');
Cet exemple crée la référence **fk_category_blog** sur le champ **blog_id** de la table **category** référençant le champ **blog_id** de la table **blog**. Les deux derniers paramètres sont les actions possibles dans les cas respectifs de mise à jour et de suppression d'une valeur référencée.
This example creates the **fk_category_blog** reference on the **blog_id** field from the **category** table, referencing the **blog_id** field from the **blog** table. The last two parameters are the possible actions, respectively in the case of an update and a deletion of a referenced value.
==== Schema synchronization ====
Once a schema has been written, it must be synchronized. Here is how to do it with the previous code:
$s = new dbStruct($core->con,$core->prefix);
$s->mytable
->field1('varchar',255,false,"'-'")
->field2('smallint',0,true)
;
$si = new dbStruct($core->con,$core->prefix);
$changes = $si->synchronize($s);
As you can see, we create a new instance of **dbStruct**, then we call the **synchronize** method passing it the instance of the previous **dbStruct**. This method will return the number of changes made.
==== Interacting with the Import/Export plugin ====
* [[http://tips.dotaddict.org/fiche/Sauvez-sauvez-il-en-restera-toujours-quelque-chose|Sauvegarder la table lors de l'export d'un blog]] (in French)