Ajouter un champ dans une table SPIP

, par Matthieu Marcillaud

Petit tutoriel pour ajouter un champ SQL dans une table SPIP existante. Nous découvrirons par cet exemple quelques points d’entrées forts utiles pour SPIP.

Ce soir, peu avant Noël, nous remarquons que nous avons un besoin urgent d’un champ ’PS’ sur une des rubriques de notre site. Eh oui ! Nous voulons dire : « PS : Cher Père Noël, n’oublie pas l’équipe SPIP ! »

Bien... Mais comme en plus, vous pensez à vos copains, vous dites : « si j’en fais un plugin, ça pourra servir à d’autres ! » Là, vous marquez un bon point. Encore faut-il y arriver. Commençons donc simplement.

Créer le plugin

Un plugin, c’est rien d’autre qu’un dossier (au sens dossier squelettes de SPIP) avec un fichier « plugin.xml » dedans. Jusque là, tout va bien. Créons ce dossier (plugins/post_scriptum/) avec ce premier fichier (plugin.xml) dedans contenant :

  1. <plugin>
  2. <nom>Post Scriptum sur les Rubriques</nom>
  3. <auteur>
  4. Vous, bien s&ucirc;r, en &eacute;chappant les accents !
  5. </auteur>
  6. <licence>GNU/GLP</licence>
  7. <version>0.1</version>
  8. <description>
  9. Ajoute un champ "ps" sur les rubriques de SPIP.
  10. </description>
  11. <etat>dev</etat>
  12. <prefix>postscriptum</prefix>
  13. <necessite id="SPIP" version="[2.0;]" />
  14. </plugin>

Télécharger

Ce fichier XML contient donc quelques informations sur votre plugin : son nom, son auteur, sa licence, son identifiant, sa stabilité (dev (développement), test (en test), stable), sa description et d’éventuelles dépendances : ici, nous affirmons que nous devons posséder SPIP 2.0.

Il nous faudra ajouter quelques informations dans ce fichier au fil de l’avancement, mais à ce stade, vous pouvez déjà voir la présence de ce plugin dans la page ecrire/?exec=admin_plugin.

Déclarer le champ SQL

Pour ajouter le champ SQL dans la table ’spip_rubriques’ il faut 2 choses : premièrement, déclarer son existence, et deuxièmement, expliquer à SPIP qu’il doit le créer à l’installation du plugin (et le supprimer à la désinstallation complète du plugin aussi !).

Prenons les éléments dans l’ordre et commençons par déclarer la présence du champ SQL. Pour cela, nous allons créer un répertoire dans notre plugin nommé base qui va contenir les informations relatives à la base de donnée.

Dedans, nous créons un premier fichier nommé postscriptum.php (on nommera de préférence les fichiers comme le préfixe du plugin) qui va contenir la définition du champ dans une fonction précise :

  1. <?php
  2. if (!defined("_ECRIRE_INC_VERSION")) return;
  3.  
  4. function postscriptum_declarer_tables_principales($tables_principales){
  5. // Extension de la table rubriques
  6. $tables_principales['spip_rubriques']['field']['ps'] = "text DEFAULT '' NOT NULL";
  7.  
  8. return $tables_principales;
  9. }
  10. ?>

Télécharger

La fonction postscriptum_declarer_tables_principales est une fonction crée pour un point d’entrée de SPIP, le pipeline « declarer_tables_principales » servant donc à déclarer, définir, les tables dites principales de SPIP.

D’autres tables dites « auxiliaires » peuvent aussi être déclarées via le pipeline « declarer_tables_auxiliaires » exactement de la même façon. Les tables auxiliaires sont souvent des tables dites « de liaison », c’est à dire servant à lier des informations de 2 tables principales (exemple : « spip_mots_articles » pour lier « spip_mots » et « spip_articles », ou « spip_documents_liens » pour lier « spip_documents » à « spip_xx »).

Pour revenir au code de la fonction, nous disons simplement qu’il existe un champs (tableau ’field’) nommé ’ps’ de type ’text’.

Pour certains champs ajoutés, ce n’est pas le cas ici, qui servent très souvent aux requêtes de sélections SQL (via des boucles SPIP par exemple), il peut être judicieux de poser un index sur le champ, permettant aux gestionnaires de base de donnée d’être plus rapide (mais la table prend alors plus de place). Voici un exemple extrait du plugin « openID » faisant cela :

  1. <?php
  2. if (!defined("_ECRIRE_INC_VERSION")) return;
  3.  
  4. function openid_declarer_tables_principales($tables_principales){
  5. // Extension de la table auteurs
  6. $tables_principales['spip_auteurs']['field']['openid'] = "text DEFAULT '' NOT NULL";
  7. $tables_principales['spip_auteurs']['key']['KEY openid'] = "openid";
  8.  
  9. return $tables_principales;
  10. }
  11. ?>

Télécharger

Pour terminer la prise en compte de ce champs par SPIP, il faut expliquer à SPIP que notre plugin utilise le pipeline « declarer_table_principales ». Pour cela, nous allons ajouter dans notre fichier « plugin.xml » les informations suivantes, avant </plugin> :

  1. <pipeline>
  2. <nom>declarer_tables_principales</nom>
  3. <inclure>base/postscriptum.php</inclure>
  4. </pipeline>

Télécharger

Installer le champ SQL

Nous allons maintenant définir une installation automatique de ce champs à l’installation du plugin. Pour cela, nous allons faire appel à un fichier base/postscriptum_install.php qu’il faudra créer.

Comme les pipelines, nous informons SPIP de la présence d’une méthode d’installation dans le fichier plugin.xml en ajoutant 2 champs : <install> et <version_base>, ce dernier définissant une version de la structure de la base de donnée du plugin. Cela sert à l’installation ou à la mise à jour du plugin (si la structure évolue un jour, par exemple pour renommer le champ ’ps’ en ’chapo’ ou je ne sais quoi).

  1. <version_base>0.1</version_base>
  2. <install>base/postscriptum_install.php</install>

Télécharger

Dans le fichier d’installation (postscriptum_install.php), nous allons maintenant déclarer 2 fonctions : une pour installer, une pour désinstaller.

  1. <?php
  2. if (!defined("_ECRIRE_INC_VERSION")) return;
  3.  
  4. function postscriptum_upgrade($nom_meta_base_version,$version_cible){
  5. $current_version = 0.0;
  6.  
  7. if ((!isset($GLOBALS['meta'][$nom_meta_base_version]))
  8. || (($current_version = $GLOBALS['meta'][$nom_meta_base_version])!=$version_cible)){
  9. include_spip('base/postscriptum');
  10. // cas d'une installation
  11. if ($current_version==0.0){
  12. include_spip('base/create');
  13. maj_tables('spip_rubriques');
  14. ecrire_meta($nom_meta_base_version, $current_version=$version_cible, 'non');
  15. }
  16. }
  17. }
  18.  
  19. function postscriptum_vider_tables($nom_meta_base_version) {
  20. sql_alter("TABLE spip_rubriques DROP ps");
  21. effacer_meta($nom_meta_base_version);
  22. }
  23. ?>

Télécharger

upgrade()

Détaillons un peu ce qu’elles font et comment. La première, xx_upgrade() prend 2 arguments qui sont automatiquement transmis par SPIP : le nom de la variable contenant (ou devant contenir) la valeur actuelle de la version de la base de donnée du plugin installée sur le SPIP en cours. Le second paramètre contient la version de la base de donnée fournie par l’entrée « version_base » du fichier plugin.xml.

Un premier test indique que si la version cible est différente de la version actuelle, alors on a des choses à faire. Un second test à l’intérieur, définit les différentes actions en fonction de la version actuelle de la base. Pour l’instant, notre base n’a jamais été installée, nous devons donc simplement créer les champs manquant.

Pour cela, nous utilisons une fonction prévue par SPIP, maj_tables(); qui met à jour toutes les tables ou seulement la table dont le nom est transmis : les champs manquants sont alors automatiquement créés. Pour notre cas, le champs ’ps’ va se créer.

Enfin, la fonction ecrire_meta() met à jour la valeur de la version de la base du plugin installé dans le SPIP.

vider_table()

La suppression se passe aussi en deux temps dans une fonction xx_vider_table() : on supprime les champs utilisés par le plugin, puis l’information de version de la base du plugin.

La fonction sql_alter("TABLE spip_rubriques DROP ps"); permet de supprimer le champ SQL ’ps’ de la table ’spip_rubriques’.

Permettre aux rédacteurs de modifier le nouveau champ

A ce stade là, le plugin ajoute et supprime le champs PS lors de l’installation ou de la suppression complète du plugin. Les boucles RUBRIQUES peuvent alors utiliser #PS.

Cependant, pour le moment, le nouveau champs ne s’affiche pas dans l’interface de rédaction. Nous allons résoudre ce petit problème en deux temps ! D’abord, nous ajoutons la possibilité de saisie dans le formulaire d’édition de rubrique, ensuite, nous prenons en compte la saisie du rédacteur dans l’enregistrement fait par SPIP.

Nous allons utiliser deux pipelines pour cela : « editer_contenu_objet » et « pre_edition ».

Ajouter le champ de saisie

Pour ajouter le champ de saisie, nous allons ajouter le résultat de la compilation d’un petit squelette à un endroit précis du formulaire de saisie prive/formulaires/editer_rubrique.html.

Prenons exemple sur le champ PS du formulaire d’édition d’article, et créons un dossier et un fichier formulaires/inc-rubriques-ps.html contenant :

  1. <li class="editer_ps[ (#ENV**{erreurs}|table_valeur{ps}|oui)erreur]">
  2. <label for="ps"><:info_post_scriptum:></label>[
  3. <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{ps})</span>
  4. ]<textarea name='ps' id='ps'[ lang='(#LANG)'] rows='5' cols='40'>[(#ENV**{ps})]</textarea>
  5. </li>

Télécharger

Cette structure HTML est une base standard de tous les formulaires d’édition SPIP actuels.

Nous allons maintenant indiquer à SPIP d’ajouter le résultat de la compilation de ce squelette dans le formulaire d’édition de rubrique. On déclare donc l’utilisation du pipeline editer_contenu_objet dans son fichier plugin.xml et on en profite pour ajouter le pipeline qui servira tout à l’heure : pre_edition.

  1. <pipeline>
  2. <nom>editer_contenu_objet</nom>
  3. <inclure>postscriptum_pipelines.php</inclure>
  4. </pipeline>
  5. <pipeline>
  6. <nom>pre_edition</nom>
  7. <inclure>postscriptum_pipelines.php</inclure>
  8. </pipeline>

Télécharger

Et oui ! Vous l’avez compris, il faut créer le fichier postscriptum_pipelines.php. Commençons par lui mettre ce contenu :

  1. <?php
  2. if (!defined("_ECRIRE_INC_VERSION")) return;
  3.  
  4. // ajouter un champ ps sur le formulaire CVT editer_rubrique
  5. function postscriptum_editer_contenu_objet($flux){
  6. if ($flux['args']['type']=='rubrique') {
  7. $flux['args']['contexte']['ps'] = sql_getfetsel('ps','spip_rubriques','id_rubrique='.sql_quote($flux['args']['contexte']['id_rubrique']));
  8. $ps = recuperer_fond('formulaires/inc-rubriques-ps', $flux['args']['contexte']);
  9. $flux['data'] = preg_replace('%(<!--extra-->)%is', $ps."\n".'$1', $flux['data']);
  10. }
  11. return $flux;
  12. }
  13. ?>

Télécharger

Ce pipeline est appelé pour tous les formulaires d’édition de SPIP. Ici, on regarde si le formulaire concerne les rubriques. Si c’est le cas, on récupère la valeur du champs ’ps’, en exécutant une requête SQL. Ce résultat est ajouté au contexte par la même occasion. On utilise ensuite la fonction magique recuperer_fond() pour obtenir le résultat de la compilation du squelette « inc-rubriques-ps » avec le contexte en cours. Ce résultat est stocké dans la variable $ps. Enfin, on place le contenu de $ps juste avant le texte "<!--extra-->" du formulaire d’édition en cours.

On aurait pu placer le ps en ciblant plus le lieu. Par exemple, le plugin « openID » place le champ openid dans un formulaire auteur juste après le champ email de la sorte :

  1. $openid = recuperer_fond('formulaires/inc-openid', $flux['args']['contexte']);
  2. $flux['data'] = preg_replace('%(<li class="editer_email(.*?)</li>)%is', '$1'."\n".$openid, $flux['data']);

Télécharger

Prendre en compte l’enregistrement

A ce moment là de l’histoire, le champ ps est bien présent dans la table et dans le formulaire... mais nous avons beau valider... Rien n’est sauvé. Là encore, il faut le dire à SPIP et utiliser le pipeline « pre_edition » que nous avons déjà déclaré.

Ajoutons simplement la fonction dans notre fichier « postscriptum_pipelines.php » de la sorte :

  1. // ajouter le ps soumis soumis lors de la soumission du formulaire CVT editer_rubrique
  2. function postscriptum_pre_edition($flux){
  3. if ($flux['args']['table']=='spip_rubriques') {
  4. if ($ps = _request('ps')) {
  5. $flux['data']['ps'] = corriger_caracteres($ps);
  6. }
  7. }
  8. return $flux;
  9. }

Télécharger

Et voir le résultat !!!!

C’est bien beau, le ps s’enregistre, il s’affiche bien dans le formulaire, mais on ne le voit pas sur la page ecrire/?exec=naviguer de la rubrique ? Bien oui !
C’est encore autre chose ! Il faut encore utiliser un pipeline nouveau : « afficher_contenu_objet ». Vous connaissez le principe maintenant. On ajoute donc dans plugin.xml :

  1. <pipeline>
  2. <nom>afficher_contenu_objet</nom>
  3. <inclure>postscriptum_pipelines.php</inclure>
  4. </pipeline>

Télécharger

On se crée un squelette avec ce que l’on souhaite voir s’afficher en plus, c’est à dire le PS de la rubrique, dans le fichier prive/contenu/inc-rubriques-ps.html :

  1. <BOUCLE_rub(RUBRIQUES){id_rubrique}{statut==.*}>
  2. <div class="#EDIT{ps} ps"><strong><:info_post_scriptum:></strong> #PS</div>
  3. </BOUCLE_rub>

Télécharger

Enfin, on ajoute le résultat du squelette grâce au pipeline sus-mentionné, en ajoutant la fonction qui va bien :

  1. // ajouter le champ ps sur la visualisation des rubriques
  2. function postscriptum_afficher_contenu_objet($flux){
  3. if ($flux['args']['type']=='rubrique') {
  4. $ps = recuperer_fond('prive/contenu/inc-rubriques-ps', $flux['args']['contexte']);
  5. $flux['data'] .= "\n".$ps;
  6. }
  7. return $flux;
  8. }

Télécharger

Pour tester, il faudra certainement recalculer votre page en cours (exemple : ecrire/?exec=naviguer&id_rubrique=26&var_mode=recalcul).

Et c’est tout !

Comment ça c’est long ? Mais non, je vous assure que non !
La preuve, le plugin zippé est joint à l’article, il n’a presque rien, et grâce à lui, vous saurez créer un plugin pour ajouter les champs qui vous sont nécessaires...

Coup de pouce

Pour me maintenir en éveil et en pleine forme physique et mentale, vous pouvez me faire le cadeau d'un jus de fruit pressé.

En plus de m'hydrater, de m'offrir une alimentation saine crudivore et frugivore, cela peut aussi me motiver à produire d'autres documentations ou peut-être à prendre des vacances ! :)

Vous pouvez également me « Flattrer » si vous utilisez le service en ligne très malin Flattr de microdonations qui permet d'allouer un budget mensuel à des créateurs de contenu. Votre budget est partagé chaque mois entre toutes les personnes que vous avez flattées ce mois là.