Des techniques pour étendre les possibilités des boucles

Voici exposées plusieurs techniques permettant d’étendre les possibilités offertes par les boucles standards de SPIP :

Tout d’abord une technique permettant de mutualiser le critère IN d’une boucle sous à partir de SPIP 1.9.2 et offrant également la possibilité d’écrire des boucles qui semblaient impossibles à faire.

Ensuite, une deuxième technique disponible depuis SPIP 2.0.x, permettant de faire de nouvelles boucles grâce aux jointures « automatiques » ou « forcées ».

Demandez la lune à vos boucles :) !

L’idée

Vous utilisez souvent la même liste de valeurs dans le critère IN d’une boucle.

exemple dans la boucle suivante :

<BOUCLE_art(ARTICLES){id_article IN 12,13,14,25}>
	<h1>#TITRE</h1>
</BOUCLE_art>

La boucle précédente liste les articles d’identifiants 12, 13, 14 ou 25.

Une solution de mutualisation pour un seul squelette

Une première possibilité pour mutualiser cette liste consiste à la charger dans un tableau statique (voir cet article du site officiel de SPIP sur l’utilisation des tableaux avec #ARRAY) . On peut alors l’utiliser plusieurs fois dans le même squelette (ce qui le rend plus facile à maintenir), exemple :

[(#SET{montableau,#ARRAY{0,12,1,13,2,14,3,25}})]

<BOUCLE_art1(ARTICLES){id_article IN #GET{montableau}|sinon{0}}{par hasard}>
	<h1>#TITRE</h1>
</BOUCLE_art1>

<BOUCLE_art2(ARTICLES){id_article IN #GET{montableau}|sinon{0}}{par titre}>
	<h1>#TITRE</h1>
</BOUCLE_art2>

Une solution pour l’ensemble des squelettes

Imaginons que j’utilise souvent cette liste dans plusieurs squelettes.

Voici un moyen de la mutualiser :

Je crée un squelette tout simple qui ne fait que contenir une chaine, formée de la liste des valeurs séparées par un caractère peu utilisé (par exemple le pipe ’|’) :

On crée par exemple le fichier maliste.html :

12|13|14|25

Et voici le squelette montest.html :

#CACHE{0}
<BOUCLE_art(ARTICLES){id_article IN #INCLURE{fond=maliste}|explode{'|'}}>
	<h1>#TITRE</h1>
</BOUCLE_art>

Le filtre « explode » est une fonction php qui sépare la chaîne passée en paramètre et remplit un tableau avec les valeurs. La fonction prend comme premier paramètre le caractère de séparation... et le tour est joué ! C’est un peu comme si le squelette inclus passait un tableau en paramètre.

Application à la réalisation de boucles « impossibles »

Voici un exemple permettant de faire une boucle impossible en SPIP 1.9.2 normalement : on souhaite lister les articles contenus dans les rubriques ayant le mot clé d’identifiant 15.

Une possibilité offerte par les tableaux dynamiques consisterait à faire le squelette suivant (voir également les outils du plugin SPIP-Bonux pour construire des tableaux dynamiques) :

#CACHE{0}

#SET{montableau, #ARRAY{}}
<BOUCLE_rub(RUBRIQUES){id_mot=15}>
 [(#SET{montableau,
   #GET{montableau}|push{#ID_RUBRIQUE}
 })]
</BOUCLE_rub>

<BOUCLE_art(ARTICLES){id_rubrique IN #GET{montableau}|sinon{0}}{par titre}>
<h1>#TITRE</h1>
</BOUCLE_art>

Cette solution fonctionne parfaitement, mais elle oblige à réécrire une partie du code dans chaque squelette où l’on s’en sert.

Voici une solution où l’on mutualise la première partie :
On crée un fichier liste-rubriques.html qui crée une liste d’identifiants séparés par des pipes.

<BOUCLE_rub(RUBRIQUES){id_mot?}{id_groupe?}{'|'}>#ID_RUBRIQUE</BOUCLE_rub>

On peut alors se servir de cette « sous-boucle » dans tous les autres squelettes. Par exemple, on peut l’utiliser pour la boucle suivante dans un autre squelette :

<BOUCLE_art(ARTICLES){id_rubrique IN #INCLURE{fond=liste-rubriques}{id_mot=15}|explode{'|'}|sinon{0}}{par titre}>
<h1>#TITRE</h1>
</BOUCLE_art>

Compatibilité :
Testé sous SPIP 2.0.9, devrait fonctionner également en SPIP 1.9.2.

Une technique (beaucoup) plus efficace pour faire la même chose

Avec la version 1.9.2 sont apparues les jointures « automatiques » (Voir l’article « Forcer des jointures » sur le site programmer.spip.org). On peut alors utiliser la boucle suivante pour obtenir le même résultat :

<BOUCLE_art(ARTICLES mots_rubriques){mots_rubriques.id_mot=15}{par titre}>
<h1>#TITRE</h1>
</BOUCLE_art>

L’avantage est que :
-  Il n’y pas d’inclusion
-  Tout le travail de jointure est fait par la base de donnée, ce qui est beaucoup plus rapide.

Voici pour preuve la requête fournie par le mode debug (var_mode=debug) :

SELECT articles.titre, articles.lang
FROM <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+bWFiYXNlPC9jb2RlPg=="></span>.spip_articles
AS <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+YXJ0aWNsZXM8L2NvZGU+"></span>
INNER JOIN <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+bWFiYXNlPC9jb2RlPg=="></span>.spip_mots_rubriques
AS L1 ON ( L1.id_rubrique = articles.id_rubrique )
WHERE (articles.statut = 'publie')
AND (articles.date < '9999-12-31')
AND (L1.id_mot = 15)
GROUP BY articles.id_article
ORDER BY articles.titre

Compatibilité :
Testé sous SPIP 2.0.9, devrait fonctionner à partir de SPIP 1.9.2.

  1. Pour utiliser les nouvelles possibilités offertes par SPIP 2.0.x, il ne faut pas hésiter à utiliser un outil comme PhpMyAdmin, proposé en général par tous les hébergeurs, pour découvrir les tables de spip et leur structure (qui est vraiment TRÈS claire !) de manière à trouver les tables intermédiaires qui permettront ces nouvelles jointures.
    Vérifier ensuite que SPIP fait bien les jointures souhaitées en testant votre squelette avec le paramètre var_mode=debug et en affichant le « calcul » généré par la boucle considérée. Il faudra pour certains apprendre quelques rudiments de langage sql (Structured_Query_Language).
  2. (màj le 22/02/2010) On pourra lire également avec intérêt cet article qui traite de l’anti-doublon. C’est une technique très efficace pour créer des regroupements d’origines diverses du même type d’objet (des UNION en sql). Cela évitera dans la plupart des cas d’avoir recours aux tableaux.

Discussion

4 discussions

  • OH My God ! Mais j’ai encore du retard sur la subtilité des boucles moi ... oO

    Merci à toi Thierry pour ces éclaircissements :-)

    Répondre à ce message

  • Attention, bien mettre « IN » en majuscules. Je viens de m’arracher les cheveux à essayer de comprendre pourquoi ma boucle traitait seulement le premier élément, et en fait c’est juste parce que j’avais mis « in » en minuscules.

    Si ça peut faire gagner du temps à d’autres...

    Répondre à ce message

  • 1
    Matthieu Marcillaud
    <BOUCLE_art(ARTICLES mots_rubriques){id_mot=15}{par titre}>
    <h1>#TITRE</h1>
    </BOUCLE_art>

    J’aime bien cet exemple. Je l’aurais bien ajouté sur Programmer, mais il me parait un rien aléatoire. Ce n’est pas évident que le id_mot s’applique sur la rubrique et non l’article. En SPIP 2, je me demande si {mots_rubriques.id_mot=15} n’est pas plus parlant (si ça marche)

    • Thierry Kauffmann

      En SPIP 2, je me demande si mots_rubriques.id_mot=15 n’est pas plus parlant (si ça marche)

      Ça marche effectivement de la même façon (jointure absolument identique). C’est sans doute plus parlant et probablement moins aléatoire (dans la mesure où on spécifie la jointure). On peut penser que la requête est moins susceptible de changer suite à une mise à jour de SPIP.

    Répondre à ce message

  • Bravo et merci pour cette démonstration très claire qui apporte notamment plus de lumière sur les jointures faites directement dans les boucles

    Répondre à ce message

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom