PageRenderTime 121ms CodeModel.GetById 41ms app.highlight 46ms RepoModel.GetById 14ms app.codeStats 9ms

/kernel/classes/ezsearch.php

http://github.com/ezsystems/ezpublish
PHP | 659 lines | 422 code | 91 blank | 146 comment | 110 complexity | 3193a9bbd89180d91df32df9812ee295 MD5 | raw file
  1<?php
  2/**
  3 * File containing the eZSearch class.
  4 *
  5 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
  6 * @license For full copyright and license information view LICENSE file distributed with this source code.
  7 * @version //autogentag//
  8 * @package kernel
  9 */
 10
 11/*!
 12  \class eZSearch
 13  \ingroup eZKernel
 14  \brief eZSearch handles indexing of objects to the search engine
 15
 16*/
 17
 18class eZSearch
 19{
 20   /*!
 21     \static
 22     determine how to pass the commit argument, for deletes and updates
 23     maybe this needs to be further splitted
 24    */
 25
 26    static function needCommit()
 27    {
 28        $searchEngine = eZSearch::getEngine();
 29
 30        if ( $searchEngine instanceof ezpSearchEngine )
 31        {
 32            return $searchEngine->needCommit();
 33        }
 34        return true;
 35    }
 36    /*!
 37     \static
 38     See if a remove is needed in an update of content objects
 39    */
 40
 41    static function needRemoveWithUpdate()
 42    {
 43        $searchEngine = eZSearch::getEngine();
 44
 45        if ( $searchEngine instanceof ezpSearchEngine )
 46        {
 47            return $searchEngine->needRemoveWithUpdate();
 48        }
 49        return true;
 50    }
 51
 52    /**
 53     * Removes object $contentObject from the search database.
 54     *
 55     * @deprecated Since 5.0, use removeObjectById()
 56     * @param eZContentObject $contentObject the content object to remove
 57     * @param bool $commit Whether to commit after removing the object
 58     * @return bool True if the operation succeed.
 59     */
 60    static function removeObject( $contentObject, $commit = null )
 61    {
 62        $searchEngine = eZSearch::getEngine();
 63
 64        if ( $searchEngine instanceof ezpSearchEngine )
 65        {
 66            return $searchEngine->removeObjectById( $contentObject->attribute( "id" ), $commit );
 67        }
 68
 69        return false;
 70    }
 71
 72    /**
 73     * Removes a content object by Id from the search database.
 74     *
 75     * @since 5.0
 76     * @param int $contentObjectId the content object to remove by id
 77     * @param bool $commit Whether to commit after removing the object
 78     * @return bool True if the operation succeed.
 79     */
 80    static function removeObjectById( $contentObjectId, $commit = null )
 81    {
 82        $searchEngine = eZSearch::getEngine();
 83        if ( $searchEngine instanceof ezpSearchEngine )
 84        {
 85            return $searchEngine->removeObjectById( $contentObjectId, $commit );
 86        }
 87
 88        return false;
 89    }
 90
 91    /**
 92     * Adds object $contentObject to the search database.
 93     *
 94     * @param eZContentObject $contentObject Object to add to search engine
 95     * @param bool $commit Whether to commit after adding the object
 96     * @return bool True if the operation succeed.
 97     */
 98    static function addObject( $contentObject, $commit = true )
 99    {
100        $searchEngine = eZSearch::getEngine();
101
102        if ( $searchEngine instanceof ezpSearchEngine )
103        {
104            return $searchEngine->addObject( $contentObject, $commit );
105        }
106
107        return false;
108    }
109
110    /*!
111     \static
112     Runs a query to the search engine.
113    */
114    static function search( $searchText, $params, $searchTypes = array() )
115    {
116        $searchEngine = eZSearch::getEngine();
117
118        if ( $searchEngine instanceof ezpSearchEngine )
119        {
120            return $searchEngine->search( $searchText, $params, $searchTypes );
121        }
122    }
123
124    /*!
125     \static
126    */
127    static function normalizeText( $text )
128    {
129        $searchEngine = eZSearch::getEngine();
130
131        if ( $searchEngine instanceof ezpSearchEngine )
132        {
133            return $searchEngine->normalizeText( $text );
134        }
135
136        return '';
137    }
138
139    /*!
140     \static
141      returns search parameters in array based on supported search types and post variables
142     */
143    static function buildSearchArray()
144    {
145        $searchEngine = eZSearch::getEngine();
146
147        $searchArray = array();
148        $andSearchParts = array();
149        $searchTypesDefinition = array( 'types' => array(), 'general_filter' => array() );
150
151        if ( $searchEngine instanceof ezpSearchEngine )
152        {
153            // This method was renamed in pre 3.5 trunk
154            if ( method_exists( $searchEngine, 'supportedSearchTypes' ) )
155            {
156                $searchTypesDefinition = $searchEngine->supportedSearchTypes();  // new and correct
157            }
158            else
159            {
160                $searchTypesDefinition = $searchEngine->suportedSearchTypes();  // deprecated
161            }
162        }
163
164        $http = eZHTTPTool::instance();
165
166        foreach ( $searchTypesDefinition['types'] as $searchType )
167        {
168            $postVariablePrefix = 'Content_search_' . $searchType['type'] . '_' . $searchType['subtype'] . '_';
169            //print $postVariablePrefix . "\n";
170            //print_r( $searchType['params'] );
171            $searchArrayPartForType = array();
172
173            $searchPart = array();
174            $valuesFetched = false;
175            $valuesMissing = false;
176            foreach ( $searchType['params'] as $parameter )
177            {
178                eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $postVariablePrefix . $parameter,
179                                            'post variable to check' );
180
181                if ( $http->hasVariable( $postVariablePrefix . $parameter ) )
182                {
183                    $values = $http->variable( $postVariablePrefix . $parameter );
184                    eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $values, 'fetched values' );
185
186                    foreach ( $values as $i => $value )
187                    {
188                        $searchArrayPartForType[$i][$parameter] = $values[$i];
189                        $valuesFetched = true;
190                    }
191                }
192                else
193                {
194                    eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $postVariablePrefix . $parameter,
195                                                'post variable does not exist' );
196                    $valuesMissing = true;
197                    break;
198                }
199            }
200
201            if ( $valuesFetched == true && $valuesMissing == false )
202            {
203                eZDebugSetting::writeDebug( 'kernel-search-ezsearch', 'adding values to search' );
204                foreach ( array_keys( $searchArrayPartForType ) as $key )
205                {
206                    $part =& $searchArrayPartForType[$key];
207                    $part['type'] = $searchType['type'];
208                    $part['subtype'] = $searchType['subtype'];
209
210                    if ( $part['type'] == 'attribute' )
211                    {
212                        // Remove incomplete search parts from the search.
213                        // An incomplete search part is for instance an empty text field,
214                        // or a select box with no selected values.
215
216                        // This functionality has been moved to the search engine.
217                        // Checking if it is defined in the search engine
218                        if ( method_exists( $searchEngine, 'isSearchPartIncomplete' ) )
219                        {
220                            $removePart = $searchEngine->isSearchPartIncomplete( $part );
221                        }
222                        else // for backwards compatibility
223                        {
224                            $removePart = false;
225                            switch ( $part['subtype'] )
226                            {
227                                case 'fulltext':
228                                {
229                                    if ( !isset( $part['value'] ) || $part['value'] == '' )
230                                        $removePart = true;
231                                }
232                                break;
233
234                                case 'patterntext':
235                                {
236                                    if ( !isset( $part['value'] ) || $part['value'] == '' )
237                                        $removePart = true;
238                                }
239                                break;
240
241                                case 'integer':
242                                {
243                                    if ( !isset( $part['value'] ) || $part['value'] == '' )
244                                        $removePart = true;
245                                }
246                                break;
247
248                                case 'integers':
249                                {
250                                    if ( !isset( $part['values'] ) || count( $part['values'] ) == 0 )
251                                        $removePart = true;
252                                }
253                                break;
254
255                                case 'byrange':
256                                {
257                                    if ( !isset( $part['from'] ) || $part['from'] == '' ||
258                                         !isset( $part['to'] ) || $part['to'] == '' )
259                                        $removePart = true;
260                                }
261                                break;
262
263                                case 'byidentifier':
264                                {
265                                    if ( !isset( $part['value'] ) || $part['value'] == '' )
266                                        $removePart = true;
267                                }
268                                break;
269
270                                case 'byidentifierrange':
271                                {
272                                    if ( !isset( $part['from'] ) || $part['from'] == '' ||
273                                         !isset( $part['to'] ) || $part['to'] == '' )
274                                        $removePart = true;
275                                }
276                                break;
277
278                                case 'integersbyidentifier':
279                                {
280                                    if ( !isset( $part['values'] ) || count( $part['values'] ) == 0 )
281                                        $removePart = true;
282                                }
283                                break;
284
285                                case 'byarea':
286                                {
287                                    if ( !isset( $part['from'] ) || $part['from'] == '' ||
288                                         !isset( $part['to'] ) || $part['to'] == '' ||
289                                         !isset( $part['minvalue'] ) || $part['minvalue'] == '' ||
290                                         !isset( $part['maxvalue'] ) || $part['maxvalue'] == '' )
291                                    {
292                                        $removePart = true;
293                                    }
294                                }
295                            }
296                        }
297
298                        if ( $removePart )
299                        {
300                            eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $searchArrayPartForType[$key],
301                                                        'removing incomplete search part' );
302                            unSet( $searchArrayPartForType[$key] );
303                        }
304                    }
305                }
306                $andSearchParts = array_merge( $andSearchParts, $searchArrayPartForType );
307            }
308        }
309        $generalFilter = array();
310        foreach ( $searchTypesDefinition['general_filter'] as $searchType )
311        {
312
313            $postVariablePrefix = 'Content_search_' . $searchType['type'] . '_' . $searchType['subtype'] . '_';
314
315            $searchArrayPartForType = array();
316
317            $searchPart = array();
318            $valuesFetched = false;
319            $valuesMissing = false;
320
321            foreach ( $searchType['params'] as $parameter )
322            {
323                $varName = '';
324                $paramName = '';
325                if ( is_array( $parameter ) )
326                {
327                    $varName = $postVariablePrefix . $parameter['value'];
328                    $paramName = $parameter['value'];
329                }
330                else
331                {
332                    $varName = $postVariablePrefix . $parameter;
333                    $paramName = $parameter;
334                }
335
336                eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $varName,
337                                            'post variable to check' );
338
339                if ( $http->hasVariable( $varName ) )
340                {
341                    $values = $http->variable( $varName );
342                    eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $values, 'fetched values' );
343                    $searchArrayPartForType[$paramName] = $values;
344                    $valuesFetched = true;
345
346                }
347                else
348                {
349                    eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $varName,
350                                                'post variable does not exist' );
351                    $valuesMissing = true;
352                    break;
353                }
354            }
355
356            if ( $valuesFetched == true && $valuesMissing == false )
357            {
358                eZDebugSetting::writeDebug( 'kernel-search-ezsearch', 'adding values to search' );
359
360                $part =& $searchArrayPartForType;
361
362                $part['type'] = $searchType['type'];
363                $part['subtype'] = $searchType['subtype'];
364
365                if ( $part['type'] == 'general' )
366                {
367                        // Remove incomplete search parts from the search.
368                        // An incomplete search part is for instance an empty text field,
369                        // or a select box with no selected values.
370                    $removePart = false;
371                    switch ( $part['subtype'] )
372                    {
373                        case 'class':
374                        {
375                            if ( !isset( $part['value'] ) ||
376                                 ( is_array( $part['value'] ) && count( $part['value'] ) == 0 ) ||
377                                 ( !is_array( $part['value'] ) && $part['value'] == '' ) )
378                                $removePart = true;
379                        }
380                        break;
381                        case 'publishdate':
382                        {
383                            if ( !isset( $part['value'] ) ||
384                                 ( is_array( $part['value'] ) && count( $part['value'] ) == 0 ) ||
385                                 ( !is_array( $part['value'] ) && $part['value'] == '' ) )
386                                $removePart = true;
387                        }
388                        break;
389                        case 'subtree':
390                        {
391                            if ( !isset( $part['value'] ) ||
392                                 ( is_array( $part['value'] ) && count( $part['value'] ) == 0 ) ||
393                                 ( !is_array( $part['value'] ) && $part['value'] == '' ) )
394
395                                $removePart = true;
396                        }
397                        break;
398                    }
399
400                    if ( $removePart )
401                    {
402                        eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $searchArrayPartForType[$key],
403                                                    'removing incomplete search part' );
404                        unSet( $searchArrayPartForType[$key] );
405                        continue;
406                    }
407                }
408
409                $generalFilter = array_merge( $generalFilter, array( $searchArrayPartForType ) );
410            }
411
412
413        }
414
415        if ( $andSearchParts != null )
416        {
417            $searchArray['and'] = $andSearchParts;
418        }
419        if ( $generalFilter != null )
420        {
421            $searchArray['general'] = $generalFilter;
422        }
423
424        eZDebugSetting::writeDebug( 'kernel-search-ezsearch', $searchArray, 'search array' );
425        return $searchArray;
426    }
427
428    /*!
429     \static
430     Tells the current search engine to cleanup up all data.
431    */
432    static function cleanup()
433    {
434        $searchEngine = eZSearch::getEngine();
435
436        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'cleanup' ) )
437        {
438            $searchEngine->cleanup();
439        }
440    }
441
442    /**
443     * Get object instance of eZSearch engine to use.
444     *
445     * @return \ezpSearchEngine|bool Returns false (+ writes debug) if no engine was found
446    */
447    static public function getEngine()
448    {
449        // Get instance if already created.
450        $instanceName = "eZSearchPlugin_" . $GLOBALS["eZCurrentAccess"]["name"];
451        if ( isset( $GLOBALS[$instanceName] ) )
452        {
453            return $GLOBALS[$instanceName];
454        }
455
456        $ini = eZINI::instance();
457
458        $searchEngineString = 'ezsearch';
459        if ( $ini->hasVariable( 'SearchSettings', 'SearchEngine' ) == true )
460        {
461            $searchEngineString = $ini->variable( 'SearchSettings', 'SearchEngine' );
462        }
463
464        $directoryList = array();
465        if ( $ini->hasVariable( 'SearchSettings', 'ExtensionDirectories' ) )
466        {
467            $extensionDirectories = $ini->variable( 'SearchSettings', 'ExtensionDirectories' );
468            if ( is_array( $extensionDirectories ) )
469            {
470                $directoryList = eZExtension::expandedPathList( $extensionDirectories, 'search/plugins' );
471            }
472        }
473
474        $kernelDir = array( 'kernel/search/plugins' );
475        $directoryList = array_merge( $kernelDir, $directoryList );
476
477        foreach( $directoryList as $directory )
478        {
479            $searchEngineFile = implode( '/', array( $directory, strtolower( $searchEngineString ), strtolower( $searchEngineString ) ) ) . '.php';
480
481            if ( file_exists( $searchEngineFile ) )
482            {
483                eZDebugSetting::writeDebug( 'kernel-search-ezsearch', 'Loading search engine from ' . $searchEngineFile, 'eZSearch::getEngine' );
484
485                include_once( $searchEngineFile );
486                $GLOBALS[$instanceName] = new $searchEngineString();
487                return $GLOBALS[$instanceName];
488            }
489        }
490
491        eZDebug::writeDebug( 'Unable to find the search engine:' . $searchEngineString, 'eZSearch' );
492        eZDebug::writeDebug( 'Tried paths: ' . implode( ', ', $directoryList ), 'eZSearch' );
493        return false;
494    }
495
496    /**
497     * Notifies search engine about the change of section of a set of objects
498     *
499     * @since 4.6
500     * @param array $objectIDs
501     * @param int $sectionID
502     * @return false|mixed false in case method is undefined, otherwise return the result of the search engine call
503     */
504    public static function updateObjectsSection( array $objectIDs, $sectionID )
505    {
506        $searchEngine = eZSearch::getEngine();
507        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'updateObjectsSection' ) )
508        {
509            return $searchEngine->updateObjectsSection( $objectIDs, $sectionID );
510        }
511        return false;
512    }
513
514    /**
515     * Notifies search engine about section changes
516     *
517     * @since 4.1
518     * @param int $nodeID
519     * @param int $sectionID
520     * @return false|mixed False in case method is undefined, otherwise return the result of the search engine call
521     */
522    public static function updateNodeSection( $nodeID, $sectionID )
523    {
524        $searchEngine = eZSearch::getEngine();
525
526        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'updateNodeSection' ) )
527        {
528            return $searchEngine->updateNodeSection( $nodeID, $sectionID );
529        }
530
531        return false;
532    }
533
534    /**
535     * Notifies search engine about node visibility changes
536     *
537     * @since 4.1
538     * @param int $nodeID
539     * @param string $action "hide" or "show"
540     * @return false|mixed False in case method is undefined, otherwise return the result of the search engine call
541     */
542    public static function updateNodeVisibility( $nodeID, $action )
543    {
544        $searchEngine = eZSearch::getEngine();
545
546        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'updateNodeVisibility' ) )
547        {
548            return $searchEngine->updateNodeVisibility( $nodeID, $action );
549        }
550
551        return false;
552    }
553
554    /**
555     * Notifies search engine about new node assignments added
556     *
557     * @since 4.1
558     * @param int $mainNodeID
559     * @param int $objectID
560     * @param array $nodeAssignmentIDList
561     * @param bool $isMoved true if node is being moved
562     * @return false|mixed False in case method is undefined, otherwise return the result of the search engine call
563     */
564    public static function addNodeAssignment( $mainNodeID, $objectID, $nodeAssignmentIDList, $isMoved = false )
565    {
566        $searchEngine = eZSearch::getEngine();
567
568        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'addNodeAssignment' ) )
569        {
570            return $searchEngine->addNodeAssignment( $mainNodeID, $objectID, $nodeAssignmentIDList, $isMoved );
571        }
572
573        return false;
574    }
575
576    /**
577     * Notifies search engine about removed node assignments and what the new main node is (same if not changed)
578     *
579     * @since 4.1
580     * @param int $mainNodeID
581     * @param int $newMainNodeID
582     * @param int $objectID
583     * @param array $nodeAssigmentIDList
584     * @return false|mixed False in case method is undefined, otherwise return the result of the search engine call
585     */
586    public static function removeNodeAssignment( $mainNodeID, $newMainNodeID, $objectID, $nodeAssigmentIDList )
587    {
588        $searchEngine = eZSearch::getEngine();
589
590        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'removeNodeAssignment' ) )
591        {
592            return $searchEngine->removeNodeAssignment( $mainNodeID, $newMainNodeID, $objectID, $nodeAssigmentIDList );
593        }
594
595        return false;
596    }
597
598    /**
599     * Notifies search engine about nodes being removed
600     *
601     * @since 4.1
602     * @param array $nodeIdList Array of node ID to remove.
603     * @return false|mixed False in case method is undefined, otherwise return the result of the search engine call
604     */
605    public static function removeNodes( array $nodeIdList )
606    {
607        $searchEngine = self::getEngine();
608
609        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'removeNodes' ) )
610        {
611            return $searchEngine->removeNodes( $nodeIdList );
612        }
613
614        return false;
615    }
616
617    /**
618     * Notifies search engine about updates to object states
619     *
620     * @since 4.1
621     * @param int $objectID
622     * @param array $objectStateList
623     * @return false|mixed False in case method is undefined, otherwise return the result of the search engine call
624     */
625    public static function updateObjectState( $objectID, $objectStateList )
626    {
627        $searchEngine = eZSearch::getEngine();
628
629        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'updateObjectState' ) )
630        {
631            return $searchEngine->updateObjectState( $objectID, $objectStateList );
632        }
633
634        return false;
635    }
636
637    /**
638     * Notifies search engine about an swap node operation
639     *
640     * @since 4.1
641     * @param int $nodeID
642     * @param int $selectedNodeID
643     * @param array $nodeIdList
644     * @return false|mixed False in case method is undefined, otherwise return the result of the search engine call
645     */
646    public static function swapNode( $nodeID, $selectedNodeID, $nodeIdList = array() )
647    {
648        $searchEngine = eZSearch::getEngine();
649
650        if ( $searchEngine instanceof ezpSearchEngine && method_exists( $searchEngine, 'swapNode' ) )
651        {
652            return $searchEngine->swapNode( $nodeID, $selectedNodeID, $nodeIdList = array() );
653        }
654
655        return false;
656    }
657}
658
659?>