52 parent::__construct( $query, $moduleName,
'sr' );
54 $this->searchEngineConfig = $searchEngineConfig;
55 $this->searchEngineFactory = $searchEngineFactory;
56 $this->titleMatcher = $titleMatcher;
64 $this->run( $resultPageSet );
71 private function run( $resultPageSet =
null ) {
75 $query = $params[
'search'];
76 $what = $params[
'what'];
77 $interwiki = $params[
'interwiki'];
78 $searchInfo = array_fill_keys( $params[
'info'],
true );
79 $prop = array_fill_keys( $params[
'prop'],
true );
83 if ( isset( $params[
'sort'] ) ) {
84 $search->setSort( $params[
'sort'] );
86 $search->setFeatureData(
'rewrite', (
bool)$params[
'enablerewrites'] );
87 $search->setFeatureData(
'interwiki', (
bool)$interwiki );
89 $search->setFeatureData(
'snippets', $this->decideSnippets( $prop ) );
91 $nquery = $search->replacePrefixes( $query );
92 if ( $nquery !== $query ) {
95 get_class( $search ) .
', this was deprecated in MediaWiki 1.32',
99 if ( $what ==
'text' ) {
100 $matches = $search->searchText( $query );
101 } elseif ( $what ==
'title' ) {
102 $matches = $search->searchTitle( $query );
103 } elseif ( $what ==
'nearmatch' ) {
106 $matches = $this->titleMatcher->getNearMatchResultSet( $params[
'search'] );
113 $matches = $search->searchTitle( $query );
121 $matches = $search->searchText( $query );
133 if ( $status->isOK() ) {
134 $this->
getMain()->getErrorFormatter()->addMessagesFromStatus(
142 $this->
dieWithError( [
'apierror-searchdisabled', $what ],
"search-{$what}-disabled" );
147 if ( isset( $searchInfo[
'totalhits'] ) ) {
148 $totalhits =
$matches->getTotalHits();
149 if ( $totalhits !==
null ) {
150 $apiResult->
addValue( [
'query',
'searchinfo' ],
151 'totalhits', $totalhits );
154 if ( isset( $searchInfo[
'suggestion'] ) &&
$matches->hasSuggestion() ) {
155 $apiResult->
addValue( [
'query',
'searchinfo' ],
156 'suggestion',
$matches->getSuggestionQuery() );
157 $apiResult->
addValue( [
'query',
'searchinfo' ],
160 if ( isset( $searchInfo[
'rewrittenquery'] ) &&
$matches->hasRewrittenQuery() ) {
161 $apiResult->
addValue( [
'query',
'searchinfo' ],
162 'rewrittenquery',
$matches->getQueryAfterRewrite() );
163 $apiResult->
addValue( [
'query',
'searchinfo' ],
178 if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
182 $vals = $this->getSearchResultData( $result, $prop );
184 if ( $resultPageSet ===
null ) {
194 $titles[] = $result->getTitle();
195 $data[] = $vals ?: [];
204 $canAddInterwiki = (bool)$params[
'enablerewrites'] && ( $resultPageSet ===
null );
205 if ( $canAddInterwiki ) {
206 $this->addInterwikiResults(
$matches, $apiResult, $prop,
'additional',
211 if ( $interwiki && $resultPageSet ===
null ) {
212 $this->addInterwikiResults(
$matches, $apiResult, $prop,
'interwiki',
216 if ( $resultPageSet ===
null ) {
221 $resultPageSet->setRedirectMergePolicy(
static function ( $current, $new ) {
222 if ( !isset( $current[
'index'] ) || $new[
'index'] < $current[
'index'] ) {
223 $current[
'index'] = $new[
'index'];
227 $resultPageSet->populateFromTitles( $titles );
228 $offset = $params[
'offset'] + 1;
229 foreach ( $titles as $index => $title ) {
230 $resultPageSet->setGeneratorData(
232 $data[ $index ] + [
'index' => $index + $offset ]
244 private function getSearchResultData(
SearchResult $result, $prop ) {
246 if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
252 $title = $result->getTitle();
254 $vals[
'pageid'] = $title->getArticleID();
256 if ( isset( $prop[
'size'] ) ) {
257 $vals[
'size'] = $result->getByteSize();
259 if ( isset( $prop[
'wordcount'] ) ) {
260 $vals[
'wordcount'] = $result->getWordCount();
262 if ( isset( $prop[
'snippet'] ) ) {
263 $vals[
'snippet'] = $result->getTextSnippet();
265 if ( isset( $prop[
'timestamp'] ) ) {
266 $vals[
'timestamp'] =
wfTimestamp( TS_ISO_8601, $result->getTimestamp() );
268 if ( isset( $prop[
'titlesnippet'] ) ) {
269 $vals[
'titlesnippet'] = $result->getTitleSnippet();
271 if ( isset( $prop[
'categorysnippet'] ) ) {
272 $vals[
'categorysnippet'] = $result->getCategorySnippet();
274 if ( $result->getRedirectTitle() !==
null ) {
275 if ( isset( $prop[
'redirecttitle'] ) ) {
276 $vals[
'redirecttitle'] = $result->getRedirectTitle()->getPrefixedText();
278 if ( isset( $prop[
'redirectsnippet'] ) ) {
279 $vals[
'redirectsnippet'] = $result->getRedirectSnippet();
282 if ( $result->getSectionTitle() !==
null ) {
283 if ( isset( $prop[
'sectiontitle'] ) ) {
284 $vals[
'sectiontitle'] = $result->getSectionTitle()->getFragment();
286 if ( isset( $prop[
'sectionsnippet'] ) ) {
287 $vals[
'sectionsnippet'] = $result->getSectionSnippet();
290 if ( isset( $prop[
'isfilematch'] ) ) {
291 $vals[
'isfilematch'] = $result->isFileMatch();
294 if ( isset( $prop[
'extensiondata'] ) ) {
295 $extra = $result->getExtensionData();
315 private function addInterwikiResults(
320 if (
$matches->hasInterwikiResults( $type ) ) {
321 foreach (
$matches->getInterwikiResults( $type ) as $interwikiMatches ) {
323 $totalhits += $interwikiMatches->getTotalHits();
325 foreach ( $interwikiMatches as $result ) {
326 $title = $result->getTitle();
327 $vals = $this->getSearchResultData( $result, $prop );
329 $vals[
'namespace'] = $result->getInterwikiNamespaceText();
330 $vals[
'title'] = $title->getText();
331 $vals[
'url'] = $title->getFullURL();
337 $result->getInterwikiPrefix()
347 if ( $totalhits !==
null ) {
348 $apiResult->
addValue( [
'query', $section .
'searchinfo' ],
'totalhits', $totalhits );
357 private function decideSnippets( array $prop ): array {
362 if ( isset( $prop[
'titlesnippet'] ) ) {
368 if ( isset( $prop[
'redirectsnippet'] ) || isset( $prop[
'redirecttitle'] ) ) {
369 $fields[] =
'redirect';
371 if ( isset( $prop[
'categorysnippet'] ) ) {
372 $fields[] =
'category';
374 if ( isset( $prop[
'sectionsnippet'] ) || isset( $prop[
'sectiontitle'] ) ) {
375 $fields[] =
'heading';
387 ParamValidator::PARAM_TYPE => [
394 ParamValidator::PARAM_DEFAULT =>
'totalhits|suggestion|rewrittenquery',
395 ParamValidator::PARAM_TYPE => [
400 ParamValidator::PARAM_ISMULTI =>
true,
403 ParamValidator::PARAM_DEFAULT =>
'size|wordcount|timestamp|snippet',
404 ParamValidator::PARAM_TYPE => [
420 ParamValidator::PARAM_ISMULTI =>
true,
422 EnumDef::PARAM_DEPRECATED_VALUES => [
427 'interwiki' =>
false,
428 'enablerewrites' =>
false,
432 if ( $this->isInGeneratorMode() ) {
433 $allowedParams[
'prop'][ParamValidator::PARAM_DEFAULT] =
'';
434 $allowedParams[
'info'][ParamValidator::PARAM_DEFAULT] =
'';
439 $alternatives = $this->searchEngineConfig->getSearchTypes();
440 if ( count( $alternatives ) == 1 ) {
441 $allowedParams[
'sort'] = [
443 ParamValidator::PARAM_TYPE => $this->searchEngineFactory->create()->getValidSorts(),
447 return $allowedParams;
454 'help-message' =>
'apihelp-query+search-param-qiprofile',
461 'action=query&list=search&srsearch=meaning'
462 =>
'apihelp-query+search-example-simple',
463 'action=query&list=search&srwhat=text&srsearch=meaning'
464 =>
'apihelp-query+search-example-text',
465 'action=query&generator=search&gsrsearch=meaning&prop=info'
466 =>
'apihelp-query+search-example-generator',
471 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Search';
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
buildSearchEngine(array $params=null)
Build the search engine to use.
buildCommonApiParams( $isScrollable=true)
The set of api parameters that are shared between api calls that call the SearchEngine.
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
getMain()
Get the main module.
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
getResult()
Get the result object.
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
getModuleName()
Get the name of the module being executed by this instance.
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
setContinueEnumParameter( $paramName, $paramValue)
Overridden to set the generator param if in generator mode.
Query module to perform full text search within wiki titles and content.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getHelpUrls()
Return links to more detailed help pages about the module.
getExamplesMessages()
Returns usage examples for this module.
getCacheMode( $params)
Get the cache mode for the data generated by this module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
executeGenerator( $resultPageSet)
Execute this module as a generator.
__construct(ApiQuery $query, $moduleName, SearchEngineConfig $searchEngineConfig, SearchEngineFactory $searchEngineFactory, TitleMatcher $titleMatcher)
This is the main query class.
This class represents the result of the API operations.
static addMetadataToResultVars( $vars, $forceHash=true)
Add the correct metadata to an array of vars we want to export through the API.
addIndexedTagName( $path, $tag)
Set the tag name for numeric-keyed values in XML format.
addValue( $path, $name, $value, $flags=0)
Add value to the output data at the given path.
static getHtml( $input)
Provide a string or HtmlArmor object and get safe HTML back.
Configuration handling class for SearchEngine.
Factory class for SearchEngine.
const FT_QUERY_INDEP_PROFILE_TYPE
Profile type for query independent ranking features.
NOTE: this class is being refactored into an abstract base class.
trait SearchApi
Traits for API components that use a SearchEngine.
A set of SearchEngine results.
const INLINE_RESULTS
Identifier for interwiki results that can be displayed even if no existing main wiki results exist.
const SECONDARY_RESULTS
Identifier for interwiki results that are displayed only together with existing main wiki results.