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

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

Ajouter deux nouveaux critères à la boucle SPHINX qui utilisent l'API en tableau, et qui donc permettent une grande partie du filtrages sans avoir à écrire soit même les requêtes.

{filtermono (test si on fait qqc), (champ), (valeurs), (comparaison optionnelle si pas =)}

{filtermultijson (test si on fait qqc), (champ), (valeurs)}

Maintenant il faut améliorer l'API pour "mono" pour placer le test dans le "select" comme pour {filtermultijson} et {filter} afin de pouvoir utiliser length(), year(), etc qu'on a pas le droit d'utiliser dans le where.

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