(bug 19999) Made metadata and properties of search results optional. Added srprop...
[lhc/web/wiklou.git] / includes / api / ApiQuerySearch.php
index 693d621..6d3422d 100644 (file)
@@ -35,7 +35,7 @@ if (!defined('MEDIAWIKI')) {
  */
 class ApiQuerySearch extends ApiQueryGeneratorBase {
 
-       public function __construct($query, $moduleName) {
+       public function __construct( $query, $moduleName ) {
                parent :: __construct($query, $moduleName, 'sr');
        }
 
@@ -43,60 +43,115 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                $this->run();
        }
 
-       public function executeGenerator($resultPageSet) {
-               $this->run($resultPageSet);
+       public function executeGenerator( $resultPageSet ) {
+               $this->run( $resultPageSet );
        }
 
-       private function run($resultPageSet = null) {
-
+       private function run( $resultPageSet = null ) {
+               global $wgContLang;
                $params = $this->extractRequestParams();
 
+               // Extract parameters
                $limit = $params['limit'];
                $query = $params['search'];
-               if (is_null($query) || empty($query))
-                       $this->dieUsage("empty search string is not allowed", 'param-search');
-
+               $what = $params['what'];
+               $searchInfo = array_flip( $params['info'] );
+               $prop = array_flip( $params['prop'] );
+               
+               if ( strval( $query ) === '' )
+                       $this->dieUsage( "empty search string is not allowed", 'param-search' );
+
+               // Create search engine instance and set options
                $search = SearchEngine::create();
                $search->setLimitOffset( $limit+1, $params['offset'] );
                $search->setNamespaces( $params['namespace'] );
                $search->showRedirects = $params['redirects'];
 
-               if ($params['what'] == 'text')
+               // Perform the actual search
+               if ( $what == 'text' ) {
                        $matches = $search->searchText( $query );
-               else
+               } elseif( $what == 'title' ) {
                        $matches = $search->searchTitle( $query );
-               if (is_null($matches))
-                       $this->dieUsage("{$params['what']} search is disabled",
-                                       "search-{$params['what']}-disabled");
+               } else {
+                       // We default to title searches; this is a terrible legacy
+                       // of the way we initially set up the MySQL fulltext-based
+                       // search engine with separate title and text fields.
+                       // In the future, the default should be for a combined index.
+                       $what = 'title';
+                       $matches = $search->searchTitle( $query );
+                       
+                       // Not all search engines support a separate title search,
+                       // for instance the Lucene-based engine we use on Wikipedia.
+                       // In this case, fall back to full-text search (which will
+                       // include titles in it!)
+                       if( is_null( $matches ) ) {
+                               $what = 'text';
+                               $matches = $search->searchText( $query );
+                       }
+               }
+               if ( is_null( $matches ) )
+                       $this->dieUsage( "{$what} search is disabled", "search-{$what}-disabled" );
+               
+               // Add search meta data to result
+               if ( isset( $searchInfo['totalhits'] ) ) {
+                       $totalhits = $matches->getTotalHits();
+                       if( $totalhits !== null ) {
+                               $this->getResult()->addValue( array( 'query', 'searchinfo' ), 
+                                               'totalhits', $totalhits );
+                       }
+               }
+               if ( isset( $searchInfo['suggestion'] ) && $matches->hasSuggestion() ) {
+                       $this->getResult()->addValue( array( 'query', 'searchinfo' ), 
+                                               'suggestion', $matches->getSuggestionQuery() );
+               }
 
-               $data = array ();
+               // Add the search results to the result
+               $terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
+               $titles = array ();
                $count = 0;
-               while( $result = $matches->next() ) {
-                       if (++ $count > $limit) {
+               while ( $result = $matches->next() ) {
+                       if ( ++ $count > $limit ) {
                                // We've reached the one extra which shows that there are additional items to be had. Stop here...
-                               $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']);
+                               $this->setContinueEnumParameter( 'offset', $params['offset'] + $params['limit'] );
                                break;
                        }
 
-                       // Silently skip broken titles
-                       if ($result->isBrokenTitle()) continue;
+                       // Silently skip broken and missing titles
+                       if ( $result->isBrokenTitle() || $result->isMissingRevision() )
+                               continue;
                        
                        $title = $result->getTitle();
-                       if (is_null($resultPageSet)) {
-                               $data[] = array(
-                                       'ns' => intval($title->getNamespace()),
-                                       'title' => $title->getPrefixedText());
+                       if ( is_null( $resultPageSet ) ) {
+                               $vals = array();
+                               ApiQueryBase::addTitleInfo( $vals, $title );
+                               
+                               if ( isset( $prop['snippet'] ) )
+                                       $vals['snippet'] = $result->getTextSnippet( $terms );
+                               if ( isset( $prop['size'] ) )
+                                       $vals['size'] = $result->getByteSize();
+                               if ( isset( $prop['wordcount'] ) )
+                                       $vals['wordcount'] = $result->getWordCount();
+                               if ( isset( $prop['timestamp'] ) )
+                                       $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $result->getTimestamp() );
+                               
+                               // Add item to results and see whether it fits
+                               $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ), 
+                                               null, $vals );
+                               if ( !$fit ) {
+                                       $this->setContinueEnumParameter( 'offset', $params['offset'] + $count - 1 );
+                                       break;
+                               }
                        } else {
-                               $data[] = $title;
+                               $titles[] = $title;
                        }
                }
 
-               if (is_null($resultPageSet)) {
-                       $result = $this->getResult();
-                       $result->setIndexedTagName($data, 'p');
-                       $result->addValue('query', $this->getModuleName(), $data);
+               if ( is_null( $resultPageSet ) ) {
+                       $this->getResult()->setIndexedTagName_internal( array(
+                                               'query', $this->getModuleName()
+                                       ), 'p' );
                } else {
-                       $resultPageSet->populateFromTitles($data);
+                       $resultPageSet->populateFromTitles( $titles );
                }
        }
 
@@ -109,12 +164,30 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                                ApiBase :: PARAM_ISMULTI => true,
                        ),
                        'what' => array (
-                               ApiBase :: PARAM_DFLT => 'title',
+                               ApiBase :: PARAM_DFLT => null,
                                ApiBase :: PARAM_TYPE => array (
                                        'title',
                                        'text',
                                )
                        ),
+                       'info' => array(
+                               ApiBase :: PARAM_DFLT => 'totalhits|suggestion',
+                               ApiBase :: PARAM_TYPE => array (
+                                       'totalhits',
+                                       'suggestion',
+                               ),
+                               ApiBase :: PARAM_ISMULTI => true,
+                       ),
+                       'prop' => array(
+                               ApiBase :: PARAM_DFLT => 'size|wordcount|timestamp|snippet',
+                               ApiBase :: PARAM_TYPE => array (
+                                       'size',
+                                       'wordcount',
+                                       'timestamp',
+                                       'snippet',
+                               ),
+                               ApiBase :: PARAM_ISMULTI => true,
+                       ),
                        'redirects' => false,
                        'offset' => 0,
                        'limit' => array (
@@ -132,6 +205,8 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                        'search' => 'Search for all page titles (or content) that has this value.',
                        'namespace' => 'The namespace(s) to enumerate.',
                        'what' => 'Search inside the text or titles.',
+                       'info' => 'What metadata to return.',
+                       'prop' => 'What properties to return.',
                        'redirects' => 'Include redirect pages in the search.',
                        'offset' => 'Use this value to continue paging (return by query)',
                        'limit' => 'How many total pages to return.'
@@ -153,4 +228,4 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
        public function getVersion() {
                return __CLASS__ . ': $Id$';
        }
-}
+}
\ No newline at end of file