Développer un plugin GLPI v0.83.91 3

Nous voici dans un petit tutoriel sur la manière de réaliser un plugin pour GLPI v0.83.91.

Pour d’autres versions, se tutoriel pourra peut-être fonctionner mais je ne le garanti pas. Toutefois, il suffit des fois d’adapter ou d’aller voir dans les classes natives de GLPI, pour voir ce qui est attendu ( dans /glpi/inc). Ce sont souvent des noms de fonction, des placements de fonctions ou certains mécanismes qui changent, mais dans l’absolu la manière de faire reste équivalente. Attention donc : je ne suis pas parole d’évangile, il faudra donc des fois réadapter ce que j’affirme et ne pas suivre bêtement mes instructions (c’est jamais bon ;))

Bien, je vais commencer par expliquer les fondamentaux. Admettons que vous avez déjà analysé vos besoins et défini la structure de la ou des tables dans lesquelles vous allez stocker vos informations, vous possédez également vos fonctions .php de traitement de vos tables. Maintenant il faut réussir à créer le plugin en lui-même pour l’intégrer à GLPI, et intégrer vos fonctions.

I – Structure du dossier

Tout d’abord il faudra déposer dans /glpi/plugins le dossier racine de votre plugin, portant le nom de celui-ci. Ici notre plugin s’appellera « exemple« .

Voici la structure acceptée dans votre dossier racine glpi/plugins/exemple :

  • Un dossier « ajax » ou « scripts » contenant vos scripts
  • Un dossier « docs » qui contiendra tous les fichiers textes
  • Un dossier « front » qui contiendra toutes les pages « affichées » dans GLPI (affichage des formulaires et du texte), les vues en quelque sorte.
  • Un dossier « inc » qui contiendra les includes, les classes … vos fonctions
  • Un dossier « locales » contenant les fichiers de traductions, ces fichiers doivent êtres nommés de la façon qui suit : <code langue>_<code pays>.php (exemples : fr_FR.php, en_GB.php, en_US.php …). vous pouvez également utiliser gettext afin de traduire les messages de votre plugin.
  • Un dossier « pics » qui contiendra vos images

Bon, en gros sont obligatoires les dossiers inc et front.

Note : Dans le répertoire « inc« , vous allez pouvoir mettre vos classes PHP, par exemple « plugin_exemple.class.php« , qui contiendra toutes les méthodes de traitement de votre plugin (calcul, entrées en bases, affichages et sorties en bases …)

Ensuite, à la racine de votre plugin, doivent se trouver 2 fichiers vitaux :

  • setup.php
  • hook.php

On verra plus loin qu’elle sont leur utilité (bien que j’imagine que vous devez en avoir une idée).

II- Setup.php, l’installation de votre plugin

Dans ce fichier vont se trouver plusieurs fonctions :

Note : Chacun des noms de fonctions comportent le nom de votre plugin, soyez vigilants à ce que tout corresponde au nom de votre plugin.

Note : Les fonctions d’installation/désinstallation du plugin peuvent se situer dans hook.php ou setup.php. Personnellement, je préfère les placer dans setup.php, qui porte le nom adéquat et est plus petit que hook.php, donc cela équilibre le nombre de lignes des fichiers.

function plugin_exemple_install() :

C’est dans cette fonction que l’on :

  • Créée ses tables
  • Fait éventuellement des INSERT afin de paramétrer des valeurs par défaut
  • Inscrit une tâche Cron automatisée associée au plugin

On oublie pas au tout début de déclarer le handle de la base de données de GLPI comme ceci :

 global $DB;

Puis on peut par exemple créer des tables :

if (!TableExists("glpi_plugin_exemple_stock")) {
	$query = "CREATE TABLE `glpi_plugin_exemple_stock` (
          `id` int(11) NOT NULL auto_increment,
          `stock_id` int(11) NOT NULL,
          `computer_name` varchar(255) NOT NULL default 'Inconnu',
          `product` varchar(255),
          `version` int(11) NOT NULL default '0',
	  `counter` mediumint(5) default '0',
          `is_deleted` tinyint(1) NOT NULL default '0',
            PRIMARY KEY (`id`)
        ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci";

        $DB->query($query) or die("Erreur creation table glpi_plugin_exemple_stock". $DB->error());
}

J’en arrive à un point IMPORTANT :

Toujours nommer ses tables avec le préfixe « glpi_plugin_ » puis le nom de votre plugin et votre nom de table. Comme ci-dessus par exemple « glpi_plugin_exemple_stock »

Maintenant, si vous voulez inscrire une tâche automatique lors de l’installation, voici un code type :

$cron = new CronTask;
// creation du cron - param = duree de conservation
if (!$cron->getFromDBbyName('PluginExempleSynchro','Synchronize'))
{
	CronTask::Register('PluginExempleSynchro', 'Synchronize', DAY_TIMESTAMP,array('param' => 24));
}

On vérifie en base que la tâche Synchronize n’existe pas pour le module PluginExempleSynchro, si c’est bon, on enregistre la tâche automatique.

On peut remplacer DAY_TIMESTAMP par l’unité de temps qui nous arrange, car ici cela veut dire que la tâche sera exécutée tous les jours sur une plage horaire de 0 à 24 heures. Si on met HOUR_TIMESTAMP, la tâche sera exécutée toutes les heures sur une plage de 24 heures (par défaut). Le param, est une valeur que vous voudriez passer en paramètre.

Dans la rubrique des points IMPORTANTS en voici un autre :

La fonction exécutée par l’action doit retourner true à la fin (return true; ) sinon, amarchepas :p

Pour que cela fonctionne, il faut avoir un fichier de classe dans le répertoire « inc » qui se nomme, selon l’exemple du dessus : synchro.class.php et qui contiendra la classe PluginExempleSynchro.

Cette classe comportera deux méthodes minimum, les méthodes statiques cronInfo($name) et cronSynchronize($task) :

<?php 
class PluginExempleSynchro {
	/* Information sur la tâche automatisée */
	static function cronInfo($name) {
	
		switch ($name) {
			case 'Synchronize' :
				return array('description' => __('Cette tâche va synchroniser les données', 'exemple'),
				'parameter'   => __('Test', 'exemple'));
		}
		return array();
	}
	
	/**
	 * Execute une tâche gerée par le plugin - fonction de process
	 *
	 * @param $task Object of CronTask class for log / stat
	 *
	 * @return integer
	 *    >0 : done
	 *    <0 : to be run again (not finished)
	 *     0 : nothing to do
	 	*/
	static function cronLmcProcess($task) {
              $task->addVolume(5);    // j'ai traité 5 éléments (c'est le nombre affiché dans la colonne nombre de chaque exécutions)
              $task->log("J'écris dans le journal de log de la tâche");
        }
?>

 

function plugin_init_exemple() :

Dans cette fonction, vont être définies tout un tas de variables.

C’est simple, à chaque chargement de GLPI, cette fonction est appelée. C’est donc ici que l’on fait des traitements spéciaux lorsque le plugin est activé.

On commence par déclarer les variables globales dont on a besoin :

global $PLUGIN_HOOKS, $CFG_GLPI;

Ensuite, on peut « enregistrer » les classes que l’on va utiliser, comme ci-dessous :

Plugin::registerClass('PluginExempleConfig'); // PluginExempleConfig est le nom de la class

A chaque classe, on peut associer un élément de type « form », qui sera la page, sur laquelle on pourra effectuer des modifications et visualiser le contenu désiré. Il est important de bien comprendre la structure à ce niveau c’est pourquoi je vais donner un petit exemple  :

Vous voulez une classe de configuration, afin de pouvoir paramétrer votre plugin :

  • Dans le répertoire « inc » vous allez ajouter un fichier « config.class.php » qui contiendra votre classe PluginExempleConfig (cette classe doit hériter de CommonDBTM pour pouvoir utiliser la base de données de GLPI)
  • Ensuite, vous allez créer un fichier « config.form.php » dans le répertoire « front« , (ce répertoire contient les pages « affichées » et « navigables » sur GLPI, par convention)
  • Il vous suffit d’ajouter le nom de la classe dans un Plugin::registerClass(PluginExempleConfig) dans le fichier setup.php, dans la fonction plugin_init_exemple()

Les noms des fichiers sont des conventions de nommage que je vous conseille de respecter, afin de vous y retrouver si vous devez jeter un coup d’oeil dans d’autres plugins. Ils sont souvent structurés ainsi. Il est obligatoire de nommer ses classes avec la première lettre majuscule. Dans mon exemple, PluginExempleconfig n’aurait pas fonctionné !

Bon, on  va maintenant apprendre comment définir tout un tas de choses :

– Vous voulez  définir la CSRF COMPLIANCE de votre plugin ?

Note : Un plugin CSRF_COMPLIANT est un plugin qui contient des formulaires fermés avec Html::closeForm() et qui ne passe aucune variable de type GET.

Pour cela, on ajoute dans la fonction :

$PLUGIN_HOOKS['csrf_compliant']['exemple'] = true;

Avec true ou false si on veut afficher « Oui » ou « Non » dans le menu du plugin. Toujours bien penser à remplacer « exemple » par le nom de votre plugin.

– On désire vérifier si l’utilisateur à les droits sur tel ou tel partie de GLPI ?

On peut tester ceci grâce à

if (Session::haveRight("ocsng", "w"))
{
     // traitement
}

Ici, si l’utilisateur à les droits en écriture sur OCSNG (le module de gestion d’OCS), alors on passe dans le traitement. Vous pouvez trouver tous les modules sur lesquels sont définis des droits dans la classe Session, (/glpi/inc/session.php)

– Vous voulez vérifier si votre plugin est activé ?

on va instancier la classe Plugin, cela nous servira à vérifier que notre plugin est activé :

$plugin = new Plugin();
if($plugin->isActivated("exemple"))
{
      // traitement
}

Toujours dans la même fonction, on peut ajouter une partie de traitement si le plugin est activé. Remplacer « exemple » par le nom de votre plugin.

–  Vous voulez définir des noms de fonctions qui vont être appelées dans différents cas ?

// Init session
$PLUGIN_HOOKS['init_session']['exemple'] = 'plugin_init_session_exemple';
// Si on change de profil
$PLUGIN_HOOKS['change_profile']['exemple'] = 'plugin_change_profile_exemple';
// Si on change d'entité
$PLUGIN_HOOKS['change_entity']['exemple'] = 'plugin_change_entity_exemple';
//headings
$PLUGIN_HOOKS['headings']['exemple']         = 'plugin_exemple_get_headings';
$PLUGIN_HOOKS['headings_action']['exemple']  = 'plugin_exemple_headings_actions';

Dans tous ces exemple, on défini le nom de la fonction à appeler dans tel ou tel cas. Les « headings » sont les en-têtes, et permettent de rajouter des noms de fonctions qui vont ajouter des onglets (headings) et des actions associées au clic de ces onglets (headings_action).

function plugin_version_exemple() :

Cette fonction permet de donner les infos à afficher lorsque qu’on est sur l’interface de gestion des plugins, elle se compose comme suit :

function plugin_version_getofficekeys() {

   return array('name'           => 'Mon Exemple',
                'version'        => '1.0',
                'author'         => '<a href="mailto:admin@fortisfio.com">Moi</a>',
                'license'        => 'GPLv2+',
                'homepage'       => 'https://forge.indepnet.net/projects/exemple',
                'minGlpiVersion' => '0.83'); // For compatibility / no install in version < 0.80
}

Les attributs sont les suivants :

  • name : Le nom complet de votre plugin
  • version : la version (merci Captain Obvious :p )
  • author : un lien vers votre mail, ou votre nom ou pseudo
  • licence : GPL, GNU, … ce que vous voulez
  • homepage : le lien de la page d’accueil de votre plugin (téléchargements, etc …)
  • minGlpiVersion : la version minimum compatible avec votre plugin

Et donnerait un résultat semblable dans la vue de vos plugins :

my_plugin

III – Hook.php

Le fichier hook.php  contient toutes nos options (comme une sorte de fichier rempli de constantes) qui sera utilisé pour lier GLPI avec notre plugin.

On peut y inclure notamment :

function plugin_change_profile_exemple()

Une fonction qui permet d’activer/désactiver l’onglet de configuration de votre plugin en fonction de son état (activé/désactivé) :

function plugin_change_profile_exemple() {
   $plugin = new Plugin();
   if ($plugin->isActivated("exemple")) {
      if (/*Session::haveRight("logs", "r") || Session::haveRight("ocsng", "w")*/true) {
         $PLUGIN_HOOKS['menu_entry']['exemple'] = true;   // on active l'onglet dans le menu
      } else {
         $PLUGIN_HOOKS['menu_entry']['exemple'] = false;   // on desactive l'onglet dans le menu
      }
   }
}

function plugin_exemple_get_headings()

Une fonction qui permet d’ajouter un onglet sur le corps d’une page déjà existante de GLPI, comme ci-dessous :

new_tab_plugin_glpi

// On ajoute un onglet "clé office" dans l'affichage d'un ordinateur (computer)
function plugin_exemple_get_headings($type, $withtemplate)
{
	switch(get_Class($type))
	{
		case 'Computer' : return array( 1 => "Cl&eacute;s office"); break;
	}
	return false;
}

function plugin_exemple_headings_actions()

Une fonction permettant de définir l’action qui sera exécutée au clic sur notre nouvel onglet :

// Définit le champs d'action de l'onglet des licences offices dans les ordinateurs
function plugin_exemple_headings_actions($type)
{
	switch(get_Class($type))
	{
		case 'Computer' : return array( 1 => "plugin_getofficekeys_display"); break;
	}
	return false;
}

function plugin_exemple_getDatabaseRelations()

Une fonction qui nous permet de définir les « dropdown relations » (les relations sous-jacentes à votre plugin) :

// Definir les "dropdown relations"
function plugin_exemple_getDatabaseRelations() {
   return array("glpi_plugin_exemple_dropdowns" => array("glpi_exemple_getofficekeys" => "plugin_exemple_dropdowns_id"));
}

function plugin_exemple_getDropdown()

Une fonction permettant de définir les tables sous-jacentes (dropdown tables), en gros ce sont les tables que vous allez exploiter avec votre plugin :

// Definit les tables sous-jacentes  :
function plugin_exemple_getDropdown() {
   // Table => Name
   return array('PluginExempleKeysDropdown' => "Exemple Dropdown",
		"glpi_plugin_exemple_officepack",
                "glpi_plugin_exemple_profiles",
		"glpi_plugin_exemple_configs");
}

function plugin_exemple_Status()

Une fonction qui permet de définir le statut de votre plugin :

// Vérifie le plugin afin d'ajouter à la page de statut
function plugin_exemple_Status($param) {
   // Do checks
   $ok = true;
   echo "exemple plugin: checking ...";
   if ($ok) {
      echo "_OK";
   } else {
      echo "_PROBLEM";
      // On affecte false à OK si il y a un problème (sur le statut global)
      $param['ok'] = false;
   }
   echo "\n";
   return $param;
}

Et après on peut définir pas mal d’autres fonctions, que je n’ai personnellement pas utilisées.

Note : Pour débugger certaines fonctions, on peut ajouter une méthode addMessageAfterRedirect, définie dans la classe Session. Elle va afficher un message après que vous ayez effectué une action, un traitement … :

Session::addMessageAfterRedirect(sprintf(__(OK? %1$s %2$d -> %3$d', 'exemple'),
      $parm['type'],
      $parm['id'], 
      $parm['newID']));

Dans le code ci-dessus, on va afficher « OK? » suivi des 3 paramètres passés (représentés dans l’ordre par %1, %2 et %3) et suffixés avec un « d » ou un « s » en fonction du type de l’argument (« s » pour String et « d » pour Decimal)

IV – Visualiser son plugin

Je pense avoir fait le tour, et normalement vous devriez déjà avoir un bon résultat et un plugin presque achevé ! Maintenant pour faire le tour et voir ce que sa donne, si toutefois vous avez fait un plugin ressemblant au mien, voici les quelques choses à vérifier (normalement vous devez déjà avoir vérifié ces fonctionnalités mais on ne sait jamais) :

Vous avez normalement la page de configuration accessible depuis le menu « Configuration > Plugins« , en cliquant sur le nom de votre plugin « Exemple ». (Le titre devient un lien cliquable lorsqu’il est activé normalement) :

config_pluginEt vous avez également votre page « dédiée » à votre plugin si j’ose dire. L’endroit ou vous pouvez lancer vos actions, traitements …. Accessible depuis le menu « Plugins > Exemple » :

actions_pluginsPour le coup j’ai pris mon vrai plugin, « Get Office Keys », mais vous verrez le nom de votre plugin. Les deux liens que j’ai intégré à ma page sont simplement des liens vers un petit fichier READ ME et mon article sur la liaison GLPI et OCS, disponible sur ce site :o)

J’espère avoir pu lancer l’esprit créatif et ingénieux qui est en vous, et avoir pu amorcer le développement de votre propre plugin. Le mien permet de récupérer les clés des produits Microsoft Office depuis OCS (Attention, il faut qu’OCS dispose déjà du module de récupération des clés), et d’afficher pour chaque poste, ses licences Offices et également si il y a conflit ou non (si l’option est activée dans les paramètres). A l’heure ou j’écris cet article, le plugin n’existe pas dans la liste exhaustive, je l’ai donc fait par besoin.

Si vous souhaitez consulter les subtilités pour la version 0.84.5 de GLPI, et également lire deux, trois astuces que j’ai apprises,  je vous invite à lire cet article : http://www.fortisfio.com/?p=819

3 thoughts on “Développer un plugin GLPI v0.83.91

  1. Pingback: GLPI v0.84.5 : changements dans le développement d’un plugin ← Fortis Fio

  2. Répondre rostand Août 2, 2016 9 h 34 min

    Bonjour j’utilise glpi version 0.90.4 et je suis débutant. j’aimerais pouvoir créer mon propre plugins mais à chaque fois, glpi ne voit pas les fontions …_install et …_uninstall que je crée. Que me suggérez vous?

    • Répondre Alexandre Août 2, 2016 12 h 21 min

      Bonjour,

      Quel est le nom de votre plugin et le nom de vos fonctions ? Pour que GLPI sache comment appeler ces fonctions il faut se conformer à la convention de nommage plugin__install (ou _uninstall) et il faut que tout soit placé sous le dossier « plugins/nomdeplugin » dans un fichier setup.php ou hook.php.

      Il est aussi possible que la manière de faire ai changé depuis. Je ne développe plus en PHP et encore moins sur GLPI depuis + de 2 ans, donc la version 0.90.4 modifie peut etre la manière d’intégrer un plugin.

      Je vous conseille d’aller faire un tour sur le forum officiel http://forum.glpi-project.org/ . Il y a sûrement des infos intéressantes à ce sujet.

Laisser un commentaire