-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve plugins documentation; closes #3
- Loading branch information
Showing
8 changed files
with
500 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
Database | ||
-------- | ||
|
||
.. warning:: | ||
|
||
A plugin should **never** change core's database! It just add its own tables to manage its own data. | ||
|
||
Of course, plugins relies on :doc:`GLPI database model <../devapi/dbmodel>` and must therefore respect :ref:`database naming conventions <dbnaming_conventions>`. | ||
|
||
Creating, updating or removing tables is done by the plugin, at installation, update or uninstallation; functions added in the ``hook.php`` file will be used for that; and you will rely on the `Migration class <https://forge.glpi-project.org/apidoc/class-Migration.html>`_ provided from GLPI core. Please refer to this documentation do know more about various `Migration` possibilities. | ||
|
||
Creating and updating tables | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Creating and updating tables must be done in the plugin installation process. You will add the required code to the ``plugin_{myplugin}_install``. As the same fucntion is used for both installation and update, you'll have to make tests to know what to do. | ||
|
||
For example, we will create a basic table to store some configuration for our plugin: | ||
|
||
.. code-block:: php | ||
<?php | ||
/** | ||
* Install hook | ||
* | ||
* @return boolean | ||
*/ | ||
function plugin_myexample_install() { | ||
global $DB; | ||
//instanciate migration with version | ||
$migration = new Migration(100); | ||
//Create table only if it does not exists yet! | ||
if (!TableExists('glpi_plugin_myexample_configs')) { | ||
//table creation query | ||
$query = "CREATE TABLE `glpi_plugin_myexample_config` ( | ||
`id` INT(11) NOT NULL autoincrement, | ||
`name` VARCHAR(255) NOT NULL, | ||
PRIMARY KEY (`id`) | ||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci"; | ||
$DB->queryOrDie($query, $DB->error()); | ||
} | ||
//execute the whole migration | ||
$migration->executeMigration(); | ||
return true; | ||
} | ||
The update part is quite the same. Considering our previous example, we missed to add a field in the configuration table to store the config value; and we should add an index on the ``name`` column. The code will become: | ||
|
||
.. code-block:: php | ||
<?php | ||
/** | ||
* Install hook | ||
* | ||
* @return boolean | ||
*/ | ||
function plugin_myexample_install() { | ||
global $DB; | ||
//instanciate migration with version | ||
$migration = new Migration(100); | ||
//Create table only if it does not exists yet! | ||
if (!TableExists('glpi_plugin_myexample_configs')) { | ||
//table creation query | ||
$query = "CREATE TABLE `glpi_plugin_myexample_configs` ( | ||
`id` INT(11) NOT NULL autoincrement, | ||
`name` VARCHAR(255) NOT NULL, | ||
PRIMARY KEY (`id`) | ||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci"; | ||
$DB->queryOrDie($query, $DB->error()); | ||
} | ||
if (TableExists('glpi_plugin_myexample_configs')) { | ||
//missed value for configuration | ||
$migration->addField( | ||
'glpi_plugin_myexample_configs', | ||
'value', | ||
'string' | ||
); | ||
$migration->addKey( | ||
'glpi_plugin_myexample_configs', | ||
'name' | ||
); | ||
} | ||
//execute the whole migration | ||
$migration->executeMigration(); | ||
return true; | ||
} | ||
Of course, we can also add or remove tables in our upgrade process, drop fields, keys, ... Well, do just what you need to do :-) | ||
|
||
Deleting tables | ||
^^^^^^^^^^^^^^^ | ||
|
||
You will have to drop all plugins tables when it will be uninstalled. Just put your code into the ``plugin_{myplugin]_uninstall`` function: | ||
|
||
.. code-block:: php | ||
<?php | ||
/** | ||
* Uninstall hook | ||
* | ||
* @return boolean | ||
*/ | ||
function plugin_myexample_uninstall() { | ||
$tables = [ | ||
'configs' | ||
]; | ||
foreach ($tables as $table) { | ||
$tablename = 'glpi_plugin_myexample_' . $table; | ||
//Create table only if it does not exists yet! | ||
if (TableExists($tablename)) { | ||
$DB->queryOrDie( | ||
"DROP TABLE `$tablename`", | ||
$DB->error() | ||
); | ||
} | ||
} | ||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
Adding and managing objects | ||
--------------------------- | ||
|
||
In most of the cases; your plugin will have to manage several objects | ||
|
||
Define an object | ||
++++++++++++++++ | ||
|
||
Objects definitions will be stored into the ``inc/`` directory of your plugin. File name will be the name of your class, lowercased; the class name will be the concatenation of your plugin name and your class name. | ||
|
||
For example, if you want to create the ``MyObject`` in ``MyExamplePlugin``; you will create the ``inc/myobject.class.php`` file; and the class name will be ``MyExamplePluginMyObject``. | ||
|
||
Your object will extends one of the :doc:`common core types <../devapi/mainobjects>` (``CommonDBTM`` in our example). | ||
|
||
Extra operations are aslo described in the :doc:`tips and tricks page <tips>`, you may want to take a look at it. | ||
|
||
Add a front for my object (CRUD) | ||
++++++++++++++++++++++++++++++++ | ||
|
||
The goal is to build CRUD (Create, Read, Update, Delete) and list views for your object. | ||
|
||
You will need: | ||
|
||
* a class for your object (``inc/myobject.class.php``), | ||
* a front file to handle display (``front/myobject.php``), | ||
* a front file to handle form display (``front/myobject.form.php``). | ||
|
||
First, create the ``inc/myobject.class.php`` file that looks like: | ||
|
||
.. code-block:: php | ||
<?php | ||
class PluginMyExampleMyObject extends CommonDBTM { | ||
public function showForm($ID, $options = []) { | ||
global $CFG_GLPI; | ||
$this->initForm($ID, $options); | ||
$this->showFormHeader($options); | ||
if (!isset($options['display'])) { | ||
//display per default | ||
$options['display'] = true; | ||
} | ||
$params = $options; | ||
//do not display called elements per default; they'll be displayed or returned here | ||
$params['display'] = false; | ||
$out = '<tr>'; | ||
$out .= '<th>' . __('My label', 'myexampleplugin') . '</th>' | ||
$objectName = autoName( | ||
$this->fields["name"], | ||
"name", | ||
(isset($options['withtemplate']) && $options['withtemplate']==2), | ||
$this->getType(), | ||
$this->fields["entities_id"] | ||
); | ||
$out .= '<td>'; | ||
$out .= Html::autocompletionTextField( | ||
$this, | ||
'name', | ||
[ | ||
'value' => $objectName, | ||
'display' => false | ||
] | ||
); | ||
$out .= '</td>'; | ||
$out .= $this->showFormButtons($params); | ||
if ($options['display'] == true) { | ||
echo $out; | ||
} else { | ||
return $out; | ||
} | ||
} | ||
} | ||
The ``inc/myobject.php`` file will be in charge to list objects. It should look like: | ||
|
||
.. code-block:: php | ||
<?php | ||
include ("../../../inc/includes.php"); | ||
// Check if plugin is activated... | ||
$plugin = new Plugin(); | ||
if (!$plugin->isInstalled('myexampleplugin') || !$plugin->isActivated('myexampleplugin')) { | ||
Html::displayNotFoundError(); | ||
} | ||
//check for ACLs | ||
if (PluginMyExampleMyObject::canView()) { | ||
//View is granted: display the list. | ||
//Add page header | ||
Html::header( | ||
__('My example plugin', 'myexampleplugin'), | ||
$_SERVER['PHP_SELF'],, | ||
'assets', | ||
'pluginmyexamplemyobject', | ||
'myobject' | ||
); | ||
Search::show('PluginMyExampleMyObject'); | ||
Html::footer(); | ||
} else { | ||
//View is not granted. | ||
Html::displayRightError(); | ||
} | ||
And finally, the ``front/myobject.form.php`` will be in charge of CRUD operations: | ||
|
||
.. code-block:: php | ||
<?php | ||
include ("../../../inc/includes.php"); | ||
// Check if plugin is activated... | ||
$plugin = new Plugin(); | ||
if (!$plugin->isInstalled('myexampleplugin') || !$plugin->isActivated('myexampleplugin')) { | ||
Html::displayNotFoundError(); | ||
} | ||
$object = new PluginMyExampleMyObject(); | ||
if (isset($_POST['add'])) { | ||
//Check CREATE ACL | ||
$object->check(-1, CREATE, $_POST); | ||
//Do object creation | ||
$newid = $object->add($_POST); | ||
//Redirect to newly created object form | ||
Html::redirect("{$CFG_GLPI['root_doc']}/plugins/front/myobject.form.php?id=$newid"); | ||
} else if (isset($_POST['update'])) { | ||
//Check UPDATE ACL | ||
$object->check($_POST['id'], UPDATE); | ||
//Do object update | ||
$object->update($_POST); | ||
//Redirect to object form | ||
Html::back(); | ||
} else if (isset($_POST['delete'])) { | ||
//Check DELETE ACL | ||
$object->check($_POST['id'], DELETE); | ||
//Put object in dustbin | ||
$object->delete($_POST); | ||
//Redirect to objects list | ||
$object->redirectToList(); | ||
} else if (isset($_POST['purge'])) { | ||
//Check PURGE ACL | ||
$object->check($_POST['id'], PURGE); | ||
//Do object purge | ||
$object->delete($_POST, 1); | ||
//Redirect to objects list | ||
Html::redirect("{$CFG_GLPI['root_doc']}/plugins/front/myobject.php"); | ||
} else { | ||
//per default, display object | ||
$withtemplate = (isset($_GET['withtemplate']) ? $_GET['withtemplate'] : 0; | ||
$object->display( | ||
[ | ||
'id' => $_GET['id'], | ||
'withtemplate' => $withtemplate | ||
] | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.