Un crayon listant des liaisons Crayon de mots-clés sur un auteur

, par Matthieu Marcillaud

Les crayons, c’est facile d’utilisation, surtout quand on veut modifier des éléments de la table en cours de lecture. Mais lorsqu’il s’agit d’éléments liés, comme des mots clés sur des auteurs, le parcours est plus délicat !

Cet article présente une solution pour obtenir cela. Le code mériterait d’être amélioré, mais il présente une base de travail pour ceux qui aimeraient copier :)

Tout d’abord, précisons que cet exemple concerne SPIP 2.1. Certaines parties mériteraient d’être réadaptées pour SPIP 3 (mais devraient aussi fonctionner).

Nous avions besoin d’un listing d’auteurs où il serait facile de choisir des mots d’un groupe de mots donné (le numéro 40) avec un crayon. Dans notre cas le nombre de mots du groupe est limité (environ 10 mots) ce qui permet une interface assez simple : on liste tous les mots du groupe dans un sélecteur multiple.

Nous avons une liste d’auteurs (les lignes), et la colonne montrée indique les mots clés attachés (des métiers) aux auteurs. C’est eux que l’on veut éditer avec un crayon.

Liste d'auteurs avec les mots associés

Commençons par montrer le code permettant d’amener l’icone de crayon sur la liste :

  1. <td class="categorie #EDIT{ctags}">
  2. <BOUCLE_cat(MOTS){id_auteur}{id_groupe=40}{', '}>[(#TITRE|supprimer_numero)]</BOUCLE_cat>
  3. ---
  4. <//B_cat>
  5. </td>

Télécharger

Nous sommes à l’intérieur d’une boucle auteur (non présentée ici) et notre colonne est affichée grâce à une boucle sur les mots de même auteur, du groupe 40. Sur la balise td du tableau, nous appelons le crayons nommé ctags avec #EDIT{ctags}, comme n’importe quel crayon habituel, sauf qu’ici, la colonne « ctags » n’existe pas dans notre table auteurs.

Il va falloir indiquer à crayons :

  • comment obtenir les données du formulaire à afficher, via une fonction PHP
  • quel formulaire afficher, via un contrôleur et une saisie
  • comment enregistrer les données saisies, via une fonction PHP
  • comment réafficher le résultat, via une vue

Le plugin crayons sait gérer des formulaires traitant plusieurs types de champs d’un coup ; par exemple le crayon « introduction » affiche 3 champs : description, chapeau et texte (de mémoire) et gère leur enregistrement. Il utilise pour ça 1 contrôleur, qui obtient les données des 3 champs et affiche les 3 champs de formulaire.

Nous, nous avons besoin d’1 contrôleur, pour obtenir 1 champ de formulaire, mais les données du champ sont obtenues et enregistrées en plusieurs endroits ensuite. Le fait d’avoir 1 seul champ nous dispense de devoir créer un contrôleur PHP en plus du HTML, qui serait indispensable pour déclarer les champs utilisés dans le contrôleur sinon. Ici, Crayons comprend que le champ souhaité porte le même nom que le contrôleur.

Commençons par le plus simple.

Le contrôleur et sa saisie

Il affiche le formulaire et porte le nom indiqué dans la balise #EDIT, soit ici controleurs/ctags.html. Il contient :

  1. #CACHE{0}
  2.  
  3. #SET{mots,#ARRAY}
  4. <BOUCLE_mots_actifs(MOTS){id_groupe=40}{id_auteur}>
  5. #SET_PUSH{mots,#ID_MOT}
  6. </BOUCLE_mots_actifs>
  7.  
  8. <ul>
  9. [(#SAISIE{ctags, content_#ENV{key}_ctags, id_groupe=40, class=crayons-active, valeur=#GET{mots},
  10. label=<:utilisateurs:label_categorie:>})]
  11. </ul>

Télécharger

La première partie s’amuse à retrouver les mots déjà associés à l’auteur et les stocke dans une variable « mots » qui est passée, ensuite comme valeur de la saisie « ctags ». Cette saisie va lister les mots du groupe 40 et sélectionner ceux qui sont déjà associés à l’auteur.

Il est important de noter que la saisie crée un attribut name de nom : content_X_ctagsX est un identifiant attribué par crayons.

La saisie saisies/ctags.html est simple (enfin c’est relatif, mais c’est juste un copié collé adapté d’une autre saisie) :

  1. [(#REM) defaut peut être une chaine (plusieurs valeurs ou pas) qu'on sait décomposer ]
  2. #SET{defaut, #ENV{defaut}|saisies_chaine2tableau}
  3.  
  4. [(#REM) valeur peut être une chaine (plusieurs valeurs ou pas) qu'on sait décomposer ]
  5. #SET{valeur, #ENV{valeur}|saisies_valeur2tableau}
  6.  
  7. <select name="#ENV{nom}[]" multiple="multiple" class="#GET{type}[ (#ENV{class})]" size="#ENV{size,15}" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ value="(#ENV{valeur_forcee,#ENV{valeur}})"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>
  8. [(#ENV{cacher_option_intro}|non)
  9. <option value="">[(#ENV{option_intro})]</option>]
  10. <BOUCLE_mots(MOTS){par id_groupe, num titre, titre}{id_groupe ?}>
  11. [<optgroup label="(#TYPE|unique|attribut_html)" />]
  12. <option value="#ID_MOT" [(#ID_MOT|in_array{#ENV{valeur_forcee,#GET{valeur,#GET{defaut}}}}|oui) selected="selected"]>[(#TITRE|supprimer_numero)]</option>
  13. </BOUCLE_mots>
  14. </select>

Télécharger

En gros, c’est une saisie affichant une sélection multiple, bouclant sur les mots du groupe de mot demandé.

Ajoutons un rien de CSS pour enlever le label de notre saisie (sinon le crayons est 2 fois plus large) :

  1. .crayon-html .saisie_ctags label {display:none;}
  2. .crayon-html .saisie_ctags {padding-left:10px;}

Télécharger

Déjà, nous arrivons maintenant à un formulaire lorsqu’on édite ressemblant à cela :
Crayon ouvert

Faisons la vue.

La vue

La vue d’un crayon, c’est ce qui s’affiche après avoir modifié un élément. Il y a des vues par défaut, mais on peut les personnaliser. Nous, nous souhaitons le même affichage que dans notre tableau à l’origine. Il nous suffit de recoller le même code dans vues/ctags.html :

  1. #CACHE{0}
  2. <BOUCLE_cat(MOTS){id_auteur}{id_groupe=40}{', '}>[(#TITRE|supprimer_numero)]</BOUCLE_cat>
  3. ---
  4. <//B_cat>

Télécharger

Simple et efficace :)

Voyons maintenant comment faire pour que crayons enregistre les données !

Préparation et enregistrement des données

Crayons, pour savoir si une donnée a été modifiée par la personne qui valide le formulaire fait envoyer par le formulaire une signature des données qu’il avait calculé au moment de l’affichage dudit formulaire. Chaque champ possède 2 signatures : une signature identifiant le champ (le key de tout à l’heure), une autre identifiant le contenu des données (un md5 de celles-ci).

Comme SPIP dans l’espace privé, Crayons n’acceptera de modifier une donnée que si sa signature envoyée par le formulaire est la même que celle actuellement en base. Le cas contraire indique que quelqu’un d’autre a modifié les données entre temps. Si les signatures correspondent, il regarde si les données envoyées sont différentes également (sinon pas la peine d’enregistrer la même chose). Si tel est le cas l’enregistrement se fait, pour uniquement les données modifiées.

Le corollaire est que Crayons doit connaître les données en créant le formulaire ! Comme notre champ n’est pas standard, il va falloir lui indiquer comment l’obtenir.

C’est ce que fait la fonction suivante (à placer, par exemple dans un fichier d’option - il y a certainement mieux, mais je n’ai pas regardé plus en détail encore) :

  1. // obtenir la liste des identifiants de mots clés liés à notre objet...
  2. function valeur_champ_ctags($table, $id, $champ) {
  3. $valeurs = sql_allfetsel("m.id_mot", "spip_mots AS m, spip_mots_${table}s AS ma",
  4. array("m.id_groupe=40", "m.id_mot = ma.id_mot", "ma.id_${table}=".sql_quote($id)));
  5. $valeurs = array_map('array_shift', $valeurs);
  6. return $valeurs;
  7. }

Télécharger

La fonction valeur_champ_XX est le nom du champ souhaité (c’est aussi personnalisable en fonction du nom de la table) reçoit 3 arguments : le type de table (ici auteur), son identifiant (le numéro d’auteur), et le nom du champ désiré (le X, soit « ctags » ici).

La fonction doit retourner la valeur du champ. Ici, on retourne un tableau de tous les identifiants de mots clés associé à l’objet et son identifiant. Une fonction d’API spécifique en SPIP 3 pourrait obtenir ces données (cf API éditer liens), mais j’étais en SPIP 2.1.

Ceci fait, il faut maintenant indiquer le traitement à réaliser pour notre contrôleur, puisque ce n’est pas un traitement automatique. Cela se passe avec la fonction X_revisionX est le nom du contrôleur.

  1. // la révision du crayon ctags doit supprimer ou ajouter des liaisons de mots clés
  2. function ctags_revision($id_objet, $colonnes, $type_objet){
  3.  
  4. // actuellement en bdd
  5. $old = valeur_champ_ctags($type_objet, $id_objet, 'ctags');
  6. // ceux qu'on veut maintenant
  7. $new = explode(',', $colonnes['ctags']);
  8. // les mots à supprimer
  9. $del = array_diff($old, $new);
  10. // les mots à ajouter
  11. $add = array_diff($new, $old);
  12.  
  13. // actions !
  14. if ($del) {
  15. sql_delete("spip_mots_${type_objet}s",
  16. array(sql_in("id_mot", $del), "id_$type_objet=$id_objet"));
  17. }
  18. if ($add) {
  19. $adds = array();
  20. foreach ($add as $a) {
  21. $adds[] = array(
  22. "id_$type_objet" => $id_objet,
  23. "id_mot" => $a,
  24. );
  25. }
  26. sql_insertq_multi("spip_mots_${type_objet}s", $adds);
  27. }
  28.  
  29. return true;
  30. }

Télécharger

Ici la fonction reçoit 3 arguments : l’identifiant de l’objet, les couples de données à enregistrer, le type d’objet. Ici, SPIP 3 simplifierait aussi le code avec son API d’édition de liens.

Le principe est simple : on récupère ce qu’on veut enregistrer dans la clé ’ctags’ de la variable $colonne. Elle contient la liste des identifiants de mots pour notre auteur. On fait ensuite la différence entre ce qui est déjà stocké et les nouvelles données pour savoir ce qu’on doit enlever et ajouter en BDD.

Voilà :)

Bon, tout n’est pas très propre, mais c’est une belle base !

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à.