Interfaces extras !

, par Matthieu Marcillaud

Après les petites péripéties de tout à l’heure (Outils de debug), nous pouvons poursuivre la modification du plugin champs extras. Nous souhaitons 2 choses : pouvoir ordonner les champs extras, et pouvoir prendre en compte les champs déjà présents dans la base de données !

Ce qui parait évident au premier abord ne l’est pas forcément dans la réalité. On va être méthodique et commencer par corriger les principaux écueils actuels du plugin :

  • ne pas déclarer les autorisations dans le fichier d’option mais bien en utilisant un fichier spécifique appelé par le pipeline autoriser,
  • ne pas jouer au fou avec des id_extra basé sur les clés de tableau qui pourraient être problématiques si deux administrateurs modifient un même extra en même temps (bon, j’admets c’est peu probable),
  • utiliser la classe ChampExtra aussi dans l’interface plutôt que d’utiliser un autre tableau, ce qui sera plus pérenne,
  • rationaliser les noms des fonctions entre les deux plugins,
  • ajouter des points de log.

Rationaliser les nommages

Afin d’éviter de trop se disperser dans les noms des fonctions entre le plugin ’core’ et le plugin ’interface’ pour les champs extras, nous allons les renommer, ainsi que leurs fonctions cextras et iextras. Et en plus, je l’ai déjà fait, ce qui donne : http://zone.spip.org/trac/spip-zone/changeset/25554 et le retardataire http://zone.spip.org/trac/spip-zone/changeset/25555 !

Autorisations au bon endroit !

Je l’avais oublié un peu trop vite, mais il y a un pipeline pour les autorisations, qui permet de charger un fichier contenant de nouvelles autorisations.

Nous allons donc le déclarer dans l’interface à la place du fichier d’options.

Le fichier d’options est déplacé, renommé dans inc/iextras_autoriser.php et modifié comme suit :

La fonction iextras_autoriser doit être présente, mais elle ne sert à rien. Elle est juste prétexte à la lecture du fichier d’autorisation au moment de l’appel à la librairie autoriser de SPIP.

Ajouter des points de logs

Certaines actions effectuées méritent d’être logguées, comme l’ajout et la suppression de champ extra.

Créons une fonction pour cela dans le core du plugin :

On ajoutera au fur et à mesure des appels aux points essentiels du plugin.

Utiliser la classe ChampExtra dans l’interface graphique

Les objets PHP peuvent se linéariser et se dé-linéariser de la même manière que les tableaux PHP. La condition est que la classe soit définie au moment de la dé-linéarisation. Ce qu’on appelle linéarisation, ou sérialisation, c’est l’action de transformer une variable PHP en une chaine de caractère particulière pouvant alors être stockée, par exemple dans un fichier. Ces chaines peuvent être ensuite dé-sérialisées pour obtenir de nouveau la variable d’origine.

Donc, à la place d’un tableau PHP, nous allons stocker une classe ChampExtra.

Rien d’extraordinaire à montrer ici : http://zone.spip.org/trac/spip-zone/changeset/25559

Utiliser un identifiant qui identifie réellement !

L’identifiant que nous avons attribué aux champs extras correspond en ce moment à la clé du tableau PHP contenant la liste des champs extras. Cette clé, générée automatiquement n’identifie pas les contenus, mais juste une position dans un tableau. Si par mégarde la position change entre le moment où l’on affiche la liste des extras et le moment où l’on appuie sur le bouton supprimer (parce que quelqu’un a déplacé l’extra en question presque au même moment), alors ce sera un mauvais champ qui sera supprimé ! Pas good !

Nous allons donc créer un identifiant qui représente réellement le contenu du champ extra, de sorte que si le champ est déplacé dans le tableau, ce soit bien lui néanmoins qui soit supprimé et non son voisin.

On ajoute donc des petites fonctions à la classe ChampExtra pour gérer cet identifiant :

La première fonction make_id() crée un hash (une chaine unique) en utilisant les variables de la classe ChampExtra qui ne commencent pas par un souligné.

La seconde get_id() renvoie l’identifiant (ou le crée puis le renvoie), enfin, la dernière déjà présente mais modifiée retourne un tableau PHP avec le contenu de la classe ChampExtra et en profite pour ajouter dedans une clé ’id_extra’ avec l’identifiant en question.

De la sorte, le formulaire peut maintenant récupérer des données en fonction d’un identifiant fiable. Voyons par exemple comment devient la fonction charger du formulaire :

Lorsque nous sommes face à un champ en modification (pas nouveau), on parcoure la liste des champs extras tant qu’on ne trouve pas celui ayant le bon identifiant. Lorsque c’est le bon, on ajoute ses valeurs dans le chargement. C’est un peu plus long en traitement, mais ce n’est pas un lieu d’un site fréquenté (ça ne sert qu’à la création du site généralement). Les changements complets sont là : http://zone.spip.org/trac/spip-zone/changeset/25560

Nous avons maintenant corrigé les principaux écueils et pouvons attaquer la prise en compte par le plugin des champs déjà ajoutés dans la base de donnée. Ca ne va pas être si simple que ça !

Bien poser la problématique...

Quand on ne sait pas trop comment commencer, il y a plusieurs possibilités :

  • dormir (le plus efficace certainement),
  • faire des schémas et des plans sur papier qui permettent d’avoir une vue d’ensemble meilleure ou encore écrire en français la problématique,
  • commencer par ce dont on est certain ; le reste viendra en codant.

Cernons la problématique : certains webmestres ont déjà ajouté dans des tables des champs via phpMyAdmin ou en écrivant dans un squelette SPIP :

Ces champs déjà présents ne sont pour le moment pas pris en compte par le plugin. La question, c’est comment les prendre en compte, et que prendre en compte aussi. Car il peut y avoir une lecture à plusieurs niveaux : le champ peut exister et être déclaré, mais sans être accessible aux rédacteurs d’articles, c’est à dire ne s’affichant pas dans les formulaires. Le champ peut aussi être déclaré et devoir s’afficher.

Le plus simple, il me semble, c’est de pouvoir dire qu’un champ peut non seulement être supprimé, mais peut aussi être lié et délié au plugin champs extras. Ainsi, on pourrait lier un champ au plugin, il s’affiche alors dans le formulaire, puis le délier (il ne s’y affiche plus, et n’est plus géré par le plugin d’interface) mais est toujours présent dans la table. Ceci résoudrait l’épineux problème de la suppression car sinon, on ne pourrait retirer un champ extra ajouté dans le plugin qu’en le supprimant... Ce qui n’est pas forcément idéal.

On a donc un premier aperçu de ce qu’il faut réaliser (ajouter un champ existant / délier un champ extra du plugin).

Commençons par pouvoir ajouter les champs existants. Il faut déjà pouvoir les lister. Enfin, lister tous les champs de la base de donnée qui ne sont pas déclarés à SPIP, c’est bien de ceux là qu’il s’agit, car ceux déjà déclarés ont toutes les chances d’être déjà gérés par d’autres plugins. Ca tombe assez bien car Fil a déjà réalisé cette partie dans le futur défunt plugin « extras2 » que ce plugin est en train de manger !

On va donc intégrer tout ou partie de son code. (¡ Que viva GPL !)

Récupérer les descriptions des tables SQL

On va donc comparer deux descriptions : celle des tables réelles et celles des déclarations faites à SPIP. La différence des deux donnera les champs possiblement utilisables par le plugin. Ajoutons ces fonctions au core, adaptées de Fil :

Commençons par observer la fonction extra_tables(). Elle demande quelle sont les tables réellement présentes dans la base, gràce à la fonction sql sql_showbase(). Le paramètre $connect correspond au nom du fichier de connexion qu’utilise SPIP pour se connecter (dans le répertoire connect/). Lorsqu’il n’est pas renseigné, SPIP utilise sa connexion principale (la connexion ayant installée le SPIP).

La fonction extra_champs() prend un nom de table en entrée et récupère la liste des champs réels et leurs descriptions SQL, ceci gràce à la fonction sql_showtable().

La fonction extra_base() crée un tableau de toutes les descriptions des champs pour chaque table rencontrée.

Reste maintenant la fonction extras_champs_anormaux(). Elle récupère tous les champs réels en appelant extra_base(), tous les champs SPIP déclarés en concaténant les tableaux tables_principales et tables_auxiliaires, et retourne la liste des champs présents en base, mais non déclarés à SPIP.

Afficher les champs utilisables dans l’interface

Nous allons maintenant afficher ces champs dans l’interface graphique du plugin, avec des actions pour les associer ou les supprimer définitivement.

Ajoutons déjà l’appel à un squelette les affichant dans exec/iextras.php :

Puis créons le squelette champs_extras_possibles.html, sur le même principe que son collègue prive/contenu/champs_extra.html :

Nous bouclons sur les différentes tables, puis sur les champs et nous affichons un lien pour associer et un lien pour supprimer le champ.

Nous en profitons pour ajouter en même temps, sur l’autre squelette prive/contenu/champs_extras.html un lien pour désassocier un champ extra déclaré :

Il faut maintenant s’occuper de traiter les différentes actions.

Créer les nouvelles actions

Modifions le fichier actions/iextras.php pour lui ajouter ces traitements. Cela peut donner le résultat ci-dessous. Chaque action appelle une fonction dédiée. Notons juste le cas de l’association d’un champ SQL déjà présent : après l’appel de la fonction d’association, on redirige la page vers le formulaire de modification. C’est un peu déroutant, mais lorsqu’on ajoute un tel champ, une des premières choses faite sera de renseigner correctement le label, donc envoyer sur le formulaire parait assez cohérent. (NdA : finalement j’ai réellement trouvé ça trop déroutant en pratique et j’ai mis en commentaire ce code)

Pour cela, on appelle la fonction redirige_par_entete() présent dans la librairie inc/header. Elle prend comme paramètre l’URL de redirection et doit être appelée avant tout affichage sur la page.

Ordonner les champs extras

Lorsqu’il y a au moins deux champs extras déclarés sur une table, on peut avoir envie de les afficher dans un certain ordre. Nous allons donc ajouter deux actions : monter et descendre. Par ailleurs, on ne peut pas monter le premier élément ni descendre le dernier !

En ajoutant ces deux nouvelles actions, on remarque qu’il commence à y en avoir beaucoup (d’actions) et que leur affichage est un peu le fouillis. Avant de traiter les actions, on va effectuer un peu de présentation CSS.

D’une part, nous allons mettre les actions dans une liste ul/li :

Ajouter du CSS dans l’interface privé

Ensuite, nous allons ajouter du CSS pour présenter cette liste. Comment ? Très simple, chaque plugin peut déclarer un fichier prive/style_prive_plugin_prefix.html qui sera interprété comme un fichier css. Créons le fichier prive/style_prive_plugin_iextras.html et ajoutons dedans :

On remarquera que ce squelette reçoit quelques paramètres (lang, couleur_foncee, couleur_claire et ltr (direction de la langue)). Nous utilisons ici la couleur claire pour mettre une petite bordure.

Par contre, voir les modifications CSS dans le privé n’est pas simple du tout car d’une part les CSS sont compactées automatiquement dans l’espace privé, mais on peut désactiver cela en ajoutant dans son fichier d’option :

Et d’autre part, ce sont des CSS calculées à partir de squelettes SPIP, et les faire recalculer n’est pas simple. Le plus rapide étant de vider à la fois le cache de SPIP et celui du navigateur.

Traiter les actions monter et descendre

Nous allons utiliser une fonction assez géniale de PHP pour cela : array_splice(). Cette fonction permet d’insérer ou de remplacer des éléments dans un tableau. Nous allons l’utiliser pour insérer notre champ déplacé au bon endroit.

Pour cela, on ordonne notre tableau pour avoir tous les champs d’une même table à la suite, puis il suffit de remonter ou descendre un élément pour modifier l’ordre.

Commençons par trier les champs par table :

Ensuite, nous pouvons ajouter les actions monter et descendre :

Résultat des courses : http://zone.spip.org/trac/spip-zone/changeset/25572 (et petit « oups »).

Afficher une boite d’information

Pour terminer ce plugin, nous allons ajouter des descriptions sur les pages de l’interface. Rien de transcendant, mais il existe des fonctions et pipelines déjà prévus, alors utilisons les !

Commençons par créer les chaines de langues :

Puis créons une nouvelle fonction cadre_champs_extras_infos() dans le fichier exec/iextras.php. Elle contient simplement l’appel d’un pipeline boite_infos avec un paramètre type indiquant quelle information afficher :

Nous appelons la fonction dans la partie gauche de la page comme ceci :

Le pipeline « boite_infos » appelle automatiquement un squelette prive/infos/$type avec les autres paramètres qui lui sont transmis (ici il n’y a pas d’autre chose que « type »), mais pour les infos de la page auteur sont transmis l’id_auteur ainsi que tout le contenu de l’entrée SQL de l’auteur en question (row) :

Bref, il nous suffit donc, pour avoir quelque chose de fonctionnel, de créer le squelette prive/infos/champs_extras.html avec :

Et c’est tout ! Résultat : http://zone.spip.org/trac/spip-zone/changeset/25575 .

Conclusions

Promis, j’arrête de parler de ce plugin « champs extras », de toute façon il n’y a plus grand chose à dire, l’essentiel est maintenant codé. Il restera à prendre en compte des champs extras autre que le type text ou textarea, comme des sélections, des liste de choix, etc...

En tout cas, cet exemple de plugin vous aura fait découvrir l’essentiel des pipelines de SPIP pour ajouter des éléments dans des formulaires, pour afficher des pages dans le privé. J’espère que cela vous aura été profitable et que ça vous donnera des idées pour vos réalisations.

Plus vous utiliserez les outils prévus par SPIP, meilleure sera sa portabilité au fil des évolutions. Sur ce, bons champs extras !

Vue du plugin Champs Extras
Vue au 28/12/2008
Modification des champs extras
Page d’édition au 28/12/2008