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’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 :
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.
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é.
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".
É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 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 :
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.
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 fonctionnement est le suivant {id_mot= #ENV{id1,#ENV{id2,#ENV{id3}}}}
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.
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 là, 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>
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 !
;-)
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...
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 :
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>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 !
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 :-(
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.
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
"Aucun mot clé (et il ne trouvera rien, le nigot)"
En toute logique, il devrait plutôt trouver tout non ?
:-)
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>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 ?
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.
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)
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
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 ^^
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à
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 !!!
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.