Développer un plugin

Cette documentation est valable pour Paheko version 1.3.0 ou supérieure. Merci de voir ici pour la version précédente de cette documentation.

Détails techniques

Vie des plugins du point de vue utilisateur

Depuis la version 1.3.0, il n'y a plus de notion d'installation ou désinstallation d'un plugin dans l'interface, pour simplifier et clarifier les choses pour les utilisateurs.

Les plugins sont gérés dans l'onglet Extensions du menu Configuration, où sont regroupés les modules et plugins.

Quand un plugin est activé pour la première fois, il est installé en appelant le fichier install.php.

Ensuite le plugin peut être activé ou désactivé, cela ne change rien aux données créées par le plugin (tables SQL, fichiers, signaux), simplement le plugin n'est plus disponible (les signaux ne sont plus appelés, il n'apparaît plus dans le menu, etc.).

Une fois désactivé, un plugin peut être désinstallé avec le bouton Supprimer les données dans la fiche de l'extension (cliquer sur le bouton Détails sur la ligne de l'extension). Dans ce cas le fichier uninstall.php est appelé pour supprimer toutes les données et signaux du plugin.

Le plugin reste disponible pour être à nouveau activé (installé) par l'utilisateur, à aucun moment Paheko ne supprimer le code du plugin, c'est à l'administrateur de le faire manuellement.

Format des plugins

Les plugins sont des archives .tar.gz : tous les fichiers du plugin (code PHP, CSS, templates, images, etc.) sont stockés dans l'archive et y restent (l'archive n'est jamais décompressée).

Il est aussi possible de simplement avoir le plugin dans un sous-répertoire du répertoire des plugins. Ceci permet de faciliter le développement ou la maintenance du plugin. Pour la distribution d'un plugin, le format .tar.gz est toujours préféré.

Il est possible de créer soi-même l'archive .tar.gz de cette manière, depuis le répertoire racine du plugin :

$ tar czvf src/plugins/test.tar.gz ./

Informations sur le plugin (plugin.ini)

Chaque plugin doit au moins fournir à la racine de son archive un fichier nommé plugin.ini. Ce fichier fournit le nom, la description et quelques détails sur le plugin :

name="Ma première extension Paheko"
description="Affiche un message trop cool"
author="Anne Onyme"
author_url="http://paheko.cloud/"
version="1.0"
min_version="1.3.0"
menu=true
home_button=true
restrict_section="users"
restrict_level="read"

Explication des directives :

  • name indique le nom du plugin, qui sera utilisé dans les listes et menus.
  • description fournit une description plus longue, peut faire plusieurs lignes.
  • author donne le nom de l'auteur du plugin
  • author_url indique l'adresse du site web de l'auteur.
  • version est utilisée pour savoir quelle est la version du plugin fournie dans l'archive. Voir plus loin : Mise à jour.
  • min_version est facultatif et peut comporter le numéro de version de Paheko minimal nécessaire à l'installation du plugin. Par exemple si on renseigne "0.8.0" et que la version installé de Paheko est la 0.7.1, le plugin refusera de s'installer.
  • menu indique (true ou false) à Paheko s'il doit afficher une entrée dans le menu des extensions de la partie privée. L'entrée du menu appellera le fichier admin/index.php qui devra donc exister, à défaut l'installation de l'extension échouera.
  • home_button indique (true ou false) à Paheko s'il doit afficher une icône sur la page d'accueil de la partie privée. L'entrée appellera le fichier admin/index.php qui devra donc exister, à défaut l'installation de l'extension échouera.
  • restrict_section indique la section auquel l'utilisateur doit avoir accès pour voir l'entrée de menu ou le bouton de la page d'accueil (users, web, accounting, config, documents)
  • restrict_level indique le niveau d'accès de l'utilisateur pour voir l'entrée de menu ou le bouton de la page d'accueil (read, write, admin)

Attention, si le fichier plugin.ini n'existe pas dans le plugin il ne pourra pas être installée, n'étant pas considérée comme un plugin de Paheko.

Icône

L'icône doit obligatoirement être au format SVG, et être référencée par l'id img. Il est également préférable qu'elle ne soit qu'en noir sur fond transparent, pour que ses couleurs puissent être modifiées selon le thème de l'interface.

Pour cela il convient de placer ceci dans la balise <svg...> de l'icône :

<svg width="100%" height="100%" id="img" stroke="none" fill="currentColor"

Scripts magiques

Chaque archive peut comporter certains scripts magiques qui seront appelés automatiquement par Paheko lors de certains événements.

  • install.php est appelé quand le plugin a été téléchargé et qu'il est déjà noté comme installé (post-installation), utile notamment pour créer une table dans la base de données
  • upgrade.php : quand la version de l'archive (notée dans plugin.ini) ne correspond pas à la version enregistrée en base de donnée
  • uninstall.php : juste avant que le plugin ne soit supprimé, utile par exemple pour supprimer les tables de la base de données.

Objet GarradinEntitiesPlugin

  • setConfig(string $key, string $value): mixed : enregistre la configuration du plugin, si $value est null alors toute clé est effacée de la configuration
  • getConfig(string $key): mixed : récupère la valeur de la clé $key pour la configuration du plugin
  • upgrade(): void : mise à jour du plugin
  • needUpgrade(): bool : le plugin doit-il être mis à jour ?
  • uninstall(): void : désinstaller le plugin
  • path(): string : renvoie le chemin vers l'archive du plugin
  • registerSignal(string $signal, callable $callback): void : enregistre un callback associé à un signal
  • unregisterSignal(string $signal): void : supprime un callback associé à un signal

Base de données

Tous les plugins ont un accès illimité à la base de données principale de Paheko. Cependant il est interdit d'ajouter, modifier ou supprimer des données directement dans les tables de cette BDD afin de ne pas compromettre l'intégrité des données. Pour modifier ces données il faut utiliser les méthodes de Paheko.

Chaque plugin peut créer une ou plusieurs tables dans cette BDD, elles devront par contre être supprimées à la désinstallation. Dans ce cas un plugin peut modifier directement ses tables.

Fichiers

Les plugins ne devraient pas créer, modifier ou supprimer de fichiers dans l'arborescence de Paheko.

Les seuls fichiers qu'un plugin devrait modifier sont dans le cache : utiliser de préférence l'objet Static_Cache de Paheko, ou faire attention aux collisions de noms ;

Pour enregistrer et récupérer des documents il faut utiliser les méthodes de stockage de fichiers fournies par Paheko.

Chaque plugin dispose d'un répertoire de stockage dédié (supprimé à la désinstallation), dans ext/p/nom_plugin. Dans ce répertoire tous les fichiers sont modifiables et lisibles par les membres connectés ayant accès au plugin (voir restrict_section et restrict_level dans le fichier INI du plugin). Pour créer des fichiers accessibles publiquement, placez-les dans le sous-répertoire public du plugin : ext/p/nom_plugin/public.

Les plugins qui n'ont pas de restrict_section renseignée ne peuvent pas stocker de fichiers.

Signaux

Les plugins peuvent se « brancher » sur des signaux émis par Paheko lors de certaines actions.

Voir wiki:Dev/Signaux pour les détails.

Contrôleurs et ressources privées

Les contrôleurs et autres fichiers qui ne doivent être accessibles que depuis l'administration de l'association doivent être placés dans le sous-répertoire admin du plugin. Ceux-si seront accessible via l'URL /admin/p/nom_du_plugin/.

Constantes définies pour le code PHP

Pour les fichiers PHP appelés, les constantes suivantes seront définies :

  • PLUGIN_ROOT : le chemin vers la racine du code du plugin
  • PLUGIN_URL : l'URL publique du plugin (/p/nom_du_plugin/)
  • PLUGIN_ADMIN_URL : l'URL privée du plugin (/admin/p/nom_du_plugin/)

Pages et ressources publiques

Un plugin peut mettre à disposition des ressources publiques (accessibles sans connexion) en les plaçant dans le sous-répertoire public du plugin. Ce contenu sera accessible via l'URI /p/nom_du_plugin/.

Ainsi un fichier public/image.png du plugin test sera accessible via l'URL https://site-association.tld/p/test/image.png. Le fichier index.php sera interprété comme l'index d'un répertoire, comme dans n'importe quel site web :

public/index.php sera appelé pour servir l'URL https://site-association.tld/p/test/.

Le plugin reservations utilise ce système.

Templates Smartyer

Paheko fournit la lib Smartyer pour les pages privées (répertoire /admin/), où elle est déjà chargée par défaut. C'est une version allégée du moteur de template Smarty 2. Voir la documentation de Smartyer

Afficher un template contenu dans le plugin :

$tpl = \Garradin\Template::getInstance();
$tpl->display(PLUGIN_ROOT . '/templates/index.tpl');

Inclure un template de Paheko depuis un template :

{include file="admin/_head.tpl"}

Inclure un template du plugin depuis un autre template du plugin :

{include file="%s/templates/_nav.tpl"|args:$plugin_root}

Faire un lien vers une autre page du plugin :

<a href="{plugin_url file="liste.php"}">Liste des trucs</a>

Inclure une feuille de style CSS supplémentaire sur les pages du plugin (chemin relatif à la racine du plugin) :

$tpl->assign('plugin_css', [ 'styles/bleu.css' ]);

User Templates

Le site public de l'association n'utilise pas Smartyer mais des squelettes, qui utilisent le langage Brindille.

Ces squelettes sont basés sur les User Templates, qui peuvent servir pour faire des modèles de documents internes, en plus des squelettes du site web.

  • Le langage de base est Brindille
  • Paheko étend ce langage avec les User Templates (qui peuvent être utilisés comme modèle de document, modèle d'email, etc.) (classe UserTemplate)
  • Les UserTemplates sont étendus à leur tour pour faire les Squelettes (classe Skeleton)

Il est possible d'étendre les UserTemplates avec de nouvelles fonctions, sections (boucles), ou modifieurs, simplement en les enregistrant à l'objet UserTemplate lors de son initialisation, avec le signal usertemplate.init.

Un exemple de plugin qui rajoute une section appelée velos aux templates, à l'installation enregistre le signal :

$plugin->registerSignal('usertemplate.init', 'Garradin\Plugin\Stock_Velos\Velos::register');

Et dans le fichier lib/Velos.php du plugin on ajoute cette méthode :

    static public function register(Signal $signal)
    {
        $usertemplate = $signal->getIn('template');
        $usertemplate->registerSection('velos', [self::class, 'section']);
    }

Et le code de la section elle-même, qui doit obligatoirement renvoyer un générateur (yield) :

    static public function section(array $params)
    {
        if (isset($params['count'])) {
            $sql = 'SELECT COUNT(*) AS count FROM plugin_stock_velos WHERE prix > 0 AND date_sortie IS NULL;';
        }
        else {
            $sql = 'SELECT prix, modele, roues, type, genre, etiquette FROM plugin_stock_velos
                WHERE date_sortie IS NULL AND prix > 0 ORDER BY date_entree ASC;';
        }

        $db = DB::getInstance();
        foreach ($db->iterate($sql) as $row) {
            yield (array) $row;
        }
    }