SPIP-Contrib

SPIP-Contrib

عربي | Deutsch | English | Español | français | italiano

273 Plugins, 191 contribs sur SPIP-Zone, 193 visiteurs en ce moment

Accueil du site > Squelettes > Tutoriaux pour squelettes > Boucles avec des conditions en OR (et explication des critères)

Boucles avec des conditions en OR (et explication des critères)

16 janvier 2012 – par Matthieu Marcillaud – <blink style='color:red;'>public|spip|ecrire:commentaire</blink>

5 votes

Comme vous le savez il n’est pas possible dans l’écriture des critères de boucle d’indiquer une condition OR, autrement appelé « OU logique », autrement dit d’indiquer : « trouve les éléments avec ça OU avec ça. »

La seule possibilité [1] est de créer un critère spécifique. C’est ce que nous allons voir ici pour un cas assez simple.

Quelqu’un est venu hier soir sur l’IRC de SPIP pour demander s’il était possible d’écrire une boucle brèves qui cherche (BREVES) {titre LIKE %#TITRE%} OU {texte LIKE %#TITRE%}, le #TITRE étant pris dans une boucle parente (une boucle ARTICLES il me semble, mais cela a peu d’importance...)

Une solution à ce problème est de créer son propre critère, puisque SPIP fait systématiquement des ET entre ses critères (ils sont cumulatifs).

J’annonce tout de suite que créer un critère peut être simple, mais peut aussi être très compliqué ! Par chance la demande ici est simple, et c’est pourquoi elle offre une jolie base pour un exemple.

Nous allons donc imaginer un critère nommé « va_chercher » qui prendra un argument. Son utilisation sera : {va_chercher toto} ou encore {va_chercher #TITRE}

Comme toute nouvelle définition (balise, filtre, critère, boucle), on mettra le code de notre critère dans un fichier de fonctions, par exemple dans squelettes/mes_fonctions.php.

Déclaration de base du critère

Voici une déclaration de la fonction PHP de notre critère. Ici il n’y a que la déclaration et aucune action encore.

  1. function critere_va_chercher_dist($idb, &$boucles, $crit) {
  2.         $boucle = &$boucles[$idb];
  3. }

Un critère arrive avec trois arguments :

  • $idb est le nom de la boucle
  • &$boucles est l’arbre de construction de toutes les boucles du squelette en question. $boucle, calculé ensuite, est celui de la boucle que le critère va modifier directement. Le & est important, il signifie en PHP que la variable est passée « par référence », autrement dit que toute modification de cette variable à l’intérieur de la fonction du critère affecte la variable à l’extérieur de l’appel. On peut aussi dire que le & permet de ne pas avoir une copie du contenu de la variable demandée, mais le contenu lui-même.
  • $crit est l’arbre de construction du critère, il permet de savoir ce que contient le critère en question (nom, opérateur, négation, arguments...)

Effectuer une action

Nous allons voir comment ajouter un critère de sélection dans la boucle grâce à ce critère. Nous allons ajouter un élément dans le tableau $boucle->where.

Notons déjà, que tous les éléments dans ce tableau where sont enchaînés par des opérateurs AND. Cependant, et c’est ce que nous verrons plus loin, un élément de ce tableau peut contenir des sous-éléments, et pour ceux-là, nous pouvons décrire précisément le type de liaison qui les affecte parmi une panoplie d’opérateurs à disposition (AND, OR, NOT, LIKE, REGEXP, >, <, =, >=, <= et je dois en oublier)

Commençons simplement. D’une part, le $table calculé contient le nom de la table SQL concernant notre boucle. Le tableau $c contient trois éléments : Opérateur, Valeur1, Valeur2. Cela sera traduit ensuite par « Valeur1 Operateur Valeur2 » soit ici : « titre = ’’ ». En fonction des opérateurs, il n’y a pas obligatoirement trois éléments dans le tableau ; ainsi NOT ne compare qu’à une valeur. À la fin, le tableau $c est ajouté à where.

  1. function critere_va_chercher_dist($idb, &$boucles, $crit) {
  2.         $boucle = &$boucles[$idb];
  3.         $table = $boucle->id_table;
  4.         $c = array("'='", "'$table.titre'", "''");
  5.         $boucle->where[] = $c;
  6. }

Comme vous le voyez, le contenu du tableau $c possède une drôle d’écriture à base de doubles guillemets tel que "'='". Il faut comprendre, qu’on est à un niveau d’abstraction un peu au dessus de celui des squelettes. On fait écrire, dans le critère, le code PHP que SPIP produira pour calculer la boucle.

On comprendra donc que ces deux lignes ne donnent pas le même résultat

  1. $c = array("'='", "'$table.titre'", "sql_quote('toto')");
  2. $c = array("'='", "'$table.titre'", "'sql_quote(\'toto\')'");

Cela écrira en PHP à peu près :

  1. 'spip_articles.titre' .  '=' .  sql_quote('toto')
  2. 'spip_articles.titre' . '=' . 'sql_quote(\'toto\')'

Puis à l’execution, la rèquete SQL :

  1. spip_articles.titre='toto'
  2. spip_articles.titre=sql_quote('toto')

La deuxième ligne créerait une erreur MySQL puisque sql_quote('toto') est une fonction PHP pour SPIP et non une fonction d’un gestionnaire de requête SQL.

Cependant la seconde écriture peut être souhaitée si on veut utiliser une fonction SQL, tel que "MIN" ou "MAX", ou je ne sais quoi... Il faut donc bien comprendre ce qui se passe et ce que l’on souhaite obtenir :)

Ajouter la négation

La négation, c’est la présence dans le critère de NOT, représenté par le point d’exclamation (!) comme dans : {!va_chercher toto}.

Prendre en compte la négation consiste —en général [2]— à demander l’inverse du résultat attendu, c’est à dire à encapsuler tout notre tableau $c dans un NOT avant de le donner à manger au where. Pour savoir si notre critère a une négation, on interroge $crit->not.

  1. function critere_va_chercher_dist($idb, &$boucles, $crit) {
  2.         $boucle = &$boucles[$idb];
  3.         $table = $boucle->id_table;
  4.         $c = array("'='", "'$table.titre'", "''");
  5.         // Inversion de la condition ?
  6.         if ($crit->not) {
  7.                 $c = array("'NOT'", $c);
  8.         }
  9.         $boucle->where[] = $c;
  10. }

Comme vous le voyez, $c, lorsqu’il y a une condition NOT devient un tableau d’une profondeur plus importante. C’est grâce à ce principe que nous pourrons faire un OU logique plus loin.

Récupérer un paramètre de critère

Nous allons rechercher le paramètre ’toto’ ou ’#TITRE’ passé à notre critère via {va_chercher toto} ou {va_chercher #TITRE}. Pour cela, nous allons tester la présence de $crit->param[ n ] ou le nombre indique la présence du paramètre n (en comptant de 0), et utiliser la fonction adaptée calculer_liste.

S’il n’y a pas de paramètre 0, nous pourrions mettre une valeur par défaut, mais nous dirons ici que c’est une erreur de squelettes pour forcer à avoir ce paramètre dans le critère. On aurait pu, aussi, en absence de paramètre récupérer automatiquement un paramètre de l’environnement ou le #TITRE de la boucle parente, mais cela n’entre pas dans l’objet de ce tutoriel. Sachez simplement que c’est possible, tout comme réaliser des jointures ou faire des calculs complexes. Vous pouvez en exemple regarder les critères de certains plugins (agenda, organiseur, tradsync, ... ) et de SPIP (ecrire/public/criteres.php)

  1. function critere_va_chercher_dist($idb, &$boucles, $crit) {
  2.         $boucle = &$boucles[$idb];
  3.         $table = $boucle->id_table;
  4.         // chercher quoi ?
  5.         if (isset($crit->param[0])) {
  6.                 $quoi = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
  7.         } else {
  8.                 # $quoi = "''";
  9.                 // rendons obligatoire ce parametre
  10.                 return (array('zbug_critere_necessite_parametre', array('critere' => $crit->op )));
  11.         }
  12.         $c = array("'='", "'$table.titre'", "$quoi");
  13.         // Inversion de la condition ?
  14.         if ($crit->not) {
  15.                 $c = array("'NOT'", $c);
  16.         }
  17.         $boucle->where[] = $c;
  18. }

Ajouter la condition OR

Le dernier élément, le plus simple finalement maintenant que tout est compris, est d’ajouter l’opérateur OR entre deux sélections. Nous l’obtenons avec :

  1.         $c = array("'OR'",
  2.                 array("'LIKE'", "'$table.titre'", "sql_quote('%' . $quoi . '%')"),
  3.                 array("'LIKE'", "'$table.texte'", "sql_quote('%' . $quoi . '%')")
  4.         );

Je n’en dis pas plus. Voici le code complet :

  1. // {va_chercher #TITRE}
  2. function critere_va_chercher_dist($idb, &$boucles, $crit) {
  3.         $boucle = &$boucles[$idb];
  4.         $table = $boucle->id_table;
  5.         $not = $crit->not;
  6.         // chercher quoi ?
  7.         if (isset($crit->param[0])) {
  8.                 $quoi = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
  9.         } else {
  10.                 // rendons obligatoire ce parametre
  11.                 return (array('zbug_critere_necessite_parametre', array('critere' => $crit->op )));
  12.         }
  13.         $c = array("'OR'",
  14.                 array("'LIKE'", "'$table.titre'", "sql_quote('%' . $quoi . '%')"),
  15.                 array("'LIKE'", "'$table.texte'", "sql_quote('%' . $quoi . '%')")
  16.         );
  17.         // Inversion de la condition ?
  18.         if ($crit->not) {
  19.                 $c = array("'NOT'", $c);
  20.         }
  21.        
  22.         $boucle->where[] = $c;
  23. }

Notes

[1hormis une sorte de contournement sur plusieurs boucles avec le critère {doublons}

[2Ce n’est pas systématiquement vrai, notamment pour des critères complexes

Retour en haut de la page

Vos commentaires

Répondre à cet article

Qui êtes-vous ?

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 Les choses à faire avant de poser une question (Prolégomènes aux rapports de bugs. )
Ajouter un document

Retour en haut de la page

Ça discute par ici

  • Introduction à la création d’un livre

    17 janvier – <blink style='color:red;'>public|spip|ecrire:commentaires</blink>

    Pour produire un livre avec SPIP, on peut produire un PDF. Une des solutions est d’utiliser LaTeX. C’est celle que nous avons choisie. SPIP et LaTeX SPIP permet de produire n’importe quel fichier de type text. En général, il produit des fichiers (...)

  • Escal-V3

    16 février – <blink style='color:red;'>public|spip|ecrire:commentaires</blink>

    Un jeu de squelettes proposant un affichage en 2 ou 3 colonnes avec un large choix de noisettes à insérer ou pas, fortement paramétrable depuis l’espace privé . A l’instar de sa petite soeur plugin Escal-V2 dont elle reprend toutes les (...)

  • SPIP 1.9.2n, 2.0.17, 2.1.12 disponibles

    17 novembre 2011 – 10 <blink style='color:red;'>public|spip|ecrire:commentaires</blink>

    Bonjour, Plusieurs failles de sécurité ont été repérées (Merci à High-Tech Bridge SA Security Research Lab, Davy et Arnault) dans les versions 1.9, 2.0 et 2.1 de SPIP. Nous rappelons à toutes et tous que le meilleur moyen pour signaler des failles, ou (...)

  • Table des Matières

    29 juillet 2007 – 50 <blink style='color:red;'>public|spip|ecrire:commentaires</blink>

    Ajoute des ancres en fonction des intertitres et fournit une balise pour afficher la « table des matières » d’un article - autrement dit un « sommaire » -.

  • Navigation AJAX

    31 janvier – 30 <blink style='color:red;'>public|spip|ecrire:commentaires</blink>

    Ce plugin permet de modifier automatiquement une parties des liens internes de manière à ce qu’ils ne déclenchent pas un chargement complet de la page cible, mais un chargement en AJAX de certains éléments spécifiés à l’avance. Il permet aussi de (...)