Chats 2 - SPIP 3 Créer un nouvel objet dans le futur SPIP 3 (en développement)

, par Matthieu Marcillaud

Il y a presque deux ans, j’écrivais l’article Créer un nouvel objet éditorial en mettant des félins dans l’interface privée. Le développement de SPIP 3.0 (en alpha2 actuellement) fait des prouesses extraordinaires pour tout ce qui est la création et l’utilisation de nouveaux objets éditoriaux. Je propose ici de décrire la création d’une version 2.0 du plugin d’exemple Chats, en partant de rien.

SPIP 3.0 alpha 2

C’est le nom de la version en cours de développement et qui externalise un certain nombre de fonctionnalités de SPIP, tout en rendant générique un grand nombre de processus habituels (Cédric a effectué là de biens beaux travaux !). Cette version se voit dotée d’un espace privé entièrement en squelettes (et donc facilement surchargeable), découpé en Z, tout en normalisant le code HTML sous-jacent qui en avait besoin. Certaines fonctions anciennement en plugin ont été intégrées : les itérateurs, une partie de CFG, une partie de Bonux, Textwheel, Job Queue, et d’autres ont atterri en tant qu’extension par défaut de la distribution SPIP comme la médiathèque ou le plugin de boites modales (mediabox). La liste est longue des nouveautés et comme c’est encore loin d’être finalisé nous nous attarderons juste sur ce qui nous intéresse pour notre nouvel objet éditorial.

Il faut noter tout de même que dans cette nouvelle version, on peut déclarer, comme on le faisait pour déclarer des tables SQL à SPIP un nouvel objet éditorial. Ceci fait, la simple présence d’un champ « id_rubrique » permet de ranger l’objet dans une rubrique. La simple présence de « lang » permet de gérer des langues... la simple présence de « id_trad » permet de gérer les traductions... la simple déclaration de l’objet permet d’y lier des mots, des documents, des forums, de gérer les révisions de l’objet, déclarer des statuts permet d’afficher l’encart de changement de statut, d’accéder aux prévisualisations, ... Enfin presque !

Voilà... SPIP 3, c’est ça... mais c’est aussi que... on peut pratiquement ne rien écrire, SPIP est capable de générer à la volée une partie des pages nécessaires à l’affichage de l’objet si elles n’existent pas dans le plugin (ou en tant que surcharge ailleurs).

En fait, à l’heure ou j’écris, il faut tout de même écrire le code HTML du formulaire, et son code PHP. Mais vous allez voir que c’est impressionnant !

Débuter le plugin

Créons un plugin « chats » dans notre dossier plugins/ avec les fichiers :

  • paquet.xml
  • prive/themes/spip/images/chat-24.png de même que -48, -128 et -16
  • base/chats.php
  • chats_administrations.php
  • lang/chat_fr.php
  • lang/paquet-chats_fr.php

Nous allons les remplir au fur et à mesure. Tout d’abord, le paquet.xml.

paquet.xml

Comme on le remarque, la déclaration se fait maintenant avec un fichier nommé « paquet.xml » en lieu et place de « plugin.xml » (ce dernier est toujours compris par SPIP 3.0 alpha 2). « paquet.xml » a une écriture plus cohérente et concise.

Peu de choses ont changé dans les pipelines à l’exception notable, d’un nouveau pipeline pour déclarer l’objet (et sa table SQL). Il se nomme « declarer_tables_objets_sql ».

Enfin, une partie des descriptions du plugin (slogan, descriptif et éventuellement le nom) passent dans les chaînes de langue (lang/paquet-chats_fr.php), et peuvent ainsi être traduits.

  1. <paquet
  2. prefix="chats"
  3. categorie="edition"
  4. version="2.0.0"
  5. etat="stable"
  6. compatibilite="[3.0.0-alpha2;["
  7. logo="prive/themes/spip/images/chat-128.png"
  8. schema="1.0.0"
  9. documentation="http://marcimat.magraine.net/?article356"
  10. >
  11.  
  12. <nom>Chats (Plugin d'exemple)</nom>
  13. <!-- Gestion des chats dans SPIP -->
  14.  
  15. <auteur lien="http://magraine.net/">Matthieu Marcillaud</auteur>
  16. <licence>GNU/GPL</licence>
  17.  
  18. <credit lien="http://www.yootheme.com/icons">Logo de YOOtheme</credit>
  19.  
  20.  
  21. <pipeline nom="declarer_tables_objets_sql" inclure="base/chats.php" />
  22. <pipeline nom="declarer_tables_interfaces" inclure="base/chats.php" />
  23.  
  24. <!-- facilitons les champs de formulaires -->
  25. <necessite nom="saisies" compatibilite="[1.14.0;]" />
  26.  
  27. </paquet>

Télécharger

Nous retrouvons

  • le nom, l’auteur, la version
  • l’état (stable, test, dev)
  • le préfixe
  • la version de la structure des tables SQL du plugin se nomme maintenant « schéma »

chats_administrations.php

Le fichier d’installation, simple. Il peut changer (par rapport à SPIP 2.1) car on peut maintenant dans les mises à jour d’un plugin utiliser la même procédure que celle de SPIP Core pour les déclarer. Ainsi, une fonction « maj_plugin » permet de passer : la version actuelle, la version future, et un tableau de la liste des actions à faire. Contentons nous de la création et de la suppression du plugin :

  1. function chats_upgrade($nom_meta_base_version, $version_cible){
  2.  
  3. $maj = array();
  4. $maj['create'] = array(
  5. array('maj_tables', array('spip_chats')),
  6. );
  7.  
  8. include_spip('base/upgrade');
  9. maj_plugin($nom_meta_base_version, $version_cible, $maj);
  10. }
  11.  
  12. function chats_vider_tables($nom_meta_base_version) {
  13. sql_drop_table("spip_chats");
  14. effacer_meta($nom_meta_base_version);
  15. }

Télécharger

Dans la variable $maj la clé « create » est appliquée à la première installation du plugin, et contient un tableau listant les fonctions à appeler avec leurs paramètres. Ici, on appelera donc l’équivalent de : maj_tables('spip_chats');.

Pour une mise à jour, on utilise par exemple $maj['numéro'] = array(...) tel que $maj['1.1.0'] = .... Nous le verrons plus loin.

base/chats.php

Le fichier de déclaration comporte les fonctions appelées par le pipeline « declarer_tables_objets_sql ». Voyons cela :

  1. function chats_declarer_tables_objets_sql($tables){
  2. $tables['spip_chats'] = array(
  3.  
  4. 'principale' => "oui",
  5. 'field'=> array(
  6. "id_chat" => "bigint(21) NOT NULL",
  7. "nom" => "tinytext DEFAULT '' NOT NULL",
  8. "race" => "tinytext DEFAULT '' NOT NULL",
  9. "date" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
  10. "date_naissance" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
  11. "robe" => "tinytext DEFAULT '' NOT NULL",
  12. "infos" => "text DEFAULT '' NOT NULL",
  13. "maj" => "TIMESTAMP"
  14. ),
  15. 'key' => array(
  16. "PRIMARY KEY" => "id_chat",
  17. ),
  18. 'titre' => "nom AS titre, '' AS lang",
  19. 'date' => "date",
  20. );
  21.  
  22. return $tables;
  23. }

Télécharger

Ce tableau de la table peut prendre de nombreux autres attributs. Ils sont optionnels et complétés automatiquement par SPIP en absence de leur déclaration pour certains. Nous en verrons quelques-uns par la suite.

Nous remarquons les déclarations ’field’ et ’key’ qui n’ont pas changé, présentant le nom des champs et leur description SQL pour ’field’, de même que le type de clé et le ou les champs d’application pour ’key’.

La clé "principale" indique que la table est une table qui s’auto-incrémente. Les clés "titre" et "date" (déclarées avant dans le pipeline declarer_tables_interfaces) indiquent respectivement les colonnes servant au calculs des titres d’URLs, et aux calculs de date (si besoin).

Pour pouvoir utiliser l’alias de boucle CHATS à la place du nom complet spip_chats, comme dans <BOUCLE_liste(CHATS){par titre}>...</BOUCLE_liste>, il faut déclarer cet alias via le pipeline declarer_tables_interfaces :

  1. function chats_declarer_tables_interfaces($interfaces) {
  2. $interfaces['table_des_tables']['chats'] = 'chats';
  3. return $interfaces;
  4. }

Télécharger

lang/paquet-chats.php

Mettons un peu de texte sur la signification du plugin dans le fichier lang/paquet-chats.php , tel que :

  1. if (!defined('_ECRIRE_INC_VERSION')) return;
  2.  
  3. $GLOBALS[$GLOBALS['idx_lang']] = array(
  4. 'chats_nom' => "Chats",
  5. 'chats_slogan' => "Plugin d'apprentissage",
  6. 'chats_description' => "Crée un nouvel objet éditorial de façon simple,
  7. donnant un exemple de code pour les développeurs.",
  8. );

Télécharger

Ces descriptions pourront ainsi être traduites. Remarque : chats_nom n’est pas encore pris en compte à l’heure de l’écriture de ces lignes, mais c’est prévu.

Premier test

À partir de maintenant, le plugin doit pouvoir s’activer et s’installer. Il est présent dans la liste des plugins.

PNG - 26.2 ko
Affichage du plugin dans la liste des plugins
En cas d’erreurs dans le fichier paquet.xml, celles-ci seraient affichées de façon précise.

Une fois coché, et la configuration enregistrée, l’activation indique l’état de l’installation. Ici, le plugin installe la version 1.0 de sa structure SQL.

PNG - 21.2 ko
Activation du plugin chats
La version 1.0.0 du plugin chats est installée.

On peut alors aller sur l’URL privée ?exec=chats qui affiche en clignotant (pour l’instant) cela :

PNG - 41.5 ko
Liste des chats...
Les chaînes de langues absentes sont affichées en rouge

Ajout d’un bouton d’accès et des chaînes manquantes

Pour pourvoir accéder à la page ?exec=chats facilement, nous allons créer un bouton dans le menu, depuis la déclaration de paquet.xml. On en profitera pour ajouter dans la foulée un bouton d’ajout rapide d’un chat. Ces 2 lignes sont donc ajoutées à paquet.xml :

  1. <menu nom="chats" titre="chat:titre_chats" parent="menu_edition" icone="images/chat-16.png" />
  2.  
  3. <menu nom="chat_creer" titre="chat:icone_creer_chat" parent="outils_rapides" icone="images/chat-new-16.png" action="chat_edit" parametres="new=oui" />

Télécharger

Il faudra ajouter une image « chat-new-16.png » qui est la même que « chats-16.png », avec un + de dessiné. Cette image (pour faciliter la création) se trouve dans SPIP dans prive/themes/images/add-16.png

Nous pouvons ensuite ajouter quelques chaînes de langue dans le fichier lang/chat_fr.php. Attention dans le nom du fichier : ici, c’est l’objet désiré au singulier, alors que pour le fichier de langue du paquet, c’est le préfixe du plugin qui est utilisé.

  1. $GLOBALS[$GLOBALS['idx_lang']] = array(
  2. // I
  3. 'icone_creer_chat' => "Créer un chat",
  4. 'info_aucun_chat' => "Aucun chat",
  5.  
  6. // T
  7. 'titre_chats' => "Chats",
  8.  
  9. );

Télécharger

Aussitôt, on peut voir (en repassant sur la page d’administration des plugins pour mettre à jour les informations du paquet) les icônes et le texte :

PNG - 41.5 ko
Icone de chat rapide, et chaînes de langues présentes

Voilà qui est maintenant plus clair. On comprend que SPIP génère automatiquement cette page, car nous n’avons créé encore aucun squelette pour afficher quoi que ce soit. Cela pourrait être fait, mais nous allons essayer le lui faire faire le maximum de chose sans rien toucher.

Créer un chat

En cliquant le bouton de création d’un chat, on voit qu’il manque des choses :
une chaîne de langue... et un formulaire !

PNG - 42.3 ko
Édition d’un chat.
Il manque le formulaire !

La chaîne de langue va dans lang/chat.php en ajoutant

  1. 'icone_modifier_chat' => "Modifier ce chat",

Par la suite, et pour simplifier, je ne parlerai plus de l’ajout des chaînes de langue dans ce fichier. Vous saurez faire de toutes façons :)

Pour le formulaire, il va falloir un peu plus de travail, en créant les fichiers :

  • formulaires/editer_chat.html et
  • formulaires/editer_chat.php

Le fichier HTML est semblable à SPIP 2.1 et utilise ici le plugin « saisies » :

  1. <div class='formulaire_spip formulaire_editer formulaire_#FORM formulaire_#FORM-#ENV{id_chat,nouveau}'>
  2. [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
  3. [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
  4.  
  5. [(#ENV{editable})
  6. <form method='post' action='#ENV{action}'><div>
  7. #ACTION_FORMULAIRE{#ENV{action}}
  8. <input type='hidden' name='id_chat' value='#ENV{id_chat}' />
  9. <ul>
  10. [(#SAISIE{input, nom, label=<:chat:label_nom:>})]
  11. [(#SAISIE{input, race, label=<:chat:label_race:>})]
  12. [(#SAISIE{input, robe, label=<:chat:label_robe:>})]
  13. [(#SAISIE{textarea, infos, label=<:chat:label_infos:>})]
  14. </ul>
  15. [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
  16. <!--extra-->
  17. <p class="boutons"><input type='submit' class='submit' value='<:bouton_enregistrer:>' /></p>
  18. </div></form>
  19. ]
  20. </div>

Télécharger

Le fichier PHP appelle des fonctions génériques de traitement des objets :

  1. if (!defined("_ECRIRE_INC_VERSION")) return;
  2.  
  3. include_spip('inc/actions');
  4. include_spip('inc/editer');
  5.  
  6.  
  7. function formulaires_editer_chat_charger_dist($id_chat='new', $id_rubrique=0, $retour='', $lier_trad=0, $config_fonc='', $row=array(), $hidden=''){
  8. $valeurs = formulaires_editer_objet_charger('chat',$id_chat,$id_rubrique,$lier_trad,$retour,$config_fonc,$row,$hidden);
  9. return $valeurs;
  10. }
  11.  
  12. /**
  13.  * Identifier le formulaire en faisant abstraction des parametres qui ne representent pas l'objet edite
  14.  */
  15. function formulaires_editer_chat_identifier_dist($id_chat='new', $id_rubrique=0, $retour='', $lier_trad=0, $config_fonc='', $row=array(), $hidden=''){
  16. return serialize(array(intval($id_chat)));
  17. }
  18.  
  19. function formulaires_editer_chat_verifier_dist($id_chat='new', $id_rubrique=0, $retour='', $lier_trad=0, $config_fonc='', $row=array(), $hidden=''){
  20. return formulaires_editer_objet_verifier('chat', $id_chat);
  21. }
  22.  
  23. function formulaires_editer_chat_traiter_dist($id_chat='new', $id_rubrique=0, $retour='', $lier_trad=0, $config_fonc='', $row=array(), $hidden=''){
  24. return formulaires_editer_objet_traiter('chat',$id_chat,$id_rubrique,$lier_trad,$retour,$config_fonc,$row,$hidden);
  25. }

Télécharger

Enfin, dans la déclaration de l’objet (base/chats.php), il faut indiquer à SPIP les champs qu’il a le droit de modifier en ajoutant la clé :

  1. 'champs_editables' => array(
  2. "nom", "race", "robe", "infos", "date_naissance"
  3. ),

Télécharger

Avec quelques chaînes de langues en plus, voici ce que l’on obtient : le formulaire est visible et fonctionne (cependant il ne réaffiche pas les textes saisis après une création).

PNG - 16.4 ko
Formulaire de modification du chat

La liste des chats liste les créations.

PNG - 35.6 ko
Liste des chats

Enfin, la vue d’un chat permet de changer la date de publication et de mettre un logo. Elle n’affiche pas automatiquement autre chose que le titre.

PNG - 60.2 ko
Vue d’un chat

Lier des documents et des mots clés

Pour lier des documents au chat il suffit de cocher les « Chats » dans la configuration des documents sur ?exec=configurer_contenu.

Pour lier des mots clés, il suffit de créer un groupe de mot permettant la liaison avec des chats.

PNG - 74.1 ko
Mots clés, document et logo

Versionner les modifications des chats

Pour pouvoir revenir sur des modifications effectuées sur le contenu de la table chats, il faut indiquer quels champs sont versionnables, puis activer les « révisions » sur l’objet Chats (?exec=configurer_revisions). On ajoute donc, dans la déclaration de notre objet éditorial :

  1. 'champs_versionnes' => array(
  2. "nom", "race", "robe", "infos", "date_naissance",
  3. ),

Télécharger

Sur l’accueil, on peut ainsi suivre les modifications faites, puis revenir dessus éventuellement depuis la page des révisions :

PNG - 9.8 ko
Révisions sur l’accueil
PNG - 64.9 ko
Révision d’un chat

Lier les chats aux rubriques

Pour pouvoir lier un chat à une, et une seule rubrique, il suffit de créer un champ « id_rubrique » dans la table spip_chats et d’ajouter un sélecteur de rubrique dans le formulaire d’édition.

Déclarons le dans base/chats.php, avec les autres champs :

  1. 'field'=> array(
  2. "id_chat" => "bigint(21) NOT NULL",
  3. "id_rubrique" => "bigint(21) NOT NULL DEFAULT 0",
  4. ...

Télécharger

Créons la mise à jour dans chats_administrations.php en ajoutant la version 1.1.0, qui ajoute le champs id_rubrique et un index dessus :

  1. $maj['1.1.0'] = array(
  2. array('maj_tables', array('spip_chats')),
  3. array('sql_alter', "TABLE spip_chats ADD INDEX id_rubrique(id_rubrique)")
  4. );

Télécharger

Changeons le schéma dans paquet.xml pour refléter la mise à jour :

  1. schema="1.1.0"

Enfin, ajoutons un sélecteur de rubrique sur le formulaire d’édition (repris de celui sur le formulaire d’édition d’un article) :

  1. [<li class="editer editer_rubrique[ (#ENV**{erreurs}|table_valeur{id_parent}|oui)erreur]">
  2. <label for="id_parent"><:titre_cadre_interieur_rubrique:></label>[
  3. <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{id_parent})</span>
  4. ]
  5. (#VAL|chercher_rubrique{#ENV{id_chat},#ENV{id_parent},'chat',#ENV{id_secteur},'',0,form_simple})
  6. </li>]

Télécharger

Et regardons maintenant :

PNG - 15.6 ko
Choix d’une rubrique

Afficher les chats sur les rubriques

Pour aller plus loin, on va vite souhaiter pouvoir créer et voir des chats depuis les rubriques. Pour cela, il va nous falloir d’une part se brancher sur le pipeline « affiche_enfants », et d’autre part créer un premier squelette de liste de chats, permettant de trier les chats, mais surtout de filtrer par rubrique la liste.

Ajoutons l’utilisation du pipeline dans paquets.xml :

  1. <pipeline nom="affiche_enfants" inclure="chats_pipelines.php" />

Ajoutons dans le pipeline, l’appel à notre future nouvelle liste d’éléments, ainsi que le bouton pour ajouter de nouveaux chats si l’on peut. Avec la fonction trouver_objet_exec() qui retourne des informations utiles sur la page en cours de lecture dans l’espace privé, on peut filtrer l’affichage sur le type d’objet, et le fait qu’il soit ou non en édition.

  1. function chats_affiche_enfants($flux) {
  2. if ($e = trouver_objet_exec($flux['args']['exec'])
  3. AND $e['type'] == 'rubrique'
  4. AND $e['edition'] == false) {
  5.  
  6. $id_rubrique = $flux['args']['id_rubrique'];
  7.  
  8. $bouton = '';
  9. if (autoriser('creerchatdans','rubrique', $id_rubrique)) {
  10. $bouton .= icone_verticale(_T('chat:icone_creer_chat'), generer_url_ecrire('chat_edit', "id_rubrique=$id_rubrique"), "chat-24.png", "new", 'right')
  11. . "<br class='nettoyeur' />";
  12. }
  13.  
  14. $lister_objets = charger_fonction('lister_objets','inc');
  15. $flux['data'] .= $lister_objets('chats', array('titre'=>_T('chat:titre_chats_rubrique') , 'id_rubrique'=>$id_rubrique, 'par'=>'nom'));
  16. $flux['data'] .= $bouton;
  17.  
  18. }
  19. return $flux;
  20. }

Télécharger

La fonction lister_objet permet d’appeler un squelette affichant une liste de l’objet souhaité. Il est stocké dans prive/objets/liste/chats.html. Son code peut ressembler à ça :

  1. [(#SET{defaut_tri,#ARRAY{
  2. nom,1,
  3. date,#ENV{date_sens,-1},
  4. id_chat,1
  5. }})
  6. ]<B_liste_chats>
  7. #ANCRE_PAGINATION
  8. <div class="liste-objets chats">
  9. <table class='spip liste'>
  10. [<caption><strong class="caption">(#ENV*{titre,#GRAND_TOTAL|singulier_ou_pluriel{chat:info_1_chat,chat:info_nb_chats}})</strong></caption>]
  11. <thead>
  12. <tr class='first_row'>
  13. <th class='picto' scope='col'></th>
  14. <th class='nom' scope='col'>[(#TRI{nom,<:chat:label_nom:>,ajax})]</th>
  15. <th class='langue' scope='col'></th>
  16. <th class='date' scope='col'>[(#TRI{date,<:date:>,ajax})]</th>
  17. <th class='id' scope='col'>[(#TRI{id_chat,<:info_numero_abbreviation:>,ajax})]</th>
  18. </tr>
  19. </thead>
  20. <tbody>
  21. <BOUCLE_liste_chats(CHATS){id_rubrique?}{id_mot?}{id_auteur?}{where?}{statut?}{recherche?}{tri #ENV{par,num nom},#GET{defaut_tri}}{pagination #ENV{nb,10}}>
  22. <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">
  23. <td class='picto'>[(#CHEMIN_IMAGE{chat-16.png}|balise_img)]</td>
  24. <td class='nom principale'>[(#LOGO_CHAT|image_reduire{20,26})]<a href="[(#ID_CHAT|generer_url_entite{chat})]" title="<:info_numero_abbreviation|attribut_html:> #ID_RUBRIQUE">[(#RANG). ]#NOM</a></td>
  25. <td class='langue'></td>
  26. <td class='date secondaire'>[(#DATE|affdate_jourcourt)]</td>
  27. <td class='id'>[(#AUTORISER{modifier,chat,#ID_CHAT}|?{
  28. <a href="[(#URL_ECRIRE{chats_edit,id_chat=#ID_CHAT})]">#ID_CHAT</a>,
  29. #ID_CHAT
  30. })]</td>
  31. </tr>
  32. </BOUCLE_liste_chats>
  33. </tbody>
  34. </table>
  35. [<p class='pagination'>(#PAGINATION{prive})</p>]
  36. </div>
  37. </B_liste_chats>[
  38. <div class="liste-objets chats caption-wrap"><strong class="caption">(#ENV*{sinon,''})</strong></div>
  39. ]<//B_liste_chats>

Télécharger

On peut ainsi voir la liste des chats appartenant à une rubrique, dans la vue de la rubrique :

PNG - 35.3 ko
Chats dans une rubrique

Donner sa langue au chat

La présence des champs "lang" et "langue_choisie" dans la table SQL des chats suffit à faire afficher un formulaire de changement de langue de l’objet. Ajoutons les.

Dans base/chats.php ajouter :

  1. "lang" => "VARCHAR(10) DEFAULT '' NOT NULL",
  2. "langue_choisie" => "VARCHAR(3) DEFAULT 'non'",

Télécharger

Dans base/chats_administrations.php ajouter :

  1. $maj['1.3.0'] = array(array('maj_tables', array('spip_chats')));

Enfin, changer la version du schéma dans paquet.xml :

  1. schema="1.3.0"

Après un passage sur la page d’administration des plugins pour effectuer la mise à jour, sur la page de configuration de multilinguisme, on peut cocher la présence du formulaire de langue sur les Chats :

PNG - 36.1 ko
Configuration du multilinguisme

Ainsi, pour tout nouveau chat créé, le formulaire de langue s’affiche et on peut modifier la langue (pour peu qu’il y ait au moins 2 langues possibles dans la configuration du multilinguisme). Pour les anciens chats, il faudrait faire une mise à jour de la base en leur définissant une langue par défaut, sinon, le bouton [changer] n’apparaît pas.

PNG - 26.3 ko
Langue au chat

Traductions de chats

Sur le même principe que précédemment, on ajoute le champ « id_trad » tel que :

  1. "id_trad" => "bigint(21) DEFAULT '0' NOT NULL",

Sur la page de configuration du multilinguisme, il faut cocher la gestion des traductions sur les chats :

PNG - 6.9 ko
Gestion des traductions sur les chats

Il faut aussi appeler des fonctions qui vont peupler le formulaire de création d’un chat, traduction d’un autre, par les textes de la traductions. Pour cela, il faut créer le fichier inc/precharger_chat.php contenant au moins la première fonction (la seconde étant facultative si on ne change pas le code qui est présenté ici) :

  1. include_spip('inc/precharger_objet');
  2.  
  3. function inc_precharger_chat_dist($id_chat, $id_rubrique=0, $lier_trad=0) {
  4. return precharger_objet('chat', $id_chat, $id_rubrique, $lier_trad, 'nom');
  5. }
  6.  
  7. // fonction facultative si pas de changement dans les traitements
  8. function inc_precharger_traduction_chat_dist($id_chat, $id_rubrique=0, $lier_trad=0) {
  9. return precharger_traduction_objet('chat', $id_chat, $id_rubrique, $lier_trad, 'nom');
  10. }

Télécharger

On peut ainsi traduire un chat :

PNG - 35.4 ko
Formulaire de traduction d’un chat
PNG - 18.7 ko
Traduction préremplie du texte d’origine

Lier des auteurs aux chats

On pourrait créer le squelette qui affiche le contenu de notre chat, qui afficherait le formulaire de liaison entre auteurs et chat dedans, ainsi que les autres formulaires souhaités.

Nous pouvons aussi continuer d’utiliser le squelette créé automatiquement par SPIP et se brancher sur le pipeline « affiche_milieu » pour ajouter le formulaire d’auteurs sur les chats. C’est ce que nous allons voir ici. Dans paquet.xml, on ajoute l’appel au pipeline :

  1. <pipeline nom="affiche_milieu" inclure="chats_pipelines.php" />

Son utilisation appelle l’inclusion de SPIP prive/objets/editer/liens, qui elle-même appelle le formulaire éditer liens, permettant de lier 2 objets entre eux et d’afficher les liaisons existantes. Il suffit d’indiquer la source (les auteurs) et la cible, et le tour est joué :

  1. function chats_affiche_milieu($flux) {
  2. if ($e = trouver_objet_exec($flux['args']['exec'])
  3. AND $e['type'] == 'chat'
  4. AND $e['edition'] == false) {
  5. $texte = recuperer_fond('prive/objets/editer/liens', array(
  6. 'table_source' => 'auteurs',
  7. 'objet' => $e['type'],
  8. 'id_objet' => $e['id_objet'],
  9. #'editable'=>autoriser('associerauteurs', $e['type'], $e['id_objet']) ? 'oui' : 'non'
  10. ));
  11. if ($p=strpos($flux['data'],"<!--affiche_milieu-->"))
  12. $flux['data'] = substr_replace($flux['data'],$texte,$p,0);
  13. else
  14. $flux['data'] .= $texte;
  15. }
  16.  
  17. return $flux;
  18. }

Télécharger

PNG - 16 ko
Auteurs liés à un chat

Mettre des statuts sur les chats

Pour mettre des statuts de publication sur les chats, il faut un champ « statut » sur la table SQL, quelques déclarations et des chaînes de langues, éventuellement quelques autorisations.

Sur le principe habituel, on ajoute le champ statut dans la déclaration de base/chats.php (il faudra faire une mise à jour dans chats_administrations.php).

  1. "statut" => "varchar(255) DEFAULT '0' NOT NULL",

Le code de la mise à jour ajoute aussi la valeur "publie" a tous les chats déjà existants :

  1. $maj['1.5.0'] = array(
  2. array('maj_tables', array('spip_chats')),
  3. array('sql_updateq', 'spip_chats', array('statut'=>'publie'))
  4. );

Télécharger

On ajoutera aussi une déclaration des statuts prévus, toujours dans la déclaration de l’objet, ainsi qu’une description des critères limitant l’affichage d’une boucle CHATS en fonction du statut du chat :

  1. 'statut_textes_instituer' => array(
  2. 'prepa' => 'texte_statut_en_cours_redaction',
  3. 'prop' => 'texte_statut_propose_evaluation',
  4. 'publie' => 'texte_statut_publie',
  5. 'refuse' => 'texte_statut_refuse',
  6. 'poubelle' => 'texte_statut_poubelle',
  7. ),
  8. 'statut'=> array(
  9. array(
  10. 'champ' => 'statut',
  11. 'publie' => 'publie',
  12. 'previsu' => 'publie,prop,prepa',
  13. 'post_date' => 'date',
  14. 'exception' => array('statut','tout')
  15. )
  16. ),

Télécharger

La clé statut_textes_instituer indique la liste des statuts de notre objet éditorial ainsi que le nom des chaînes de langue correspondantes.

La clé statut dit à peu près : que restreint-on d’afficher en fonction de tel champ ? La restriction porte sur quel champ SQL ? Quel est la valeur de ce champ lorsqu’un chat est publié, lorsqu’il peut être prévisualisé. Y a t’il une date à prendre en compte pour ne pas publier les chats avant une certaine date (post_date) ? et quels critères de boucles annulent la prise en compte de cette restriction : ici {statut} et {tout}.

PNG - 5.6 ko
Statuts sur les chats

Lier des chats à des articles

Voici la plus grosse partie des squelettes et codes PHP à produire dès lors que l’on veut lier notre objet à 0 ou plusieurs autres objets, depuis la page de ceux-ci, par exemple lier des chats à des articles, depuis la page d’un article.

Pour installer un formulaire de liaison de chats sur les articles, un peu comme pour les auteurs précédemment, il va falloir insérer le formulaire sur les articles, en utilisant le même pipeline affiche_milieu. Il faut avant tout qu’il existe une table spip_chats_liens pour pouvoir lier des chats. Créons tout ça.

Dans paquet.xml, on change le schéma, et on ajoute le pipeline declarer_table_auxiliaires :

  1. <pipeline nom="declarer_tables_auxiliaires" inclure="base/chats.php" />

On déclare dans ce pipeline notre table de liaison :

  1. function chats_declarer_tables_auxiliaires($tables) {
  2. $tables['spip_chats_liens'] = array(
  3. 'field' => array(
  4. "id_chat" => "bigint(21) DEFAULT '0' NOT NULL",
  5. "id_objet" => "bigint(21) DEFAULT '0' NOT NULL",
  6. "objet" => "VARCHAR (25) DEFAULT '' NOT NULL",
  7. "vu" => "VARCHAR(6) DEFAULT 'non' NOT NULL"
  8. ),
  9. 'key' => array(
  10. "PRIMARY KEY" => "id_chat,id_objet,objet",
  11. "KEY id_chat" => "id_chat"
  12. )
  13. );
  14. return $tables;
  15. }

Télécharger

On crée la mise à jour dans chats_administrations.php :

  1. $maj['1.6.0'] = array(array('maj_tables', array('spip_chats_liens')));

Ceci fait, il va nous falloir créer plusieurs squelettes de liste. Le premier prive/objets/liste/chats_lie.html est une liste affichée lorsque des chats sont liés à un objet.

Il peut être (inspiré de celui des mots-clés) :

  1. [(#SET{defaut_tri,#ARRAY{
  2. num nom,1,
  3. nom,1,
  4. race,1,
  5. id_chat,1
  6. }})
  7. ]
  8. <input type="hidden" name="debutchatl" value='#ENV{debutchatl,#EVAL{_request("debutchatl");}}' />
  9. <B_liste_chat>
  10. #ANCRE_PAGINATION
  11. <div class="liste-objets liste-objets-lies chats">
  12. <table class='spip liste'>
  13. [<caption><strong class="caption">(#ENV*{titre,#GRAND_TOTAL|singulier_ou_pluriel{chat:info_1_chat,chat:info_nb_chats}})</strong></caption>]
  14. <thead>
  15. <tr class='first_row'>
  16. <th class='picto' scope='col'></th>
  17. <th class='nom' scope='col'>[(#TRI{nom,<:chat:label_nom:>,ajax})]</th>
  18. <th class='race' scope='col'>[(#TRI{race,<:chat:label_race:>,ajax})]</th>
  19. <th class='action' scope='col'>&nbsp;</th>
  20. </tr>
  21. </thead>
  22. <tbody>
  23. <BOUCLE_liste_chat(CHATS){statut==.*}{id_chat?}{id_rubrique?}{id_objet?}{objet}{where?}{tri #ENV{par,nom},#GET{defaut_tri}}{par num nom,nom}{pagination #ENV{nb,10} chatl}>
  24. <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})][(#ID_CHAT|=={#ENV{id_lien_ajoute}}|oui)append]">
  25. <td class='picto'>[(#CHEMIN_IMAGE{chat-16.png}|balise_img)]</td>
  26. <td class='nom principale'>[(#LOGO_CHAT|image_reduire{20,20})]<a href="[(#ID_CHAT|generer_url_entite{chat})]" title="<:info_numero_abbreviation|attribut_html:> #ID_CHAT">[(#RANG). ]#NOM</a></td>
  27. <td class='race secondaire'>#RACE</td>
  28. <td class='action'><button class="button link delete" name="supprimer_lien[chat-#ID_CHAT-#OBJET-#ID_OBJET]" value="X"><:chat:lien_retirer_chat:> [(#CHEMIN_IMAGE{supprimer-12.png}|balise_img{'X'})]</button></td>
  29. </tr>
  30. </BOUCLE_liste_chat>
  31. </tbody>
  32. </table>
  33. [<p class='pagination'>(#PAGINATION{prive})</p>]
  34. [(#GRAND_TOTAL|>{3}|oui)<div class="action"><button class="button link" name="supprimer_lien#EVAL{chr(91)}chat-*-#OBJET-#ID_OBJET#EVAL{chr(93)}" value="X"><:chat:lien_retirer_chats:> [(#CHEMIN_IMAGE{supprimer-12.png}|balise_img{'X'})]</button></div>]
  35. </div>
  36. </B_liste_chat>
  37. <div class="liste-objets liste-objets-lies chats caption-wrap">
  38. <strong class="caption">[(#ENV*{titre,<:chat:info_aucun_chat:>}) ]</strong>
  39. </div>
  40. <//B_liste_chat>

Télécharger

La seconde liste est utilisée pour rechercher des chats à lier, et doit se créer dans prive/objets/liste/chats_associer.html. Il peut être ainsi, et fait appel à un troisième squelette s’il y a un trop grand nombre de chats :

  1. [(#SET{defaut_tri,#ARRAY{
  2. statut,1,
  3. multi nom,1,
  4. }})]
  5. [(#SET{_MAX_CHATS_LISTE,[(#VAL{_MAX_CHATS_LISTE}|defined|?{[(#VAL{_MAX_CHATS_LISTE}|constant)],50})]})]
  6. <BOUCLE_exclus(CHATS){tout}{id_objet}{objet}{doublons 1}{doublons 2} />
  7. <BOUCLE_nb_chats(CHATS){tout}{doublons 1} />#SET{total,#TOTAL_BOUCLE}<//B_nb_chats>
  8.  
  9. <BOUCLE_nombreux(CONDITION){si #GET{total}|>{#GET{_MAX_CHATS_LISTE}}}>
  10.  
  11. [(#INCLURE{fond=prive/objets/liste/chats_associer-recherche,env,doublons})]
  12.  
  13. </BOUCLE_nombreux>
  14.  
  15. [(#REM) Pas beaucoup de chat ]
  16. <B_chats>
  17. #ANCRE_PAGINATION
  18. <div class="liste-objets liste-objets-associer chats">
  19. <table class='spip liste'>
  20. [<caption><strong class="caption">(#ENV*{titre,#GRAND_TOTAL|singulier_ou_pluriel{chat:info_1_chat,chat:info_nb_chats}})</strong></caption>]
  21. <thead>
  22. <tr class='first_row'>
  23. <th class='picto' scope='col'></th>
  24. <th class='titre' scope='col'>[(#TRI{nom,<:chat:label_nom:>,ajax})]</th>
  25. <th class='action' scope='col'>&nbsp;</th>
  26. </tr>
  27. </thead>
  28. <tbody>
  29. <BOUCLE_chats(CHATS){doublons 2}{tri #ENV{par,nom},#GET{defaut_tri}}{par num nom, nom}{pagination 10}>
  30. <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">
  31. <td class='picto'>[(#CHEMIN_IMAGE{chat-16.png}|balise_img)]</td>
  32. <td class='nom principale'>[(#LOGO_CHAT|image_reduire{20,20})]<a href="[(#ID_CHAT|generer_url_entite{chat})]" title="<:info_numero_abbreviation|attribut_html:> #ID_CHAT">[(#RANG). ]#NOM</a></td>
  33. <td class='action'><button class="button link" name="ajouter_lien[chat-#ID_CHAT-#OBJET-#ID_OBJET]" value="+"><:chat:lien_ajouter_chat:> [(#CHEMIN_IMAGE{ajouter-12.png}|balise_img{'+'})]</button></td>
  34. </tr>
  35. </BOUCLE_chats>
  36. </tbody>
  37. </table>
  38. [<p class='pagination'>(#PAGINATION{prive})</p>]
  39. </div>
  40. </B_chats>
  41. <div class="liste-objets liste-objets-associer chats caption-wrap">
  42. <strong class="caption">[(#ENV*{titre,<:chat:info_aucun_chat:>}) ]</strong>
  43. </div>
  44. <//B_chats>
  45.  
  46. <//B_nombreux>

Télécharger

Lorsqu’il y a trop de résultats à afficher, c’est un autre squelette qui est appelé, prive/objets/liste/chats_associer-recherche.html qui offre un champ de saisie pour rechercher parmi les chats afin de restreindre les résultats. Il peut être :

  1. <input type="text" class="text" name="recherche" value="[(#ENV*{recherche})]" />
  2. <input type="submit" class="submit" name="rechercheb" value="<:info_rechercher:>" />
  3. <input type="hidden" name="debutchata" value='#ENV{debutchata,#VAL{debutchatachata}|_request}' />
  4. #SET{recherche,#ENV*{recherche}}
  5. [(#GET{recherche}|non|et{#ENV*{rechercheb}})
  6. #SET{recherche,'/./'}
  7. <input type="hidden" name="rechercheb" value='x' />
  8. ]
  9. <B_liste_chat>
  10. #ANCRE_PAGINATION
  11. <div class="liste-objets liste-objets-associer chats">
  12. <table class='spip liste'>
  13. [<caption><strong class="caption">(#ENV*{titre,#GRAND_TOTAL|singulier_ou_pluriel{chat:info_1_chat,chat:info_nb_chats}})</strong></caption>]
  14. <thead>
  15. <tr class='first_row'>
  16. <th class='picto' scope='col'></th>
  17. <th class='nom' scope='col'>[(#TRI{nom,<:chat:label_nom:>,ajax})]</th>
  18. <th class='race' scope='col'>[(#TRI{race,<:chat:label_race:>,ajax})]</th>
  19. <th class='action' scope='col'>&nbsp;</th>
  20. </tr>
  21. </thead>
  22. <tbody>
  23. <BOUCLE_liste_chat(CHATS){doublons 2}{recherche #GET{recherche}}{tri #ENV{par,nom},#GET{defaut_tri}}{par num nom}{pagination 10 chata}>
  24. <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">
  25. <td class='picto'>[(#CHEMIN_IMAGE{chat-16.png}|balise_img)]</td>
  26. <td class='nom principale'>[(#LOGO_CHAT|image_reduire{20,20})]<a href="[(#ID_CHAT|generer_url_entite{chat})]" title="<:info_numero_abbreviation|attribut_html:> #ID_CHAT">[(#RANG). ]#NOM</a></td>
  27. <td class='race'>#RACE</td>
  28. <td class='action'><button class="button link" name="ajouter_lien[chat-#ID_CHAT-#OBJET-#ID_OBJET]" value="+"><:chat:lien_ajouter_chat:> [(#CHEMIN_IMAGE{ajouter-12.png}|balise_img{'+'})]</button></td>
  29. </tr>
  30. </BOUCLE_liste_chat>
  31. </tbody>
  32. </table>
  33. [<p class='pagination'>(#PAGINATION{prive})</p>]
  34. </div>
  35. </B_liste_chat>[(#ENV*{recherche}|oui)
  36. <div class="liste-objets liste-objets-associer chats caption-wrap">
  37. <strong class="caption">[(#ENV*{titre,<:chat:info_aucun_chat:>}) ]</strong>
  38. </div>]
  39. <//B_liste_chat>

Télécharger

Note : Il y a certainement moyen de regrouper ces 2 derniers squelettes en un seul, mais je n’ai pas pris le temps de le faire.

On obtient donc, sur la page d’un article :

PNG - 54.6 ko
Des chats sur les articles

Permettre de chercher des chats

Pour permettre la recherche de chat dans l’espace privé ou via le critère {recherche} sur une boucle chat, il faut le déclarer dans la description de l’objet, en ajoutant dedans :

  1. 'rechercher_champs' => array(
  2. 'nom' => 8, 'race' => 1, 'robe' => 1, 'infos' => 2
  3. ),

Télécharger

PNG - 33.8 ko
Recherche parmi les chats

Conclusion

Voilà une petite démonstration prometteuse donc, pour ce qui concerne les objets éditoriaux. L’espace privé utilisant Zpip permet d’adapter facilement les pages que créée SPIP, ce qui n’est pas montré ici. Une prochaine fois peut être :)

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