MediaWiki  REL1_19
ApiQuerySearch.php
Go to the documentation of this file.
00001 <?php
00032 class ApiQuerySearch extends ApiQueryGeneratorBase {
00033 
00034         public function __construct( $query, $moduleName ) {
00035                 parent::__construct( $query, $moduleName, 'sr' );
00036         }
00037 
00038         public function execute() {
00039                 $this->run();
00040         }
00041 
00042         public function executeGenerator( $resultPageSet ) {
00043                 $this->run( $resultPageSet );
00044         }
00045 
00050         private function run( $resultPageSet = null ) {
00051                 global $wgContLang;
00052                 $params = $this->extractRequestParams();
00053 
00054                 // Extract parameters
00055                 $limit = $params['limit'];
00056                 $query = $params['search'];
00057                 $what = $params['what'];
00058                 $searchInfo = array_flip( $params['info'] );
00059                 $prop = array_flip( $params['prop'] );
00060 
00061                 // Create search engine instance and set options
00062                 $search = SearchEngine::create();
00063                 $search->setLimitOffset( $limit + 1, $params['offset'] );
00064                 $search->setNamespaces( $params['namespace'] );
00065                 $search->showRedirects = $params['redirects'];
00066 
00067                 $query = $search->transformSearchTerm( $query );
00068                 $query = $search->replacePrefixes( $query );
00069 
00070                 // Perform the actual search
00071                 if ( $what == 'text' ) {
00072                         $matches = $search->searchText( $query );
00073                 } elseif ( $what == 'title' ) {
00074                         $matches = $search->searchTitle( $query );
00075                 } elseif ( $what == 'nearmatch' ) {
00076                         $matches = SearchEngine::getNearMatchResultSet( $query );
00077                 } else {
00078                         // We default to title searches; this is a terrible legacy
00079                         // of the way we initially set up the MySQL fulltext-based
00080                         // search engine with separate title and text fields.
00081                         // In the future, the default should be for a combined index.
00082                         $what = 'title';
00083                         $matches = $search->searchTitle( $query );
00084 
00085                         // Not all search engines support a separate title search,
00086                         // for instance the Lucene-based engine we use on Wikipedia.
00087                         // In this case, fall back to full-text search (which will
00088                         // include titles in it!)
00089                         if ( is_null( $matches ) ) {
00090                                 $what = 'text';
00091                                 $matches = $search->searchText( $query );
00092                         }
00093                 }
00094                 if ( is_null( $matches ) ) {
00095                         $this->dieUsage( "{$what} search is disabled", "search-{$what}-disabled" );
00096                 }
00097 
00098                 $apiResult = $this->getResult();
00099                 // Add search meta data to result
00100                 if ( isset( $searchInfo['totalhits'] ) ) {
00101                         $totalhits = $matches->getTotalHits();
00102                         if ( $totalhits !== null ) {
00103                                 $apiResult->addValue( array( 'query', 'searchinfo' ),
00104                                                 'totalhits', $totalhits );
00105                         }
00106                 }
00107                 if ( isset( $searchInfo['suggestion'] ) && $matches->hasSuggestion() ) {
00108                         $apiResult->addValue( array( 'query', 'searchinfo' ),
00109                                                 'suggestion', $matches->getSuggestionQuery() );
00110                 }
00111 
00112                 // Add the search results to the result
00113                 $terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
00114                 $titles = array();
00115                 $count = 0;
00116                 $result = $matches->next();
00117 
00118                 while ( $result ) {
00119                         if ( ++ $count > $limit ) {
00120                                 // We've reached the one extra which shows that there are additional items to be had. Stop here...
00121                                 $this->setContinueEnumParameter( 'offset', $params['offset'] + $params['limit'] );
00122                                 break;
00123                         }
00124 
00125                         // Silently skip broken and missing titles
00126                         if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
00127                                 $result = $matches->next();
00128                                 continue;
00129                         }
00130 
00131                         $title = $result->getTitle();
00132                         if ( is_null( $resultPageSet ) ) {
00133                                 $vals = array();
00134                                 ApiQueryBase::addTitleInfo( $vals, $title );
00135 
00136                                 if ( isset( $prop['snippet'] ) ) {
00137                                         $vals['snippet'] = $result->getTextSnippet( $terms );
00138                                 }
00139                                 if ( isset( $prop['size'] ) ) {
00140                                         $vals['size'] = $result->getByteSize();
00141                                 }
00142                                 if ( isset( $prop['wordcount'] ) ) {
00143                                         $vals['wordcount'] = $result->getWordCount();
00144                                 }
00145                                 if ( isset( $prop['timestamp'] ) ) {
00146                                         $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $result->getTimestamp() );
00147                                 }
00148                                 if ( !is_null( $result->getScore() ) && isset( $prop['score'] ) ) {
00149                                         $vals['score'] = $result->getScore();
00150                                 }
00151                                 if ( isset( $prop['titlesnippet'] ) ) {
00152                                         $vals['titlesnippet'] = $result->getTitleSnippet( $terms );
00153                                 }
00154                                 if ( !is_null( $result->getRedirectTitle() ) ) {
00155                                         if ( isset( $prop['redirecttitle'] ) ) {
00156                                                 $vals['redirecttitle'] = $result->getRedirectTitle();
00157                                         }
00158                                         if ( isset( $prop['redirectsnippet'] ) ) {
00159                                                 $vals['redirectsnippet'] = $result->getRedirectSnippet( $terms );
00160                                         }
00161                                 }
00162                                 if ( !is_null( $result->getSectionTitle() ) ) {
00163                                         if ( isset( $prop['sectiontitle'] ) ) {
00164                                                 $vals['sectiontitle'] = $result->getSectionTitle()->getFragment();
00165                                         }
00166                                         if ( isset( $prop['sectionsnippet'] ) ) {
00167                                                 $vals['sectionsnippet'] = $result->getSectionSnippet();
00168                                         }
00169                                 }
00170                                 if ( isset( $prop['hasrelated'] ) && $result->hasRelated() ) {
00171                                         $vals['hasrelated'] = "";
00172                                 }
00173 
00174                                 // Add item to results and see whether it fits
00175                                 $fit = $apiResult->addValue( array( 'query', $this->getModuleName() ),
00176                                                 null, $vals );
00177                                 if ( !$fit ) {
00178                                         $this->setContinueEnumParameter( 'offset', $params['offset'] + $count - 1 );
00179                                         break;
00180                                 }
00181                         } else {
00182                                 $titles[] = $title;
00183                         }
00184 
00185                         $result = $matches->next();
00186                 }
00187 
00188                 if ( is_null( $resultPageSet ) ) {
00189                         $apiResult->setIndexedTagName_internal( array(
00190                                                 'query', $this->getModuleName()
00191                                         ), 'p' );
00192                 } else {
00193                         $resultPageSet->populateFromTitles( $titles );
00194                 }
00195         }
00196 
00197         public function getCacheMode( $params ) {
00198                 return 'public';
00199         }
00200 
00201         public function getAllowedParams() {
00202                 return array(
00203                         'search' => array(
00204                                 ApiBase::PARAM_TYPE => 'string',
00205                                 ApiBase::PARAM_REQUIRED => true
00206                         ),
00207                         'namespace' => array(
00208                                 ApiBase::PARAM_DFLT => 0,
00209                                 ApiBase::PARAM_TYPE => 'namespace',
00210                                 ApiBase::PARAM_ISMULTI => true,
00211                         ),
00212                         'what' => array(
00213                                 ApiBase::PARAM_DFLT => null,
00214                                 ApiBase::PARAM_TYPE => array(
00215                                         'title',
00216                                         'text',
00217                                         'nearmatch',
00218                                 )
00219                         ),
00220                         'info' => array(
00221                                 ApiBase::PARAM_DFLT => 'totalhits|suggestion',
00222                                 ApiBase::PARAM_TYPE => array(
00223                                         'totalhits',
00224                                         'suggestion',
00225                                 ),
00226                                 ApiBase::PARAM_ISMULTI => true,
00227                         ),
00228                         'prop' => array(
00229                                 ApiBase::PARAM_DFLT => 'size|wordcount|timestamp|snippet',
00230                                 ApiBase::PARAM_TYPE => array(
00231                                         'size',
00232                                         'wordcount',
00233                                         'timestamp',
00234                                         'score',
00235                                         'snippet',
00236                                         'titlesnippet',
00237                                         'redirecttitle',
00238                                         'redirectsnippet',
00239                                         'sectiontitle',
00240                                         'sectionsnippet',
00241                                         'hasrelated',
00242                                 ),
00243                                 ApiBase::PARAM_ISMULTI => true,
00244                         ),
00245                         'redirects' => false,
00246                         'offset' => 0,
00247                         'limit' => array(
00248                                 ApiBase::PARAM_DFLT => 10,
00249                                 ApiBase::PARAM_TYPE => 'limit',
00250                                 ApiBase::PARAM_MIN => 1,
00251                                 ApiBase::PARAM_MAX => ApiBase::LIMIT_SML1,
00252                                 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_SML2
00253                         )
00254                 );
00255         }
00256 
00257         public function getParamDescription() {
00258                 return array(
00259                         'search' => 'Search for all page titles (or content) that has this value',
00260                         'namespace' => 'The namespace(s) to enumerate',
00261                         'what' => 'Search inside the text or titles',
00262                         'info' => 'What metadata to return',
00263                         'prop' => array(
00264                                 'What properties to return',
00265                                 ' size             - Adds the size of the page in bytes',
00266                                 ' wordcount        - Adds the word count of the page',
00267                                 ' timestamp        - Adds the timestamp of when the page was last edited',
00268                                 ' score            - Adds the score (if any) from the search engine',
00269                                 ' snippet          - Adds a parsed snippet of the page',
00270                                 ' titlesnippet     - Adds a parsed snippet of the page title',
00271                                 ' redirectsnippet  - Adds a parsed snippet of the redirect title',
00272                                 ' redirecttitle    - Adds the title of the matching redirect',
00273                                 ' sectionsnippet   - Adds a parsed snippet of the matching section title',
00274                                 ' sectiontitle     - Adds the title of the matching section',
00275                                 ' hasrelated       - Indicates whether a related search is available',
00276                         ),
00277                         'redirects' => 'Include redirect pages in the search',
00278                         'offset' => 'Use this value to continue paging (return by query)',
00279                         'limit' => 'How many total pages to return'
00280                 );
00281         }
00282 
00283         public function getDescription() {
00284                 return 'Perform a full text search';
00285         }
00286 
00287         public function getPossibleErrors() {
00288                 return array_merge( parent::getPossibleErrors(), array(
00289                         array( 'code' => 'search-text-disabled', 'info' => 'text search is disabled' ),
00290                         array( 'code' => 'search-title-disabled', 'info' => 'title search is disabled' ),
00291                 ) );
00292         }
00293 
00294         public function getExamples() {
00295                 return array(
00296                         'api.php?action=query&list=search&srsearch=meaning',
00297                         'api.php?action=query&list=search&srwhat=text&srsearch=meaning',
00298                         'api.php?action=query&generator=search&gsrsearch=meaning&prop=info',
00299                 );
00300         }
00301 
00302         public function getHelpUrls() {
00303                 return 'https://www.mediawiki.org/wiki/API:Search';
00304         }
00305 
00306         public function getVersion() {
00307                 return __CLASS__ . ': $Id$';
00308         }
00309 }