SPIP-Contrib

SPIP-Contrib

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

286 Plugins, 197 contribs sur SPIP-Zone, 204 visiteurs en ce moment

Accueil > Squelettes > Tutoriels 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 – commentaires

19 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. }

Télécharger

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.  
  5. $c = array("'='", "'$table.titre'", "''");
  6.  
  7. $boucle->where[] = $c;
  8. }

Télécharger

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\')'");

Télécharger

Cela écrira en PHP à peu près :

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

Télécharger

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

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

Télécharger

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.  
  5. $c = array("'='", "'$table.titre'", "''");
  6.  
  7. // Inversion de la condition ?
  8. if ($crit->not) {
  9. $c = array("'NOT'", $c);
  10. }
  11.  
  12. $boucle->where[] = $c;
  13. }

Télécharger

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.  
  5. // chercher quoi ?
  6. if (isset($crit->param[0])) {
  7. $quoi = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
  8. } else {
  9. # $quoi = "''";
  10. // rendons obligatoire ce parametre
  11. return (array('zbug_critere_necessite_parametre', array('critere' => $crit->op )));
  12. }
  13.  
  14. $c = array("'='", "'$table.titre'", "$quoi");
  15.  
  16. // Inversion de la condition ?
  17. if ($crit->not) {
  18. $c = array("'NOT'", $c);
  19. }
  20.  
  21. $boucle->where[] = $c;
  22. }

Télécharger

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. );

Télécharger

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.  
  7. // chercher quoi ?
  8. if (isset($crit->param[0])) {
  9. $quoi = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
  10. } else {
  11. // rendons obligatoire ce parametre
  12. return (array('zbug_critere_necessite_parametre', array('critere' => $crit->op )));
  13. }
  14.  
  15. $c = array("'OR'",
  16. array("'LIKE'", "'$table.titre'", "sql_quote('%' . $quoi . '%')"),
  17. array("'LIKE'", "'$table.texte'", "sql_quote('%' . $quoi . '%')")
  18. );
  19.  
  20. // Inversion de la condition ?
  21. if ($crit->not) {
  22. $c = array("'NOT'", $c);
  23. }
  24.  
  25. $boucle->where[] = $c;
  26. }

Télécharger

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

Dernière modification de cette page le 16 janvier 2012

Retour en haut de la page

Vos commentaires

  • Le 9 juillet 2015 à 19:27, par pa.georges En réponse à : Boucles avec des conditions en OR (et explication des critères)

    Bonjour,

    en prenant exemple sur cet excellent tutoriel, je me suis fabriqué un critère

    {membres ...}

    Destiné à être exclusivement utilisé sur les tables d’une base de données externe, ce critère prend obligatoirement ou bien le paramètre ’actuels’ ou bien ’anciens’, i.e. les deux seules syntaxes autorisées sont :

    {membres actuels}

    ou bien

    {membres anciens}

    Dans mon code j’ai un switch($quoi) qui me génère une requête SQL (très) différente suivant le paramètre donné en entrée ($quoi). Précisons ici que c’est une requête SQL qui ne contient pas les strings ’actuels’ et ’anciens’, parce que je veux conserver un certain niveau d’abstraction entre SPIP et ma base de données externes.

    A première vue, ça fonctionne bien, mais maintenant si j’essaye de faire

    {membres #GET{type_membre}}

    je me prends une erreur, car dans la variable $quoi, au lieu d’avoir la chaîne ’actuels’, comme je m’y attendrais, j’ai à la place cette ligne de code PHP :

    1. table_valeur($Pile["vars"], (string)'statut', null)

    Or, le problème, c’est que je n’arrive pas à exécuter cette ligne de code PHP pour obtenir le contenu de ce #GET... J’ai bien essayé de faire

    1. $quoi=eval("return ".$quoi.";");

    mais ça ne fonctionne pas car apparemment $Pile n’est pas défini dans le contexte d’exécution de ma fonction critere_membres_dist()... Alors comment faire ? C’est grave docteur ?

    Répondre à ce message

  • Le 5 janvier 2013 à 18:58, par Natacha Courcelles En réponse à : Boucles avec des conditions en OR (et explication des critères)

    Génial ! merci
    cette fonction m’a sauvé

    je l’ai adapté pour avoir plus de 2 champs
    voici ma modif

    $c =array(« ’OR’ »,
    array(« ’OR’ »,
    array(« ’LIKE’ », « ’$table.champ1’ », « sql_quote(’%’ . $quoi . ’%’) »),
    array(« ’LIKE’ », « ’$table.champ2’ », « sql_quote(’%’ . $quoi . ’%’) »)
    ),
    array(« ’OR’ »,
    array(« ’LIKE’ », « ’$table.champ3’ », « sql_quote(’%’ . $quoi . ’%’) »),
    array(« ’LIKE’ », « ’$table.champ4’ », « sql_quote(’%’ . $quoi . ’%’) »)
    )
    ) ;

    si ça peut aider
    bien cordialement

    Répondre à ce message

  • Le 11 mai 2012 à 08:03, par xdjuj En réponse à : Boucles avec des conditions en OR (et explication des critères)

    Encore une fois parfaitement brillant. Juste à la portée de tous. Dit comme ça les choses sont tellement plus simples ! Bravo et merci :)

    Répondre à ce message

  • Le 6 février 2012 à 12:25, par Nicolas Hoizey En réponse à : Boucles avec des conditions en OR (et explication des critères)

    Excellent tutoriel, merci !

    Répondre à ce message

Répondre à cet article

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

  • Acces Restreint 3.0

    11 décembre 2008 – 784 commentaires

    Le plugin accès restreint permet de définir et de gérer des zones de l’espace public en accès restreint. Cette version du plugin a été redévelopée et optimisée tout spécialement pour SPIP 2.0. Il en découle une amélioration des performances sur les gros (...)

  • Champs Extras 3

    16 janvier 2012 – 538 commentaires

    Ce plugin permet de créer et/ou de gérer des champs supplémentaires dans les objets éditoriaux de SPIP. Il permet donc de prendre en compte et d’afficher de nouveaux éléments dans n’importe quel objet éditorial de SPIP. Screencast Vous n’aimez pas (...)

  • Réservation d’événements

    16 mars 2015 – 190 commentaires

    Ce plugin permet d’offrir aux visiteurs de s’inscrire pour un évènement du plugin Agenda et de gérer les réservations enregistrées. Installation Le plugin s’installe comme n’importe quel plugin. il nécessite : Agenda API de vérification (...)

  • Les crayons

    23 avril 2008 – 815 commentaires

    Ce plugin permet d’éditer les contenus sur les pages publiques du site, sans passer par l’espace privé de SPIP.

  • LESS pour SPIP : Less-CSS (anciennement LESSpip)

    5 novembre 2010 – 43 commentaires

    Less-CSS (Anciennement LESSpip) est un plugin intégrant facilement le logiciel LESS dans SPIP. LESS est une extension de CSS ajoutant les variables, les classes, les opérations, les imbrications au langage. Facilitant ainsi l’écriture de (...)

Ça spipe par là