source: spip-zone/_plugins_/indexer/trunk/iterateur/sphinx.php @ 82786

Last change on this file since 82786 was 82786, checked in by fil@…, 7 years ago

une fonction qui aide a retrouver la forme d'un mot à partir de sa racine ; application à l'affichage des mots-clés donnant zéro résultat (exemple : http://seenthis.net/recherche?recherche=chekoslavika%20voitures%20cheveaux&follow=all )

File size: 22.6 KB
Line 
1<?php
2
3if (!defined('_ECRIRE_INC_VERSION')) return;
4
5/**
6 * Gestion de l'itérateur SPHINX
7 *
8 * @package SPIP\Indexer\Iterateur\Sphinx
9**/
10
11
12/**
13 * Créer une boucle sur un itérateur SPHINX
14 *
15 * Annonce au compilateur les "champs" disponibles,
16 *
17 * @param Boucle $b
18 *     Description de la boucle
19 * @return Boucle
20 *     Description de la boucle complétée des champs
21 */
22function iterateur_SPHINX_dist($b) {
23        $b->iterateur = 'SPHINX'; # designe la classe d'iterateur
24        $b->show = array(
25                'field' => array(
26                        '*' => 'ALL' // Champ joker *
27                )
28        );
29        return $b;
30}
31
32
33/**
34 * Iterateur SPHINX pour itérer sur des données
35 *
36 * La boucle SPHINX n'a toujours qu'un seul élément.
37 */
38class IterateurSPHINX implements Iterator {
39
40        /**
41         * Type de l'iterateur
42         * @var string
43         */
44        protected $type = 'SPHINX';
45
46        /**
47         * Commandes transmises à l'iterateur
48         * @var array
49         */
50        protected $command = array();
51
52        /**
53         * Infos de debug transmises à l'iterateur
54         * @var array
55         */
56        protected $info = array();
57
58        /**
59         * Instance de SphinxQL
60         * @var \Sphinx\SphinxQL\SphinxQL
61         */
62        protected $sphinxQL = null;
63
64        /**
65         * Instance de SphinxQL\QueryApi
66         * @var \Sphinx\SphinxQL\QueryAPi
67         */
68        protected $queryApi = null;
69
70        /**
71         * Résultats par la requête à Sphinx
72         * @var array
73         */
74        protected $result = array();
75
76        /**
77         * Cle courante
78         * @var null
79         */
80        protected $cle = null;
81
82        /**
83         * facettes
84         * @var array
85         */
86        protected $facet = array();
87
88        /**
89         * index(es) scannés
90         * @var array
91         */
92        protected $index = array();
93
94        /**
95         * Valeur courante
96         * @var null
97         */
98        protected $valeur = null;
99
100        /**
101         * Constructeur
102         *
103         * @param  $command
104         * @param array $info
105         */
106        public function __construct($command, $info=array()) {
107
108                $this->command = $command + array(
109                        'index'     => array(),
110                        'selection' => array(),
111                        'recherche' => array(),
112                        'orderby'   => array(),
113                        'group'     => array(),
114                        'snippet'   => array(),
115                        'facet'     => array(),
116                        'filter'    => array(),
117                );
118
119
120                $this->info = $info;
121
122                include_spip('inc/indexer');
123
124                $this->sphinxQL  = new \Sphinx\SphinxQL\SphinxQL(SPHINX_SERVER_HOST, SPHINX_SERVER_PORT);
125                $this->queryApi  = new \Sphinx\SphinxQL\QueryApi();
126
127                $this->setIndex($this->command['index']);
128                $this->setSelection($this->command['selection']);
129                $this->setMatch($this->command['recherche']);
130                $this->setOrderBy($this->command['orderby']);
131                $this->setGroupBy($this->command['group']); // groupby interfère avec spip :/
132                $this->setFacet($this->command['facet']);
133
134                $this->setFilter($this->command['filter']);
135
136                $this->setSnippet($this->command);
137
138
139                $this->setPagination($this->command['pagination']);
140
141                $this->runQuery();
142
143        }
144
145
146        /**
147         * Sauvegarde des données pour utilisation ultérieure
148         * dans les squelettes via les balises `#SPHINX_xx`
149         * où xx est la clé sauvegardée.
150         *
151         * @param string $cle
152         * @param mixed $val
153         * @return void
154        **/
155        private function save($cle, $val) {
156                if (!isset($GLOBALS['SphinxSave'])) {
157                        $GLOBALS['SphinxSave'] = array();
158                }
159                // identifiant de la boucle
160                $id = $this->command['id'];
161                if (!isset($GLOBALS['SphinxSave'][$id])) {
162                        $GLOBALS['SphinxSave'][$id] = array();
163                }
164                $GLOBALS['SphinxSave'][$id][$cle] = $val;
165        }
166
167        /**
168         * Sauvegarde toutes les données pour utilisation ultérieure
169         *
170         * @param array $data
171         * @return void
172         */
173        private function saveAll($data) {
174                foreach ($data as $cle => $val) {
175                        $this->save($cle, $val);
176                }
177        }
178
179        /*
180         * Récupérer la forme exacte du mot à partir de
181         * la version indexée ; utilise snippet(query, racine)
182         */
183        public function keyword2word($keyword, $q) {
184                $u = $this->sphinxQL->allfetsel(
185                "SELECT SNIPPET("._q($q).","._q($keyword).") AS m "
186                . "FROM ". join(',', $this->index) ." LIMIT 1"
187                );
188                if (!$mot = supprimer_tags(extraire_balise($u['query']['docs'][0]['m'], 'b')))
189                        $mot = $keyword;
190                return $mot;
191        }
192
193        /**
194         * Exécute la requête
195         *
196         * Exécute la requête, sauvegarde des données, retravaille
197         * les résultats pour que la pagination fonctionne.
198         *
199         * @param
200         * @return
201        **/
202        public function runQuery() {
203                $q = $this->queryApi->getMatch();
204               
205                // on sait deja que cette requete necessite une correction ?
206                if (isset($GLOBALS['sphinxReplace'][$q])) {
207                        $this->queryApi->match($GLOBALS['sphinxReplace'][$q]);
208                        $this->save('message', $GLOBALS['sphinxReplaceMessage'][$q]);
209                }
210
211                $query  = $this->queryApi->get();
212                $this->save('query', $query);
213
214                $result = $this->sphinxQL->allfetsel($query);
215
216                // erreur de syntaxe ? correction de la requete
217                if (isset($result['query']['meta']['error'])) {
218                        $q = $this->queryApi->getMatch();
219                        $GLOBALS['sphinxReplace'][$q] = trim(preg_replace('/\W+/u', ' ', $q));
220                        $this->queryApi->match($GLOBALS['sphinxReplace'][$q]);
221                        $query  = $this->queryApi->get();
222                        $result = $this->sphinxQL->allfetsel($query);
223                        $message = _L('transformation de la requête en « ').htmlspecialchars($GLOBALS['sphinxReplace'][$q])." »";
224                        $GLOBALS['sphinxReplaceMessage'][$q] = $message;
225                        $this->save('message', $message);
226                }
227
228                if (!$result) {
229                        return false;
230                }
231
232                // resultat vide et plusieurs mots dont certains ont 0 hit ?
233                if (is_array($result['query']['docs'])
234                AND count($result['query']['docs']) == 0
235                AND !preg_match('/["\/&|)(]/u', $q)
236                ) {
237                        $q2 = $msg = array();
238                        if (isset($result['query']['meta']['keywords'])){
239                                foreach($result['query']['meta']['keywords'] as $w) {
240                                        $mot = $this->keyword2word($w['keyword'], $q);
241                                        if($w['docs'] == 0) {
242                                                $msg[] = "<del>".htmlspecialchars($mot)."</del>";
243                                        } else {
244                                                $msg[] = htmlspecialchars($mot);
245                                                $q2[] = $mot;
246                                        }
247                                }
248                        }
249
250                        if (count($q2) >0
251                        AND count($q2) < count($result['query']['meta']['keywords'])) {
252                                $q2 = trim(join(' ',$q2));
253                                $GLOBALS['sphinxReplace'][$q] = trim(preg_replace('/\W+/u', ' ', $q2));
254                                $this->queryApi->match($GLOBALS['sphinxReplace'][$q]);
255                                $query  = $this->queryApi->get();
256                                $result = $this->sphinxQL->allfetsel($query);
257                                $GLOBALS['sphinxReplace'][$q] = $q2;
258                                $GLOBALS['sphinxReplaceMessage'][$q] = $message = _L('Résultats pour : ').join(' ',$msg);
259                                $this->save('message', $message);
260                        }
261                }
262
263
264                // decaler les docs en fonction de la pagination demandee
265                if (is_array($result['query']['docs'])
266                AND $pagination = $this->getPaginationLimit()) { 
267
268                        list($debut) = array_map('intval', $pagination); 
269
270                        $result['query']['docs'] = array_pad($result['query']['docs'], - count($result['query']['docs']) - $debut, null);
271                        $result['query']['docs'] = array_pad($result['query']['docs'], $result['query']['meta']['total'], null);
272                }
273
274                // remettre les alias sur les facettes :
275                // {facet truc, FORMULE()} cree la facette 'truc'
276                $facets = array();
277                foreach ($this->facet as $f) {
278                        $facets[$f['alias']] = array_shift($result['query']['facets']);
279                }
280                $result['query']['facets'] = $facets;
281
282
283                $this->result = $result['query'];
284                unset($result['query']['docs']);
285                $this->saveAll($result['query']);
286
287                return true;
288        }
289
290
291        public function quote($m) {
292                return $this->queryApi->quote($m);
293        }
294
295
296        /**
297         * Définir la liste des index interrogés (FROM de la requête)
298         *
299         * Par défaut on utilise l'index déclaré dans la conf
300         *
301         * @param array $index Liste des index
302         * @return bool True si au moins un index est ajouté, false sinon
303        **/
304        public function setIndex($index) {
305                if (!is_array($index)) $index = array($index);
306                $index = array_filter($index);
307                if (!$index) {
308                        $index[] = SPHINX_DEFAULT_INDEX;
309                }
310                foreach ($index as $i) {
311                        $this->queryApi->from($i);
312                }
313                $this->index = $index;
314                return true;
315        }
316
317
318
319        /**
320         * Définir la liste des champs récupérés (SELECT de la requête)
321         *
322         * Par défaut, en absence de précisions, on prend tous les champs
323         *
324         * @param array $select Liste des index
325         * @return bool True si au moins un index est ajouté, false sinon
326        **/
327        public function setSelection($select) {
328                if (!is_array($select)) $select = array($select);
329                $select = array_filter($select);
330                // si aucune selection demandée, on prend tout !
331                if (!$select) {
332                        $select[] = '*';
333                }
334                foreach ($select as $s) {
335                        $this->queryApi->select($s);
336                }
337                return true;
338        }
339
340
341
342        /**
343         * Définir la recherche fulltext
344         *
345         * @param array $index Liste des index
346         * @return bool True si au moins un index est ajouté, false sinon
347        **/
348        public function setMatch($match) {
349                if (!is_array($match)) $match = array($match);
350                $match = array_filter($match);
351                if (!$match) {
352                        return false;
353                }
354                $match = implode(' ',$match);
355                $this->queryApi
356                        ->select('WEIGHT() AS score')
357                        ->match( $match );
358                return true;
359        }
360
361
362        public function setOrderby($orderby) {
363                if (!is_array($orderby)) $orderby = array($orderby);
364                $orderby = array_filter($orderby);
365                if (!$orderby) {
366                        return false;
367                }
368                foreach ($orderby as $order) {
369                        // juste ASC ou DESC sans le champ… passer le chemin…
370                        if (in_array(trim($order), array('ASC', 'DESC'))) {
371                                continue;
372                        }
373                        if (!preg_match('/(ASC|DESC)$/i', $order)) {
374                                $order .= ' ASC';
375                        }
376                        $this->queryApi->orderby($order);
377                }
378                return true;
379        }
380
381        public function setGroupby($groupby) {
382                if (!is_array($groupby)) $groupby = array($groupby);
383                $groupby = array_filter($groupby);
384                if (!$groupby) {
385                        return false;
386                }
387                foreach ($groupby as $group) {
388                        $this->queryApi->groupby($group);
389                }
390                return true;
391        }
392
393
394        /**
395        * Affecte une limite à la requête Sphinx (et sauve ses bornes)
396        *
397        * @param int Début
398        * @param int Nombre de résultats
399        **/ 
400        public function setPaginationLimit($debut, $nombre) { 
401                $this->pagination_limit = array($debut, $nombre); 
402                $this->queryApi->limit("$debut,$nombre"); 
403        } 
404
405        /**
406        * Retourne les limites de pagination précédemment sauvées
407        *
408        * @param int Début
409        * @param int Nombre de résultats
410        **/ 
411        public function getPaginationLimit() { 
412                return $this->pagination_limit; 
413                # return explode(',', $this->queryApi->getLimit());
414        }
415
416        /**
417         * Définir la pagination
418         *
419         * @param array $pagination
420         * @return bool True si une pagination est demandee
421        **/
422        public function setPagination($pagination) {
423                # {pagination 20}
424                if (is_array($pagination) and $pagination) {
425                        $debut = intval($pagination[0]);
426                        $nombre = 20;
427                        if (isset($pagination[1])) {
428                                $nombre = intval($pagination[1]);
429                        }
430                        $this->setPaginationLimit($debut, $nombre); 
431                        return true;
432                }
433        }
434
435        /**
436         * Définir le snippet
437         */
438        public function setSnippet($command) {
439                $snippet = array_filter($command['snippet']);
440                // si aucune selection demandée, on prend tout !
441                if (!$snippet) {
442                        return $this->setSnippetAuto($command);
443                } else {
444                        $ok = true;
445                        foreach ($snippet as $s) {
446                                if (!is_array($s)) continue;
447                                if (!$s['phrase']) {
448                                        $s['phrase'] = $this->getSnippetAutoPhrase($command);
449                                }
450                                $ok &= $this->setOneSnippet($s);
451                        }
452                }
453                return $ok;
454        }
455
456        /**
457         * Définir 1 snippet depuis sa description
458         *
459         * @param array $desc
460         * @return bool
461        **/
462        public function setOneSnippet($desc) {
463
464                $desc += array(
465                        'champ'  => 'content',
466                        'phrase' => '',
467                        'limit'  => 200,
468                        'as'     => 'snippet'
469                );
470                if (!$desc['phrase']) {
471                        return false;
472                }
473
474                $this->queryApi->addSnippetWords( $desc['phrase'] );
475                $desc['phrase'] = $this->queryApi->getSnippetWords();
476
477                if (!$desc['phrase'] OR !$desc['champ']) {
478                        return false;
479                }
480                $this->queryApi->select("SNIPPET($desc[champ], " . $this->quote($desc['phrase']) . ", 'limit=$desc[limit],html_strip_mode=strip') AS $desc[as]");
481                return true;
482        }
483
484        /**
485         * Définir automatiquement un snippet dans le champ 'snippet'
486         * à partir de la recherche et des filtres
487         */
488        public function setSnippetAuto($command) {
489                $phrase = $this->getSnippetAutoPhrase($command);
490                if (!$phrase) return false;
491                return $this->setOneSnippet(array('phrase' => $phrase));
492        }
493
494        /**
495         * Extrait de la commande de boucle les phrases pertinentes cherchées
496         *
497         * - Cherche la phrase de recherche
498         *
499         * @param array $command Commande de la boucle Sphinx
500         * @return string phrases séparées par espace.
501        **/
502        public function getSnippetAutoPhrase($command) {
503                $phrase = '';
504
505                // mots de la recherche
506                $recherche = $command['recherche'];
507                if (!is_array($recherche)) $recherche = array($recherche);
508                $recherche = array_filter($recherche);
509                $phrase .= implode(' ', $recherche);
510
511                return $phrase;
512        }
513
514
515        /**
516         * Définit les commandes FACET
517         *
518         * @param array $facets Tableau des facettes demandées
519         * @return bool
520        **/
521        public function setFacet($facets) {
522                $facets = array_filter($facets);
523                if (!$facets) {
524                        return false;
525                }
526                $ok = true;
527                foreach ($facets as $facet) {
528                        if (!isset($facet['alias']) OR !isset($facet['query'])) {
529                                $ok = false;
530                                continue;
531                        }
532                        $alias = trim($facet['alias']);
533                        $query = trim($facet['query']);
534                        if (!$alias OR !$query) {
535                                $ok =  false;
536                                continue;
537                        }
538                        $this->facet[] = array('alias' => $alias, 'query' => $query);
539                        $this->queryApi->facet($query);
540                }
541                return $ok;
542        }
543
544
545
546        /**
547         * Définit des filtres
548         *
549         * @param array $facets Tableau des filtres demandées
550         * @return bool
551        **/
552        public function setFilter($filters) {
553                // compter le nombre de filtres ajoutés à la requête.
554                static $nb = 0;
555
556                $facets = array_filter($filters);
557                if (!$filters) {
558                        return false;
559                }
560                foreach ($filters as $filter) {
561                        // ignorer toutes les données vides
562                        if (!is_array($filter) OR !isset($filter['valeur']) OR !$valeur = $filter['valeur']) {
563                                continue;
564                        }
565                        if (is_array($valeur)) {
566                                $valeurs = $valeur;
567                                $valeur = 'Array !';
568                        } else {
569                                $valeur = trim($valeur);
570                                $valeurs = array($valeur);
571                        }
572                        $valeurs = array_unique(array_filter($valeurs));
573                        if (!$valeurs) {
574                                continue;
575                        }
576
577                        $filter += array(
578                                'select_oui'  => '',
579                                'select_null' => '',
580                        );
581
582                        // préparer les données
583                        $aucun = ($valeur == '-'); // si aucun demandé
584                        $valeur = $this->quote($valeur);
585                        $valeurs = array_map(array($this, 'quote'), $valeurs);
586                        $valeurs = implode(', ', $valeurs);
587
588                        if (($aucun == '-') and $filter['select_null']) {
589                                $f = $filter['select_null'];
590                        } elseif ($filter['select_oui']) {
591                                $f = $filter['select_oui'];
592                        }
593
594                        // remplacer d'abord le pluriel !
595                        $f = str_replace(array('@valeurs', '@valeur'), array($valeurs, $valeur), $f);
596                        $this->queryApi->select("($f) AS f$nb");
597                        $this->queryApi->where("f$nb = 1");
598                        $nb++;
599                }
600        }
601
602
603        /**
604         * Revenir au depart
605         * @return void
606         */
607        public function rewind() {
608                if (!is_array($this->result['docs'])) return false;
609                reset($this->result['docs']);
610                list($this->cle, $this->valeur) = each($this->result['docs']);
611        }
612
613        /**
614         * L'iterateur est-il encore valide ?
615         * @return bool
616         */
617        public function valid(){
618                return !is_null($this->cle);
619        }
620
621        /**
622         * Retourner la valeur
623         * @return null
624         */
625        public function current() {
626                return $this->valeur;
627        }
628
629        /**
630         * Retourner la cle
631         * @return null
632         */
633        public function key() {
634                return $this->cle;
635        }
636
637        /**
638         * Passer a la valeur suivante
639         * @return void
640         */
641        public function next(){
642                if ($this->valid()) {
643                        list($this->cle, $this->valeur) = each($this->result['docs']);
644                }
645        }
646
647        /**
648         * Compter le nombre total de resultats
649         * @return int
650         */
651        public function count() {
652                if (is_null($this->total))
653                        $this->total = count($this->result['docs']);
654          return $this->total;
655        }
656
657}
658
659
660/**
661 * Transmettre la source (l'index sphinx) désirée
662 * @param string $idb
663 * @param object $boucles
664 * @param object $crit
665 */
666function critere_SPHINX_index_dist($idb, &$boucles, $crit) {
667        $boucle = &$boucles[$idb];
668        // critere unique
669        $boucle->hash .= "\n\t" . '$command[\'index\'] = array();';
670
671        foreach ($crit->param as $param){
672                $boucle->hash .= "\n\t" . '$command[\'index\'][] = '.calculer_liste($param, array(), $boucles, $boucles[$idb]->id_parent).';';
673        }
674}
675
676/**
677 * Transmettre la recherche (le match fulltext) désirée
678 * @param string $idb
679 * @param object $boucles
680 * @param object $crit
681 */
682function critere_SPHINX_recherche_dist($idb, &$boucles, $crit) {
683        $boucle = &$boucles[$idb];
684        // critere unique
685        $boucle->hash .= "\n\t" . '$command[\'recherche\'] = array();';
686
687        foreach ($crit->param as $param){
688                $boucle->hash .= "\n\t" . '$command[\'recherche\'][] = '.calculer_liste($param, array(), $boucles, $boucles[$idb]->id_parent).';';
689        }
690}
691
692
693/**
694 * Indiquer les sélections de la requête
695 *
696 * @param string $idb
697 * @param object $boucles
698 * @param object $crit
699 */
700function critere_SPHINX_select_dist($idb, &$boucles, $crit) {
701        $boucle = &$boucles[$idb];
702        // critere multiple
703        $boucle->hash .= "\n\tif (!isset(\$select_init)) { \$command['selection'] = array(); \$select_init = true; }\n";
704
705        foreach ($crit->param as $param){
706                $boucle->hash .= "\t\$command['selection'][] = "
707                                . calculer_liste($param, array(), $boucles, $boucles[$idb]->id_parent) . ";\n";
708        }
709}
710
711
712/**
713 * Indiquer les group by de la requête
714 *
715 * @param string $idb
716 * @param object $boucles
717 * @param object $crit
718 */
719function critere_SPHINX_groupby_dist($idb, &$boucles, $crit) {
720        $boucle = &$boucles[$idb];
721        // critere multiple
722        $boucle->hash .= "\n\tif (!isset(\$group_init)) { \$command['group'] = array(); \$group_init = true; }\n";
723
724        foreach ($crit->param as $param){
725                $boucle->hash .= "\t\$command['group'][] = "
726                                . calculer_liste($param, array(), $boucles, $boucles[$idb]->id_parent) . ";\n";
727        }
728}
729
730
731/**
732 * Indiquer les snippets de la requête
733 *
734 * @param string $idb
735 * @param object $boucles
736 * @param object $crit
737 */
738function critere_SPHINX_snippet_dist($idb, &$boucles, $crit) {
739        $boucle = &$boucles[$idb];
740        // critere multiple
741        $boucle->hash .= "\n\tif (!isset(\$snippet_init)) { \$command['snippet'] = array(); \$snippet_init = true; }\n";
742
743        $boucle->hash .= "\t\$command['snippet'][] = [\n"
744                . (isset($crit->param[0]) ? "\t\t'champ'  => ". calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent) . ",\n" : '')
745                . (isset($crit->param[1]) ? "\t\t'phrase' => ". calculer_liste($crit->param[1], array(), $boucles, $boucles[$idb]->id_parent) . ",\n" : '')
746                . (isset($crit->param[2]) ? "\t\t'limit'  => ". calculer_liste($crit->param[2], array(), $boucles, $boucles[$idb]->id_parent) . ",\n" : '')
747                . (isset($crit->param[3]) ? "\t\t'as'     => ". calculer_liste($crit->param[3], array(), $boucles, $boucles[$idb]->id_parent) . "\n"  : '')
748                . "\t];\n";
749}
750
751
752
753/**
754 * Indiquer les facets de la requête
755 *
756 * @param string $idb
757 * @param object $boucles
758 * @param object $crit
759 */
760function critere_SPHINX_facet_dist($idb, &$boucles, $crit) {
761        $boucle = &$boucles[$idb];
762        // critere multiple
763        $boucle->hash .= "\n\tif (!isset(\$facet_init)) { \$command['facet'] = array(); \$facet_init = true; }\n";
764
765        $boucle->hash .= "\t\$command['facet'][] = array(\n"
766                . (isset($crit->param[0]) ? "\t\t'alias'  => ". calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent) . ",\n" : '')
767                . (isset($crit->param[1]) ? "\t\t'query' => ". calculer_liste($crit->param[1], array(), $boucles, $boucles[$idb]->id_parent) . ",\n" : '')
768                . "\t);\n";
769}
770
771/**
772 * Indiquer les filtres de la requête
773 *
774 * @param string $idb
775 * @param object $boucles
776 * @param object $crit
777 */
778function critere_SPHINX_filter_dist($idb, &$boucles, $crit) {
779        $boucle = &$boucles[$idb];
780        // critere multiple
781        $boucle->hash .= "\n\tif (!isset(\$sfilter_init)) { \$command['filter'] = array(); \$sfilter_init = true; }\n";
782
783        $boucle->hash .= "\t\$command['filter'][] = array(\n"
784                . (isset($crit->param[0]) ? "\t\t'valeur'      => ". calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent) . ",\n" : '')
785                . (isset($crit->param[1]) ? "\t\t'select_oui'  => ". calculer_liste($crit->param[1], array(), $boucles, $boucles[$idb]->id_parent) . ",\n" : '')
786                . (isset($crit->param[2]) ? "\t\t'select_null' => ". calculer_liste($crit->param[2], array(), $boucles, $boucles[$idb]->id_parent) . ",\n" : '')
787                . "\t);\n";
788}
789
790
791/**
792 * Pagination
793 *
794 * @param string $idb
795 * @param object $boucles
796 * @param object $crit
797 */
798function critere_SPHINX_pagination_dist($idb, &$boucles, $crit) {
799        $boucle = &$boucles[$idb];
800        // critere unique
801        $boucle->hash .=        "\t\$command['pagination'] = array("
802                . "intval(@\$Pile[0]['debut".$idb."']),"
803                . (isset($crit->param[0]) ? calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent) : '0')
804                . ");\n";
805
806        // appliquer enfin le critere {pagination} normal
807        return critere_pagination_dist($idb, $boucles, $crit);
808}
809
810
811/**
812 * Tris `{par x}`
813 *
814 * @param string $idb
815 * @param object $boucles
816 * @param object $crit
817 */
818function critere_SPHINX_par_dist($idb, &$boucles, $crit) {
819        return critere_SPHINX_parinverse($idb, $boucles, $crit);
820}
821
822/**
823 * Tris `{inverse}`
824 *
825 * @param string $idb
826 * @param object $boucles
827 * @param object $crit
828 */
829function critere_SPHINX_inverse_dist($idb, &$boucles, $crit) {
830        $boucle = &$boucles[$idb];
831        if ($crit->not) {
832                critere_SPHINX_parinverse($idb, $boucles, $crit);
833        } else {
834                // sinon idem parent.
835                critere_inverse_dist($idb, $boucles, $crit);
836        }
837}
838
839/**
840 * Gestion des critères `{par}` et `{inverse}`
841 *
842 * @note
843 *     Sphinx doit toujours avoir le sens de tri (ASC ou DESC).
844 *
845 *     Version simplifié du critère natif de SPIP, avec une permission
846 *     pour les champs de type json `properties.truc`
847 *
848 * @param string $idb
849 * @param object $boucles
850 * @param object $crit
851**/
852function critere_SPHINX_parinverse($idb, $boucles, $crit, $sens = '') {
853        $boucle = &$boucles[$idb];
854        if ($crit->not) {
855                $sens = $sens ? "" : " . ' DESC'";
856        }
857
858        foreach ($crit->param as $tri){
859                $order = "";
860
861                // tris specifies dynamiquement
862                if ($tri[0]->type!='texte'){
863                        // calculer le order dynamique qui verifie les champs
864                        $order = calculer_critere_arg_dynamique($idb, $boucles, $tri, $sens);
865                } else {
866                        $par = array_shift($tri);
867                        $par = $par->texte;
868                        $order = "'$par'";
869                }
870
871
872                $t = $order.$sens;
873                $boucle->order[] = $t;
874        }
875}
876
877
878/**
879 * Récupère pour une balise `#SPHINX_QQC` la valeur de 'qqc'
880 * dans les meta données associées à la requête
881 *
882 * - `#SPHINX_QUERY`
883 * - `#SPHINX_META`
884 * - `#SPHINX_FACETS`
885 *
886 * @param Champ $p
887 * @return Champ
888**/
889function balise_SPHINX__dist($p){
890        $champ = $p->nom_champ;
891        if ($champ == 'SPHINX_') {
892                $msg = _T('zbug_balise_sans_argument', array('balise' => ' SPHINX_'));
893                erreur_squelette($msg, $p);
894                $p->interdire_scripts = true;
895                return $p;
896        };
897        $champ = substr($champ, 7);
898        return calculer_balise_SPHINX_CHAMP($p, $champ);
899}
900
901
902
903
904/**
905 * Récupère pour une balise `#SPHINX_QQC` la valeur de 'qqc'
906 * dans les meta données associées à la requête.
907 *
908 * @param Champ $p
909 * @param string $champ
910 * @return Champ
911**/
912function calculer_balise_SPHINX_CHAMP($p, $champ) {
913        $b = $p->nom_boucle ? $p->nom_boucle : $p->descr['id_mere'];
914        if ($b === '' || !isset($p->boucles[$b])) {
915                $msg = array('zbug_champ_hors_boucle', array('champ' => '#SPHINX_' . $champ));
916                erreur_squelette($msg, $p);
917                $p->interdire_scripts = true;
918                return $p;
919        }
920
921        $champ = strtolower($champ);
922        $p->code = '(isset($GLOBALS["SphinxSave"]["'.$b.'"]["'.$champ.'"]) ? $GLOBALS["SphinxSave"]["'.$b.'"]["'.$champ.'"] : "")';
923
924        $p->interdire_scripts = false;
925        return $p;
926}
Note: See TracBrowser for help on using the repository browser.