cent20.net
Se connecter
cent20.net
 

SPIP Pour le plaisir de la recherche

Réalisation une boucle SPIP recherchant les articles correspondant à trois mots clés, et généralisation de cette boucle à une recherche sur 10 mots clés.

Après Filtres de test - Qui a dit impossible ? et Arriverez-vous à dénouer les boucles ?, je vous propose un nouveau petit jeu, tout aussi divertissant.

 ;-P

Pré-requis :

L’objectif

L’idée c’est de réaliser une boucle en SPIP, qui soit en mesure de sélectionner tous les articles correspondant à trois mots clés, et ce sans tricher (l’utilisation de php, et de bidouilles bricolée sur un coin de table est donc strictement proscrite !).

Le visiteur dispose de trois menus déroulant, qui lui proposent des mots clés, il peut choisir :

  • Aucun mot clé (et il ne trouvera rien, le nigot)
  • Un seul mot clé dans l’un des trois menus déroulants.
  • Deux mots clés.
  • Ou bien trois mots clés.

On ne sait pas à l’avance ce que va faire le visiteur, mais il va le faire, et il sera redirigé sur une page ou les choix des mots clés seront dans l’url, par exemple sous la forme id1=27&id2=35&id3=45.

Tests préliminaires

Bien entendu, une boucle statique correctement renseignée donnera le résultat attendu.

Sachant que l’on peut récupérer les variables de l’url par la balise #ENV, on peut donc faire :

Oui mais voila, cette boucle est certes très belle et assez simple, mais elle ne fonctionne parfaitement que si le visiteur à choisit les trois mots clés.

Si il ne choisit qu’un seul mot clé, alors la boucle sera vide, même si il existe des articles correspondant à ce mot clé.

Et avec les expressions régulières ?

Il est possible d’introduire des expressions régulières dans les critères des boucles, ainsi {id_mot==^[aA]} sélectionnerait tous les articles qui ont un mot clé commençant par « a » ou « A ».

Avec ces expressions régulières, il est possible de coder très facilement le critère « OU », ainsi pour coder une boucle qui chercherait les articles ayant l’un des mots clé 27,35,45 il suffirait de faire :

Il s’agit là d’un boucle bien statique, et #ENV{id1}|#ENV{id2}|#ENV{id3} risque de ne pas marcher si l’une des variables est vide, car deux symbole "|" cote à cote, je doute que la requête sql apprécie.

De toute façon, cela ne répond en rien à notre problème, {id_mot== 27|35|45} réalise une requete sql « OU », nous cherchons à réaliser une requête "ET".

Début de solution

Étudions les pistes proposées sur la liste de développement du noyau de spip.

Les bases sont posés, des fonctionnalités et une petite limitation, maintenant il faut arriver à faire proprement une boucle, qui gère de 1 à 3 mots clés sélectionnés, et qui renvoie les titres des articles ayant tous les mots sélectionnés.

Solution à base d’INCLURE

Solution proposée par cy_altern sur le channel IRC de SPIP :

Puis il suffit de faire 4 pages html avec 1,2,3 mots clés que l’on appellera page_recherche_1.html, page_recherche_2.html et page_recherche_3.html et page_recherche_0.html.

Sachant qu’il va falloir :

  • Passer les bonnes variables à cet inclure.
  • Les récupérer pour faire la boucle.

Et pour savoir quelles variables à appeler, on peut utiliser un système qui fait :

Car ainsi, on sait quels sont les #ENVid qui ne sont pas vides, les sommes sont obligatoirement différentes : 1,3,5,6,7 les sommes obligatoirement différentes, mais cette méthode multiplie les fichiers html.

Solution à base d’une boucle unique et de tests

Voici une autre solution qui fonctionne :

Cette solution est directement inspirée de la piste proposée ici.

On a à faire à une belle permutation circulaire, et cette unique boucle gère les trois cas :

  • Le visiteurs ne choisit aucun mot clé, on ne lui donne aucun article (il n’avait qu’à y mettre du sien aussi !)
  • Le visiteurs ne choisit un, deux ou trois mot clés, et on lui communique uniquement les titres des articles ayant tous les mots clés.

Le fonctionnement est le suivant {id_mot= #ENV{id1,#ENV{id2,#ENV{id3}}}}

  • SI l’id1 existe, alors on cherche id_mot=id1
  • SINON, on regarde si id2 existe.
    • SI id2 existe, alors on cherche id_mot=id2
    • SINON, on regarde si id3 existe.
      • SI id3 existe, alors on cherche id_mot=id3
      • SINON, on cherche id_mot=, autrement dit on ne cherche rien, car l’utilisateur n’a choisit aucun mot clés.

Si cette boucle est acceptable pour trois mots clés, elle risque de devenir un peu plus indigeste pour dix mots clefs, on aurait alors dix fois un critère de recherche comparable à celui ci :

quand je dis 10 fois le même, il faut comprendre à une permutation circulaire près.

A vous de jouer !

Il ne vous reste plus qu’à trouver une superbe boucle, gérant une recherche sur une dizaine de mot clés, qui soit plus optimisée que celle qui est suggéré ci-dessus.

L’utilisation du php en dur dans les fichiers est à exclure, maintenant un petit filtre natif de SPIP ne sera pas considéré comme de la triche, un filtre perso ne sera lui accepté que si vraiment, il n’est pas possible de faire autrement.

Inutile d’aller pomper ici ou , ce ne sont que des bidouilles !

Je rappel aux débutant téméraires qui sont arrivés jusqu’à la fin de l’article, que outre le fait qu’ils sont un peu cinglé de lire mes délires, ils doivent impérativement utiliser les balises "cadre" pour encadrer leur code.

<cadre>
Code html, spip entre des balises "cadre" ...
</cadre>

 
Vincent ROBERT
Le 9 mars 2007

cy_altern me fais remarquer, et à juste titre, qu’une bidouille consisterait à créer un mot clé qui n’est attribué à aucun article, et si le numéro de ce mot clé est le n°666, alors le code suivant fonctionnerait :

Version 3 mot clés :

Version 10 mot clés :

Mais on a dit SANS bidouilles, c’est dommage hein !

 ;-)

 
Nicolas Hoizey
Le 9 mars 2007

Dans l’exemple final à trois mots clefs, il y a

id_mot=#ENVid3,#ENVid1,#ENVid3

Ce devrait à priori être ça

id_mot=#ENVid3,#ENVid1,#ENVid2

Sinon, Robert, ta proposition ne peut pas marcher s’il y a moins de trois mots clefs, puisqu’on aura alors au moins un id_mot=666, qui empêchera la sélection de tout article...

 
Vincent ROBERT
Le 9 mars 2007

En effet, il y a deux erreurs, je corrige la première dans l’article et la bidouille devient alors :

cy_altern me fais remarquer, et à juste titre, qu’une bidouille consisterait à créer un mot clé qui est attribué à tous les articles, et si le numéro de ce mot clé est le n°666, alors le code suivant fonctionnerait :

 
paolo
Le 9 mars 2007

Ceci semble marcher chez moi :


<!-- url = ... mot1=xx&mot2=yy&mot3=zz -->

#SET{mots_choisis, #ARRAY{0,0}}
[(#ENV{mot1}|?{#SET{mots_choisis,#GET{mots_choisis}|array_merge{#ARRAY{1,#ENV{mot1}}}},''})]
[(#ENV{mot2}|?{#SET{mots_choisis,#GET{mots_choisis}|array_merge{#ARRAY{2,#ENV{mot2}}}},''})]
[(#ENV{mot3}|?{#SET{mots_choisis,#GET{mots_choisis}|array_merge{#ARRAY{3,#ENV{mot3}}}},''})]

<BOUCLE_test(ARTICLES){id_mot IN #GET{mots_choisis}}>
#ID_ARTICLE  #TITRE <br>
</BOUCLE_test>
 
Joseph LARMARANGE
Le 14 mars 2007

Y a pas à dire, le passage par un tableau donne une solution plutot élégante.

 
OFondCBien
Le 28 mars 2007

Bonjour,

J’ai testé la proposition de paolo, mais il me semble que l’on n’obtienne pas un ET logique, mais un OU !

... snif, c’était si beau !

mais en tout cas bravo les gars !

 
paolo
Le 4 avril 2007

OFond a raison : ce n’est pas la même chose. Cela peut aussi être utile, mais je n’ai pas répondu (je me rends compte) à la question posée :-(

 
Vincent ROBERT
Le 4 avril 2007

Cedric à lui aussi fait la même proposition que toi sur la liste USER, mais ceci dit la version OU est aussi très intéressante, je prépare un article sur le sujet.

 
juliee
Le 4 mai 2007

au fait on peut faire ca aussi pour le ou !!

<BOUCLE_articles(ARTICLES){id_mot IN #ENV{id1},#ENV{id2},#ENV{id3},id_mot =#ENV{id4}}>
</BOUCLE_articles>

et c une solution qui marche très bien

 
PB
Le 12 mai 2007

"Aucun mot clé (et il ne trouvera rien, le nigot)"

En toute logique, il devrait plutôt trouver tout non ?

 :-)

 
Hocus
Le 17 juin 2007

Salut,

Peut etre une solution..
En deux passes : Une pour trouver les articles, une pour les afficher

#SET{mots_choisis, #ARRAY{0,0}}
[(#ENV{mot1}|?{#SET{mots_choisis,#GET{mots_choisis}|array_merge{#ARRAY{1,#ENV{mot1}}}},''})]
[(#ENV{mot2}|?{#SET{mots_choisis,#GET{mots_choisis}|array_merge{#ARRAY{2,#ENV{mot2}}}},''})]
[(#ENV{mot3}|?{#SET{mots_choisis,#GET{mots_choisis}|array_merge{#ARRAY{3,#ENV{mot3}}}},''})]

#SET{articles_cherches,#ARRAY{0,0}}
#SET{intersect,0}
<BOUCLE_test(MOTS){id_mot IN #GET{mots_choisis}}>
#SET{articles_mots,#ARRAY{0,0}}
#SET{taille_articles_mots,0}
       
<BOUCLE_resultats_mots(ARTICLES){id_mot} >
#SET{articles_mots,#GET{articles_mots}|array_merge{#ARRAY{#COMPTEUR_BOUCLE,#ID_ARTICLE}}}
</BOUCLE_resultats_mots>                        #SET{taille_articles_mots,#TOTAL_BOUCLE}
</B_resultats_mots>

[(#GET{taille_articles_mots}|>{0}|?{
        [(#GET{intersect}|>{0}|?{
#SET{articles_cherches,#GET{articles_cherches}|array_intersect{#GET{articles_mots}}},
#SET{articles_cherches,#GET{articles_cherches}|array_merge{#GET{articles_mots}}}
        })],
''})]
[(#GET{taille_articles_mots}|>{0}|?{[(#GET{intersect}|=={0}|?{#SET{intersect,1},''})],''})]
</BOUCLE_test>

<BOUCLE_resultats_recherche(ARTICLES){id_articles IN #GET{articles_cherches}}>
#ID_ARTICLE  #TITRE <br>
</BOUCLE_resultats_recherche>
 
Beurt
Le 4 mai 2008

Monnaie ancienne me donne un lien vers ici à une question que je pose sur spip.user : http://thread.gmane.org/gmane.comp....

Mon problème est du même type :

j’ai un tableau Spip (#SET{ma_liste_de_mots,#ARRAY{bla,bla,etc}}) qui contient une liste de mots-clés (id des mots). Ça pourrait tout à fait être un tableau de 3 id_mots (ou moins ou plus) comme dans le problème posé ici.

Je voudrais retrouver tous les articles qui ont tout ces mots-clés.

J’ai une solution que je trouve encore trop moche et qui peut fonctionner pour répondre au problème posé ici. Elle utilise des piles avec doublons nommées grâce à au #COMPTEUR_BOUCLE... J’ai essayé de commenter le code :

Qu’en pensez-vous ? Avez vous mieux ?

 
débutante
Le 3 octobre 2008

Voilà justement ce que j’essaie de faire sur mon site en spip (et je suis débutante...)

- 3 menus déroulants correspondants à 3 groupes de mots clés.
Le visiteur doit choisir une sélection de 3 mots

- et la page de résultats doit afficher les articles correspondants au 3 mots clefs sélectionnés... (qui ont tout ces mots-clés !)

Vos boucles ne m’ont pas vraiment (malheureusement !) aidé (quoique ça fait réfléchir...) donc je continue à creuser pour trouver une solution un peu plus concrète.

Si vous avez d’autres pistes... (je peux vous envoyer ma page pour plus de clarté si besoin).

Merci de votre aide.

 
Maïeul
Le 29 juin 2009

J’ai eu aujourd’hui le même besoin. A ceci près que on ne pouvait sélectionner deux mots clef du même groupes, et que le nombre de groupe est potentiellement illimité.

Je m’en suis tiré selon la méthode suivante :
- je fait une boucle avec le mot clef passés en paramètres.
- pour chaque mot clefs, je fait une boucle ARTICLE dedans. Je stocke les données dans un tableau ARRAY.
- après chaque boucle article, je crée un tableau qui correspond à l’intersection de sa précédente valeur et du tableau crée auparavent.

En SPIP, cela donne (il y a pas mal de fouritue autour, de plus les id_mot était passés comme valeurs d’un tableau associatifs dont les clef sonts les groupes)

 
Maïeul
Le 29 juin 2009

il y avait une erreur dans mon code ... cela gérait mal les cas où il n’y avait pas de mot sélèctionnés.

ceci devrait être mieux

 
Vincent ROBERT
Le 30 juin 2009

Maïeul :

il y avait une erreur dans mon code ... cela gérait mal les cas où il n’y avait pas de mot sélèctionnés.

Ton code final, il fait le ET logique ? ou le OU logique ?

array_intersect > Ceci à l’air exceptionnel ...

Je vais tester tout ça moi ^^

 
Maïeul
Le 30 juin 2009

il fait un ET logique

j’ai encore modifié un peu (pour des histoire de html)

le code à jour est dans le squelette "collection" sur la zone (repertoire formulaire).

Fil vient aussi de me parler d’un plugin qu’il fait en cour de dev, pour avoit un critère mot.

C’est par là

 
filnug
Le 18 janvier 2010

Bonjour,

J’ai lu attentivement cet article qui pourrait m’aiguiller dans un problème posé. La différence est que dans mon cas, je souhaite avoir 2 listes de mot-clés. Une liste "fruits" et une 2eme "couleurs".
Jusque là, j’ai tout simplement mis 2 boucles dans une page rubrique. La sélection d’un mot-clé sur l’une des listes (ex : banane) renvoie à la page mot.html. Mon objectif est de pouvoir sélectionner un nouveau mot-clé (ex. jaune), afin que la page mot.html affiche tous les articles ayant les mots-clés banane et jaune.
Le cas se complique lorsque la page mot.html doit afficher tous les articles contenu dans le groupe "fruits" et avec le mot-clé "jaune".
J’ose imaginer que ce site n’est pas fait pour poser des questions, mais peut-être pourriez-vous me conseiller svp !!!

Merci !!!

 
filnug
Le 18 janvier 2010

rastapopoulos vient de me diriger vers ce lien (il s’agit d’un plugin) http://www.spip-contrib.net/Critere... sur le canal irc.

Je vais déjà y jeter un coup d’oeil ! Peut-être que ce lien pourra être utile à des personnes qui viendront faire un tour sur ce site.

 
btm22013
Le 21 avril 2010

Bonjour,
tout d’abord mille merci pour ces astuces qui m’ont énormément servis.
J’ai utlisé la technique "Solution à base d’une boucle unique et de tests" mais ce que je souhaite réaliser (mais que je n’arrive pas), c’est si l’utilisateur n’entre aucun mots clés dans la recherche, j’affiche un message, par exemple : "Veuillez sélectionner au moins un critère "

Merci d’avance




Forum sur abonnement

Pour participer à ce forum, vous devez vous enregistrer au préalable. Merci d'indiquer ci-dessous l'identifiant personnel qui vous a été fourni. Si vous n'êtes pas enregistré, vous devez vous inscrire.

[Connexion] [s'inscrire] [mot de passe oublié ?]

SPIP 2.1.0 [15608] | BliP 3.0.6   | XHTML 1.0 | CSS 2.1 | RSS 2.0 | Plan du site
501 visiteurs hier, 1188633 depuis mars 2005