Statuts sur les objets....

, par Matthieu Marcillaud

Définir des statuts permet - par exemple - de garder un objet en édition dans la partie privée de SPIP et de choisir de ne le publier sur l’espace public que lorsqu’il est prêt, par quelqu’un qui en a l’autorisation.

Indiquons d’abord que cela s’adresse à des SPIP 2.1, certainement 2.0 également. Pour les versions actuellement en développement, cela fonctionnera avec la 2.2 s’il cette version existe un jour, mais à partir de 2.3, ce code a été en partie simplifié (et heureusement !).

Nous allons supposer qu’un objet éditorial quelconque existe (ça peut être un Chat ou autre). Pour l’exemple, ce sera un objet « Formations », se composant d’une table spip_fh_formations et ayant la clé primaire id_formation (oui, déjà, il y a quelques incohérences entre le nom de la table et celui de la clé primaire, mais on fait avec ce qu’on a sous la main !).

Nous supposerons aussi que les pages de vue et d’édition de l’objet sont réalisées. Ce qui nous intéresse est exclusivement le statut.

Préambule

Il serait simple de penser qu’il suffit de mettre un champ « statut » dans le formulaire même d’édition pour changer le statut d’un objet... Mais que neni ! SPIP empêche cela ! Tout champ « statut » soumis dans les fonctions standards modifier_contenu() sera tout bonnement ignoré, car ce n’est pas la même autorisation qui entre en jeu. Le statut se change via un autre formulaire, ou une autre action (ou possiblement en bidouillant le formulaire d’édition, ce que nous n’oserons pas faire ici !)

Le statut dans la table

Il faut posséder un champ « statut » dans la table SQL de notre objet. Par exemple avec cette définition :

  1. "statut" => "VARCHAR(15) DEFAULT 'prepa'",

S’il n’y était pas, il faudra éventuellement forcer une mise à jour en incrémentant le numéro de version de la base du plugin (<version_base> dans plugin.xml) et en ajoutant au fichier d’installation (base/formations_upgrade.php) quelque chose comme le code ci-dessous dans la fonction formations_upgrade() :

  1. // Ajouter le statut
  2. if (version_compare($current_version, '0.6', '<')) {
  3. include_spip('base/create');
  4. maj_tables("spip_fh_formations");
  5. ecrire_meta($nom_meta_base_version,$current_version="0.6");
  6. }

Télécharger

Filtrer les boucles automatiquement sur les statuts

Nous pouvons créer un fichier de fonction et le déclarer (<fonctions>formations_fonctions.php</fonctions> dans plugin.xml) en disposant le code de boucle ci-dessous. On regarde 2 choses dans la boucle :

  • si un critère {statut} est présent : on n’opère pas de restriction, c’est le critère qui le définit. Par exemple {statut?} ou {statut IN prepa,publie}
  • si on est en « prévisualisation », on autorise en plus des articles publiés, les articles en préparation. (je n’ai pas testé cette partie).

Dans les autres cas donc, on force la présence dans les critères de requête d’une selection (WHERE) correspondant au statut « publie ».

  1. //
  2. // <BOUCLE_(FH_FORMATIONS)>
  3. //
  4. function boucle_FH_FORMATIONS_dist($id_boucle, &$boucles) {
  5. $boucle = &$boucles[$id_boucle];
  6. $id_table = $boucle->id_table;
  7. $mstatut = $id_table .'.statut';
  8.  
  9. // Restreindre aux elements publies
  10. if (!isset($boucle->modificateur['criteres']['statut'])) {
  11. if (!$GLOBALS['var_preview'])
  12. array_unshift($boucle->where,array("'='", "'$mstatut'", "'\\'publie\\''"));
  13. else
  14. array_unshift($boucle->where,array("'IN'", "'$mstatut'", "'(\\'publie\\',\\'prop\\')'"));
  15. }
  16. return calculer_boucle($id_boucle, $boucles);
  17. }

Télécharger

Donner le droit de modifier le statut de l’objet

Dans le même fichier de fonctions (ou mieux, via le pipeline autoriser), on peut ajouter la fonction d’autorisation permettant (ici) aux administrateurs de modifier le statut de l’objet :

  1. function autoriser_formation_publier_dist($faire, $type, $id, $qui, $opt) {
  2. return
  3. ($qui['statut'] == '0minirezo')
  4. AND (
  5. !$qui['restreint'] OR !$id
  6. OR in_array($id, $qui['restreint'])
  7. );
  8. }

Télécharger

Afficher certaines des boucles dans le privé avec {statut?}

Notez que le critère {statut?} devra être ajouté à vos boucles sur l’espace privé dans certains fichiers (prive/contenu/formation.html, prive/exec/formation.html et d’autres) pour que la boucle s’affiche même si l’objet n’a pas le statut publié. Il faudra peut être dans certains cas, tester avant si l’utilisateur peut voir ou modifier l’objet avec une autorisation, par exemple, pour prive/exec/formation.html :

  • avec le plugin SPIP-Bonux :
    1. <BOUCLE_si_autorise(CONDITION){si (#ID_FORMATION|intval|et{#AUTORISER{voir,formation,#ID_FORMATION}})}>
    2. <BOUCLE_formation(FH_FORMATIONS){id_formation}{statut?}{tout}>
    3. ...

    Télécharger

  • ou avec le plugin Itérateurs (le critère si s’applique à n’importe quelle boucle)
    1. <BOUCLE_formation(FH_FORMATIONS)
    2. {si (#ID_FORMATION|intval
    3. |et{#AUTORISER{voir, formation, #ID_FORMATION}})}
    4. {id_formation}{statut?}{tout}>
    5. ...

    Télécharger

On a donc conditionné l’affichage de la boucle à la vérification d’une autorisation.

Ajouter le bloc de changement de statut sur la vue de l’objet

Ceci fait, nous pouvons ajouter un élément dans le bloc d’information de l’objet, listant les différents statuts utilisables (que l’administrateur pourra changer).

Statuts des formations

Pour cela, nous créons les fichiers prive/infos/fh_formations.html (si ce n’est pas déjà fait) et prive/infos/fh_formations_fonctions.php.

Commençons par le code HTML :

  1. <BOUCLE_formation(FH_FORMATIONS){id_formation=#ENV{id}}{statut?}>
  2. <div class='infos'>
  3. <div class='numero'>
  4. <:formations:info_numero_formation:>
  5. <p>#ID_FORMATION</p>
  6. </div>
  7.  
  8. [(#URL_ECRIRE{formations}
  9. |icone{<:formations:bouton_retour_formations:>, #CHEMIN{images/formations-24.png},'center'})]
  10.  
  11.  
  12. [(#REM)
  13. Bloc de changement de statut
  14. ]
  15. [(#ID_FORMATION|instituer_fh_formation{#STATUT})]
  16.  
  17.  
  18. [(#REM)
  19. Bouton voir en ligne
  20. ]
  21. <div>
  22. <a href="[(#URL_PAGE{fiche_formation}
  23. |parametre_url{type,formation}
  24. |parametre_url{id_formation,#VAL{id_formation}|_request}
  25. |parametre_url{var_mode,[(#STATUT|=={publie}|?{calcul,preview})]})]" class="cellule-h">
  26. [<img src="(#CHEMIN{prive/images/racine-24.gif})" style="vertical-align:middle;" />]
  27. <span style="vertical-align:middle;"><:voir_en_ligne:></span>
  28. </a>
  29. </div>
  30. </div>
  31. </BOUCLE_formation>

Télécharger

Nous bouclons sur la boucle FH_FORMATIONS pour l’identifiant en cours de lecture ({id_formation=#ENV{id}}), indépendamment du statut de la formation ({statut?}).

Ce qui va afficher la liste des statuts est l’appel suivant :

  1. [(#ID_FORMATION|instituer_fh_formation{#STATUT})]

(En dessous, l’appel au bouton « voir en ligne » n’est pas très standard. Je n’avais pas testé plus loin, comme déjà dit)

Donc, la ligne appelle une fonction nommée « instituer_fh_formation » que nous allons décrire dans le fichier php mitoyen. Cette fonction prend 2 arguments : l’identifiant de l’objet et son statut actuel :

  1. function instituer_fh_formation($id_formation, $statut){
  2. $instituer_fh_formation = charger_fonction('instituer_fh_formation', 'inc');
  3. return $instituer_fh_formation($id_formation, $statut);
  4. }

Télécharger

Cette fonction ne fait que charger une autre fonction ! Dans un autre dossier (cela pour harmoniser avec les noms des fichiers de SPIP). Créons donc ce fichier inc/instituer_fh_formation.php et incorporons le code ci-dessous, copie presque identique aux fonctions d’autres objets simples (brèves) utilisées dans SPIP :

  1. if (!defined("_ECRIRE_INC_VERSION")) return;
  2.  
  3. function inc_instituer_fh_formation_dist($id_formation, $statut=-1)
  4. {
  5. if ($statut == -1) return "";
  6.  
  7. $liste_statuts = array(
  8. // statut => array(titre,image)
  9. 'prepa' => array(_T('formations:item_formation_prepa'),''),
  10. 'prop' => array(_T('formations:item_formation_proposee'),''),
  11. 'publie' => array(_T('formations:item_formation_validee'),''),
  12. 'poubelle' => array(_T('formations:item_formation_poubelle'),''),
  13. );
  14. if (!in_array($statut, array_keys($liste_statuts)))
  15. $liste_statuts[$statut] = array($statut,'');
  16.  
  17. $res =
  18. "<ul id='instituer_fh_formation-$id_formation' class='instituer_fh_formation instituer'>"
  19. . "<li>" . _T('formations:entree_formation_publiee')
  20. ."<ul>";
  21.  
  22. $href = redirige_action_auteur('editer_fh_formation',$id_formation,'formation', "id_formation=$id_formation");
  23. foreach($liste_statuts as $s=>$affiche){
  24. $href = parametre_url($href,'statut',$s);
  25. if ($s==$statut)
  26. $res .= "<li class='$s selected'>" . puce_statut($s) . $affiche[0] . '</li>';
  27. else
  28. $res .= "<li class='$s'><a href='$href' onclick='return confirm(confirm_changer_statut);'>" . puce_statut($s) . $affiche[0] . '</a></li>';
  29. }
  30.  
  31. $res .= "</ul></li></ul>";
  32. return $res;
  33. }

Télécharger

Cette fonction liste les statuts disponibles (avec le texte correspondant), génère une liste pour les afficher en surlignant le statut en cours de lecture. Il ajoute un lien d’action sur chaque lien pour permettre de changer le statut. Ce lien d’action (dans $href) pointe sur action/editer_fh_formation qu’il faudra modifier pour qu’il comprenne le message envoyé.

Dans notre exemple, il faudrait conditionner le lien de changement de statut à l’autorisation de modifier le statut de l’objet (instituer), ce qui n’est pas réalisé ici (pas bien !).

Que l’action s’effectue réellement !

Il faut maintenant éditer action/editer_fh_formation.php pour qu’il comprenne le message de notre action. On teste dans l’argument d’action $arg reçu, la présence de statut dans la chaine. Si c’est le cas, on traite notre statut comme provenant d’un formulaire (set_request()), sinon, on fait ce qu’on avait l’habitude.

  1. function action_editer_fh_formation_dist() {
  2. $securiser_action = charger_fonction('securiser_action', 'inc');
  3. $arg = $securiser_action();
  4.  
  5. // Envoi depuis les boutons "publier/supprimer cette breve"
  6. if (preg_match(',^(\d+)\Wstatut\W(\w+)$,', $arg, $r)) {
  7. $id_formation = $r[1];
  8. set_request('statut', $r[2]);
  9. revisions_fh_formations($id_formation);
  10. } else {
  11. ...
  12. }
  13. ...
  14. }

Télécharger

Notre code de la fonction revisions_fh_formations() se trouve lui aussi complété pour tenir compte de la possibilité de la présence d’un changement de statut. On force dans ce cas le changement via la fonction sql_updateq(), mais uniquement si le statut à changé.

  1. // Enregistrer certaines modifications d'une formation
  2. function revisions_fh_formations($id_formation, $c=false) {
  3.  
  4. // recuperer les champs dans POST s'ils ne sont pas transmis
  5. if ($c === false) {
  6. $c = array();
  7. foreach (array(
  8. 'titre', 'id_cat', 'id_theme', 'statut',
  9. 'pourquoi', 'contenu', 'objectifs',
  10. 'page', 'label', 'sous_titre',
  11. 'methode', 'duree', 'prix_ht') as $champ) {
  12. if (($a = _request($champ)) !== null) {
  13. $c[$champ] = $a;
  14. }
  15. }
  16. }
  17.  
  18. include_spip('inc/modifier');
  19. modifier_contenu('fh_formation', $id_formation, array(
  20. 'nonvide' => array('titre' => _T('info_sans_titre')),
  21. 'invalideur' => "id='id_formation/$id_formation'"
  22. ),
  23. $c);
  24.  
  25.  
  26.  
  27. $champs = array();
  28.  
  29. // Changer le statut de la formation ?
  30. if ($statut = _request('statut', $c)) {
  31. $statut_ancien = sql_getfetsel("statut", "spip_fh_formations", "id_formation=$id_formation");
  32. if ($statut != $statut_ancien) {
  33. $champs['statut'] = _request('statut', $c);
  34. }
  35. }
  36.  
  37. if ($champs) {
  38. sql_updateq('spip_fh_formations', $champs, "id_formation=$id_formation");
  39. }
  40.  
  41. // Invalider les caches
  42. include_spip('inc/invalideur');
  43. suivre_invalideur("id='id_formation/$id_formation'");
  44.  
  45. }

Télécharger

À ce moment là, notre changement de statut via le bloc gauche fonctionne. Oui, je l’accorde, il en faut du code !

Et les petites puces de changement rapide de statut ?

Ah quelle idée !
Vous souhaitez cela ?

Puces de changement rapide

C’est encore un rien complexe aussi !!!
Il faut, comme sur la page prive/exec/formations.html appeler le code qui va générer ces petites puces dans la boucle, qui est ici dans une cellule de tableau :

  1. <td class="statut">
  2. #SET{auth,#AUTORISER{modifier,formation,#ID_FORMATION}}
  3. [(#ID_FORMATION
  4. |puce_changement_statut{#STATUT,'',fh_formation})]
  5. </td>

Télécharger

C’est la fonction puce_changement_statut() qui appelle inc_puce_statut_dist() qui va appeller une fonction puce_statut_${type}_dist(), soit pour notre exemple puce_statut_fh_formation_dist() qu’il nous faut créer. Je l’ai mis dans formation_options.php (pas adapté, mais ce sera bien mieux dans les futures versions !) :

  1. // puce statut doit etre charge pour le prive...
  2. // (changement rapide de statut)
  3. function puce_statut_fh_formation_dist($id, $statut, $id_rubrique, $type='fh_formation', $ajax = false) {
  4. global $lang_objet;
  5.  
  6. static $coord = array('publie' => 2,
  7. 'prepa' => 0,
  8. 'prop' => 1,
  9. 'refuse' => 3,
  10. 'poubelle' => 4);
  11.  
  12. if (!$id) {
  13. $id = $id_rubrique;
  14. $ajax_node ='';
  15. }
  16. else $ajax_node = " id='imgstatut$type$id'";
  17.  
  18. if ($ajax) {
  19. $statut = sql_getfetsel('statut', 'spip_fh_formations', 'id_formation='.$id);
  20. }
  21.  
  22. $inser_puce = puce_statut($statut, " width='9' height='9' style='margin: 1px;'$ajax_node");
  23.  
  24. if (!autoriser('publier', 'formation', $id)
  25. OR !_ACTIVER_PUCE_RAPIDE)
  26. return $inser_puce;
  27.  
  28. $titles = array(
  29. "blanche" => _T('texte_statut_en_cours_redaction'),
  30. "orange" => _T('texte_statut_propose_evaluation'),
  31. "verte" => _T('texte_statut_publie'),
  32. "rouge" => _T('texte_statut_refuse'),
  33. "poubelle" => _T('texte_statut_poubelle'));
  34.  
  35. $clip = 1+ (11*$coord[$statut]);
  36. if ($ajax){
  37. return "<span class='puce_fh_formation_fixe'>"
  38. . $inser_puce
  39. . "</span>"
  40. . "<span class='puce_fh_formation_popup' id='statutdecal$type$id' style='margin-left: -$clip"."px;'>"
  41. . afficher_script_statut($id, $type, -1, 'puce-blanche.gif', 'prepa', $titles['blanche'])
  42. . afficher_script_statut($id, $type, -12, 'puce-orange.gif', 'prop', $titles['orange'])
  43. . afficher_script_statut($id, $type, -23, 'puce-verte.gif', 'publie', $titles['verte'])
  44. . afficher_script_statut($id, $type, -34, 'puce-rouge.gif', 'refuse', $titles['rouge'])
  45. . afficher_script_statut($id, $type, -45, 'puce-poubelle.gif', 'poubelle', $titles['poubelle'])
  46. . "</span>";
  47.  
  48. }
  49.  
  50. $nom = "puce_statut_";
  51.  
  52. if ((! _SPIP_AJAX) AND $type != 'fh_formation')
  53. $over ='';
  54. else {
  55. $action = generer_url_ecrire('puce_statut',"",true);
  56. $action = "if (!this.puce_loaded) { this.puce_loaded = true; prepare_selec_statut('$nom', '$type', '$id', '$action'); }";
  57. $over = "\nonmouseover=\"$action\"";
  58. }
  59.  
  60. return "<span class='puce_fh_formation' id='$nom$type$id' $over>"
  61. . $inser_puce
  62. . '</span>';
  63. }

Télécharger

En gros, la fonction liste les cases possibles et génère le code HTML de ces cases. La case active va se placer au bon endroit sur la souris lors du survol. La fonction afficher_script_statut() génère une action vers instituer_$type, soit ici instituer_fh_formation. Il nous faut créer ce fichier (action/instituer_fh_formation.php) qui redirige vers la fonction de révision de l’objet :

  1. function action_instituer_fh_formation_dist() {
  2. $securiser_action = charger_fonction('securiser_action', 'inc');
  3. $arg = $securiser_action();
  4.  
  5. list($id_formation, $statut) = preg_split('/\W/', $arg);
  6. if (!$statut) $statut = _request('statut_nouv'); // cas POST
  7. if (!$statut) return; // impossible mais sait-on jamais
  8.  
  9. $id_formation = intval($id_formation);
  10. include_spip('action/editer_fh_formation');
  11. revisions_fh_formations($id_formation, array('statut' => $statut));
  12. }

Télécharger

Voilà... Ouf !

Épilogue

Vous dites ? mais c’est horrible ce code pour une si petite chose ?
Je dirai : oui ! Il faut vraiment qu’on trouve quelque chose de plus simple et plus joli tel que :

  1. #FORMULAIRE_CHANGEMENT_STATUT{objet, id_objet}
  2. #FORMULAIRE_CHANGEMENT_STATUT_RAPIDE{objet, id_objet}

Télécharger

A suivre !

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