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

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

Cette variable du tableau n'existe pas si la requête ne retourne rien. Il faut donc tester son existance avant sinon WARNING PHP.

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