Boucler sur un tableau, un compteur, les langues, une condition ...

construction de boucles permettant de parcourir un tableau php, d’itérer sur un compteur, de faire une condition, et d’itérer sur les langues

Nota SPIP-Contrib : cette contribution existe dorénavant en plugin. En attendant la mise à jour de sa documentation cet article reste celui de référence
-  sur la Zone : http://trac.rezo.net/trac/spip-zone...

Mise à jour du 29/11/2005 : quelques debugs et améliorations

L’idée de ce package est de créer des boucles sur autre chose
que des tables sql. Il y a 4 exemples dans le zip :

  • boucle langues : permet d’itérer sur les langues spip
  • boucle for : permet de boucler en affectant #COMPTEUR_BOUCLE à
    des valeurs successives (le for de php en gros)
  • boucle tableau : permet d’itérer sur les clés/valeurs d’un tableau
  • boucle if : permet de faire un tour de boucle si une condition
    est vraie

Installation

le tar contient 9 fichiers : 4 .php à inclure depuis mes_fonctions
ou assimilé, 4 squelettes d’exemple et un mes_fonctions d’exemple.
il suffit de détarrer ça à la racine d’un spip 1.8.2 ou 1.9, de mettre un include des fichiers php dans mes_fonctions.php3 (voir le fichier mes_fonctions.exemple.php3) et d’appeler les exemples par des urls comme page.php?fond=testLangue

Attention : le code est relativement quick and dirty. Je ne
sais pas trop ce que ça donne si on utilise ces boucles avec des
trucs tordus, des critères de travers ou des imbrications à tiroirs.

La boucle langue

C’est la plus simple car elle n’accepte aucun critère (on verra
plus tard si y’a besoin).

Elle permet d’itérer sur les langues définies « actives » dans
l’interface privée, et peut servir, par exemple, à faire un menu
langue personnalisé (tout ça viens d’une discussion sur la liste).

L’exemple joint (testLangue.html) montre à peu près tout ce qu’on peut faire avec, c’est à dire pas grand chose :-)

<BOUCLE_l(LANGUES)>
<br>#LANGUE : [(#LANGUE|traduire_nom_langue)].
</BOUCLE_l>

Si on ajoute le critère {tout} la boucle prend toutes les langues définies, et pas seulement celles activées. Attention,
si la configuration de précise pas de langues, elles sont toutes
considérées actives.

Comment ça marche : il suffit de définir une fonction
boucle_LANGUES pour traiter ce type de boucle.
Comme il n’y a pas de table ’langues’, on ’truande’ le compilo en
définissant des entrées dans la variable ’tables_principales’, et en
spécifiant sa pseudo-existance dans table_des_tables.
Dans la fonction, il faut maintenant définir tout le code à générer
pour la boucle. À coups de copier/coller depuis les boucles existant
dans spip, on en déduit le bout de code qui va bien.

Pour le critère tout, c’est leparseur qui se débrouille et fixe
le champ « tout » à « true ». Selon cette valeur, on va chercher un
meta ou l’autre.

La boucle for

Celle là est un peu tordue, mais elle permet de voir comment utiliser
des critères. L’utilisation basique de cette boucle est la suivante :

<BOUCLE_f(FOR){debut=2}{fin=10}{par 2}>
<br>#COMPTEUR_BOUCLE
</BOUCLE_f>

Contrairement à une boucle for dans php, on n’a pas besoin de définir de variable d’itération puisque #COMPTEUR_BOUCLE joue ce rôle.
Attention cependant, dans cet exemple, à la fin #TOTAL_BOUCLE
vaut 10 (dernière valeur) et pas 5 (nombre de tours).

Si le critère « par » est inversé ({!par 2}), on va en descendant, de « fin » jusqu’à « debut ».

Comment ça marche : comme pour la boucle précédente, on défini
une pseudo table qui contient des champs debut, fin
pour que le phraseur ne râle pas quand il croise ces noms dans les critères.

Là ou ça se complique, c’est qu’il faut analyser les critères
pour récupérer la valeur de debut, fin. Pour ça, on
parcours le tableau criteres de la structure de boucle et on
cherche les entrées ayant ’=’ comme opérateur et l’une des trois
valeurs comme partie gauche.
Il suffit alors d’appeler la fonction calculer_liste sur la partie
droite pour récupérer le code à insérer dans le code de la boucle.
Ce qui est magique, c’est que ça marche tout seul pour un
debut=1 ou pour un
debut=[(#TOTO|machin{bidule})].5

Une tambouille à base de eval permettrait également de traiter un
debut=#TOTO+1, mais j’ai l’impression que ça complique
pas mal les choses, et je ne maîtrise pas les effets de bord.

Enfin, pour le critère « par », c’est une fonction critere_par
qui surcharge la fonction par défaut et la rappelle si on n’est pas
en train de traiter une boucle for.

La boucle tableau

Après le for, le foreach ! Il s’agit cette fois d’aller chercher un
tableau associatif php et d’itérer sur ses clés / valeurs.
Le tableau doit sortir d’un élément extérieur (via mes_fonctions
ou autre) ou venir de spip (table meta, tableau des tables et autres
structures internes).

Il y a 2 contraintes :

  • il faut que ce tableau soit global, puisque quand on interprète
    une boucle, c’est toujours depuis une fonction gérée par le compilo
  • on ne peut pas définir ce tableau dans un tag php du squelette
    puisque celui ci sera évalué après le code du squelette (par contre
    ça marcherait sûrement dans le tag évoqué sur la liste).

L’utilisation de base est la suivante :

<BOUCLE_t(TABLEAU){var=toto}>
<br>- #CLE => #VALEUR
</BOUCLE_t>
vide ...
<//B_t>

Le critère var doit contenir le nom de la variable, et les
balises CLE et VALEUR correspondent aux paires clé/valeur. Si le
tableau est vide ou n’existe pas, on n’entre pas dans la boucle et
la partie <//B_..> est donc prise à la place.

Si jamais la valeur d’une entrée de tableau est elle même un
tableau, on peut utiliser cette valeur comme variable d’une boucle imbriquée via un critère {valeur} (exactement comme
quand on utilise un critère id_rubrique pour lister les articles
d’une rubrique sortie d’une boucle englobante) :

<BOUCLE_t(TABLEAU){var=tables_principales}>
	<BR>- #CLE => #VALEUR
	<BOUCLE_tt(TABLEAU){valeur}>
		<BR>-- #CLE => #VALEUR
		<BOUCLE_ttt(TABLEAU){valeur}>
			<BR>--- #CLE => #VALEUR
		</BOUCLE_ttt>
	</BOUCLE_tt>
</BOUCLE_t>

Ici, on sort les entrée de la table tables_principales dont
chaque valeur est elle-même un tableau de tableaux.

Pour aller chercher un élément de tableau directement, on
peut utiliser le critère cle, éventuellement en plusieurs
exemplaires :

<BOUCLE_t(TABLEAU){var=tables_principales}{cle=spip_tableau}{cle=field}>
<br>- #CLE => #VALEUR
</BOUCLE_t>

Ici, on sort donc directement le contenu de tables_principales['spip_tableau']['field']

Enfin, on peut utiliser le critère {fonction=toto()}
à la place du critère var afin d’itérer sur un tableau
retourné par une fonction.

Attention aux infos que vous allez chercher avec ça : si vous
listez le tableau auteur_session par exemple, vous allez mettre en
cache vos propres infos de session que les internautes suivants
récupéreront dans le cache. => mettre le délai à zéro dans ce cas.

comment ça marche : le code est très proche de celui de la
boucle for, à part qu’il y a un critère valeur qui permet de
récupérer le champ valeur de la boucle au dessus.
Là, il y aurait un point à améliorer car on ne peut pas trouver une
valeur de 2 boucles au dessus (je pensais pouvoir utiliser la
fonction index_pile, mais ça retourne une valeur de l’étage courant).

La boucle if

Je sens que celle-là, elle va être sujet à polémique :-)

Il s’agit d’évaluer une condition et de rentrer dans la boucle
ou pas selon sa valeur. Le tag <//B_..> peut alors
servir de partie ’else’.

Voici un exemple basique (et donc complètement pipo :-) :

<BOUCLE_a(ARTICLES){tout}>
  #ID_ARTICLE
  <BOUCLE_if(IF){condition #ID_ARTICLE > 1}>OUI</BOUCLE_if>NON<//B_if>
</BOUCLE_a>

(attention, la syntaxe a changé depuis la version précédente)

La condition peut contenir à peu près tout ce qu’on mettrait
dans un if php.

comment ça marche : comme les autres, sauf que cette fois, on
ne génère pas une boucle, mais un if.
La condition est récupérée comme les autres paramètres, sauf qu’en
plus on fait un eval dessus pour pouvoir évaluer les opérations au
lieu d’avoir simplement une chaîne contenant le texte de la condition.

La condition est parfois évaluée de façon exotique, il faut donc
généralement faire des tests et ne pas hésiter à regarder le code
généré pour comprendre pourquoi un if ne se comporte pas comme prévu.
Par exemple, je suis tombé sur des cas ou un
#MACHIN==truc ne marchait pas alors que
[(#MACHIN|={truc})] marchait nickel.

utilisation détournée : il arrive qu’on veuille mettre du html
autour d’une boucle si elle contient des choses, d’où l’utilisation
des blocs <B_..> et </B_..>.

Mais si on veut afficher des trucs que si il y a quelquechose parmi plusieurs boucles ?
Et bien il suffit de l’encadrer d’un bloc IF avec une condition « 1 » :

<B_bloc>
  avant
<BOUCLE_bloc(IF){cond=1}><BOUCLE_a(..)>
  ...
</BOUCLE_a><BOUCLE_b(...)>
  ...
</BOUCLE_b></BOUCLE_bloc>
  apres
</B_bloc>

Si aucune des deux boucles a et b ne sortent de résultats, les
textes avant et apres ne sont pas affichés.
Attention, il faut coller les tags pour ne pas sortir d’espaces
ou de retours la ligne qui empècheraient d’avoir un résultat
vraiment vide.

et après

J’ai dans un coin un début de boucle fichiers qui permet d’itérer
sur des fichiers du disque (ce qui permettrait de faire un explorateur
de fichiers coté serveur) et à l’occas, on pourrait également coder
une variante du foreach sur du xml. on bouclerait alors sur des
paires tag / contenu.
Il faudrait en plus coder un moyen d’écrire
#TAG{attribut}

Si ça vous botte, je vous le laisse comme exercice ;-)

Discussion

Aucune discussion

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