36 private $allowedParams;
39 private $searchEngineConfig;
42 private $searchEngineFactory;
60 parent::__construct( $query, $moduleName,
'sr' );
62 $this->searchEngineConfig = $searchEngineConfig;
63 $this->searchEngineFactory = $searchEngineFactory;
64 $this->titleMatcher = $titleMatcher;
72 $this->run( $resultPageSet );
79 private function run( $resultPageSet =
null ) {
83 $query = $params[
'search'];
84 $what = $params[
'what'];
85 $interwiki = $params[
'interwiki'];
86 $searchInfo = array_fill_keys( $params[
'info'],
true );
87 $prop = array_fill_keys( $params[
'prop'],
true );
91 if ( isset( $params[
'sort'] ) ) {
92 $search->setSort( $params[
'sort'] );
94 $search->setFeatureData(
'rewrite', (
bool)$params[
'enablerewrites'] );
95 $search->setFeatureData(
'interwiki', (
bool)$interwiki );
97 $search->setFeatureData(
'snippets', $this->decideSnippets( $prop ) );
99 $nquery = $search->replacePrefixes( $query );
100 if ( $nquery !== $query ) {
103 get_class( $search ) .
', this was deprecated in MediaWiki 1.32',
107 if ( $what ==
'text' ) {
108 $matches = $search->searchText( $query );
109 } elseif ( $what ==
'title' ) {
110 $matches = $search->searchTitle( $query );
111 } elseif ( $what ==
'nearmatch' ) {
114 $matches = $this->titleMatcher->getNearMatchResultSet( $params[
'search'] );
121 $matches = $search->searchTitle( $query );
129 $matches = $search->searchText( $query );
141 if ( $status->isOK() ) {
142 $this->
getMain()->getErrorFormatter()->addMessagesFromStatus(
150 $this->
dieWithError( [
'apierror-searchdisabled', $what ],
"search-{$what}-disabled" );
155 if ( isset( $searchInfo[
'totalhits'] ) ) {
156 $totalhits =
$matches->getTotalHits();
157 if ( $totalhits !==
null ) {
158 $apiResult->
addValue( [
'query',
'searchinfo' ],
159 'totalhits', $totalhits );
162 if ( isset( $searchInfo[
'suggestion'] ) &&
$matches->hasSuggestion() ) {
163 $apiResult->
addValue( [
'query',
'searchinfo' ],
164 'suggestion',
$matches->getSuggestionQuery() );
165 $apiResult->
addValue( [
'query',
'searchinfo' ],
166 'suggestionsnippet', HtmlArmor::getHtml(
$matches->getSuggestionSnippet() ) );
168 if ( isset( $searchInfo[
'rewrittenquery'] ) &&
$matches->hasRewrittenQuery() ) {
169 $apiResult->
addValue( [
'query',
'searchinfo' ],
170 'rewrittenquery',
$matches->getQueryAfterRewrite() );
171 $apiResult->
addValue( [
'query',
'searchinfo' ],
172 'rewrittenquerysnippet', HtmlArmor::getHtml(
$matches->getQueryAfterRewriteSnippet() ) );
186 if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
190 $vals = $this->getSearchResultData( $result, $prop );
192 if ( $resultPageSet ===
null ) {
202 $titles[] = $result->getTitle();
203 $data[] = $vals ?: [];
212 $canAddInterwiki = (bool)$params[
'enablerewrites'] && ( $resultPageSet ===
null );
213 if ( $canAddInterwiki ) {
214 $this->addInterwikiResults(
$matches, $apiResult, $prop,
'additional',
215 ISearchResultSet::INLINE_RESULTS );
219 if ( $interwiki && $resultPageSet ===
null ) {
220 $this->addInterwikiResults(
$matches, $apiResult, $prop,
'interwiki',
221 ISearchResultSet::SECONDARY_RESULTS );
224 if ( $resultPageSet ===
null ) {
229 $resultPageSet->setRedirectMergePolicy(
static function ( $current, $new ) {
230 if ( !isset( $current[
'index'] ) || $new[
'index'] < $current[
'index'] ) {
231 $current[
'index'] = $new[
'index'];
235 $resultPageSet->populateFromTitles( $titles );
236 $offset = $params[
'offset'] + 1;
237 foreach ( $titles as $index =>
$title ) {
238 $resultPageSet->setGeneratorData(
240 $data[ $index ] + [
'index' => $index + $offset ]
252 private function getSearchResultData(
SearchResult $result, $prop ) {
254 if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
260 $title = $result->getTitle();
262 $vals[
'pageid'] =
$title->getArticleID();
264 if ( isset( $prop[
'size'] ) ) {
265 $vals[
'size'] = $result->getByteSize();
267 if ( isset( $prop[
'wordcount'] ) ) {
268 $vals[
'wordcount'] = $result->getWordCount();
270 if ( isset( $prop[
'snippet'] ) ) {
271 $vals[
'snippet'] = $result->getTextSnippet();
273 if ( isset( $prop[
'timestamp'] ) ) {
274 $vals[
'timestamp'] =
wfTimestamp( TS_ISO_8601, $result->getTimestamp() );
276 if ( isset( $prop[
'titlesnippet'] ) ) {
277 $vals[
'titlesnippet'] = $result->getTitleSnippet();
279 if ( isset( $prop[
'categorysnippet'] ) ) {
280 $vals[
'categorysnippet'] = $result->getCategorySnippet();
282 if ( $result->getRedirectTitle() !==
null ) {
283 if ( isset( $prop[
'redirecttitle'] ) ) {
284 $vals[
'redirecttitle'] = $result->getRedirectTitle()->getPrefixedText();
286 if ( isset( $prop[
'redirectsnippet'] ) ) {
287 $vals[
'redirectsnippet'] = $result->getRedirectSnippet();
290 if ( $result->getSectionTitle() !==
null ) {
291 if ( isset( $prop[
'sectiontitle'] ) ) {
292 $vals[
'sectiontitle'] = $result->getSectionTitle()->getFragment();
294 if ( isset( $prop[
'sectionsnippet'] ) ) {
295 $vals[
'sectionsnippet'] = $result->getSectionSnippet();
298 if ( isset( $prop[
'isfilematch'] ) ) {
299 $vals[
'isfilematch'] = $result->isFileMatch();
302 if ( isset( $prop[
'extensiondata'] ) ) {
303 $extra = $result->getExtensionData();
323 private function addInterwikiResults(
329 foreach (
$matches->getInterwikiResults(
$type ) as $interwikiMatches ) {
331 $totalhits += $interwikiMatches->getTotalHits();
333 foreach ( $interwikiMatches as $result ) {
334 $title = $result->getTitle();
335 $vals = $this->getSearchResultData( $result, $prop );
337 $vals[
'namespace'] = $result->getInterwikiNamespaceText();
338 $vals[
'title'] =
$title->getText();
339 $vals[
'url'] =
$title->getFullURL();
345 $result->getInterwikiPrefix()
355 if ( $totalhits !==
null ) {
356 $apiResult->
addValue( [
'query', $section .
'searchinfo' ],
'totalhits', $totalhits );
365 private function decideSnippets( array $prop ): array {
370 if ( isset( $prop[
'titlesnippet'] ) ) {
376 if ( isset( $prop[
'redirectsnippet'] ) || isset( $prop[
'redirecttitle'] ) ) {
377 $fields[] =
'redirect';
379 if ( isset( $prop[
'categorysnippet'] ) ) {
380 $fields[] =
'category';
382 if ( isset( $prop[
'sectionsnippet'] ) || isset( $prop[
'sectiontitle'] ) ) {
383 $fields[] =
'heading';
393 if ( $this->allowedParams !==
null ) {
394 return $this->allowedParams;
399 ParamValidator::PARAM_TYPE => [
406 ParamValidator::PARAM_DEFAULT =>
'totalhits|suggestion|rewrittenquery',
407 ParamValidator::PARAM_TYPE => [
412 ParamValidator::PARAM_ISMULTI =>
true,
415 ParamValidator::PARAM_DEFAULT =>
'size|wordcount|timestamp|snippet',
416 ParamValidator::PARAM_TYPE => [
432 ParamValidator::PARAM_ISMULTI =>
true,
434 EnumDef::PARAM_DEPRECATED_VALUES => [
439 'interwiki' =>
false,
440 'enablerewrites' =>
false,
444 if ( $this->isInGeneratorMode() ) {
445 $this->allowedParams[
'prop'][ParamValidator::PARAM_DEFAULT] =
'';
446 $this->allowedParams[
'info'][ParamValidator::PARAM_DEFAULT] =
'';
451 $alternatives = $this->searchEngineConfig->getSearchTypes();
452 if ( count( $alternatives ) == 1 ) {
453 $this->allowedParams[
'sort'] = [
454 ParamValidator::PARAM_DEFAULT => SearchEngine::DEFAULT_SORT,
455 ParamValidator::PARAM_TYPE => $this->searchEngineFactory->create()->getValidSorts(),
459 return $this->allowedParams;
465 'profile-type' => SearchEngine::FT_QUERY_INDEP_PROFILE_TYPE,
466 'help-message' =>
'apihelp-query+search-param-qiprofile',
473 'action=query&list=search&srsearch=meaning'
474 =>
'apihelp-query+search-example-simple',
475 'action=query&list=search&srwhat=text&srsearch=meaning'
476 =>
'apihelp-query+search-example-text',
477 'action=query&generator=search&gsrsearch=meaning&prop=info'
478 =>
'apihelp-query+search-example-generator',
483 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.
Configuration handling class for SearchEngine.
Factory class for SearchEngine.
NOTE: this class is being refactored into an abstract base class.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
trait SearchApi
Traits for API components that use a SearchEngine.
A set of SearchEngine results.