36 private $format =
null;
40 private $allowedParams =
null;
43 private $linkBatchFactory;
59 parent::__construct( $mainModule, $moduleName );
60 $this->linkBatchFactory = $linkBatchFactory;
62 $this->searchEngineConfig = $searchEngineConfig;
63 $this->searchEngineFactory = $searchEngineFactory;
72 if ( $this->format ===
null ) {
74 $format = $params[
'format'];
77 if ( !in_array( $format, $allowedParams[
'format'][ParamValidator::PARAM_TYPE] ) ) {
78 $format = $allowedParams[
'format'][ParamValidator::PARAM_DEFAULT];
81 if ( substr( $format, -2 ) ===
'fm' ) {
82 $this->format = substr( $format, 0, -2 );
85 $this->format = $format;
100 $printer = $this->
getMain()->createPrinterByName(
'xml' . $this->fm );
101 '@phan-var ApiFormatXml $printer';
103 $printer->setRootElement(
'SearchSuggestion' );
113 $search = $params[
'search'];
116 $this->
getMain()->setCacheMaxAge(
117 $this->
getConfig()->
get( MainConfigNames::SearchSuggestCacheExpiry ) );
118 $this->
getMain()->setCacheMode(
'public' );
119 $results = $this->search( $search, $params );
125 $length = $this->
getConfig()->get( MainConfigNames::OpenSearchDescriptionLength );
126 foreach ( $results as &$r ) {
127 if ( is_string( $r[
'extract'] ) && !$r[
'extract trimmed'] ) {
144 private function search( $search, array $params ) {
146 $titles = $searchEngine->extractTitles( $searchEngine->completionSearchWithVariants( $search ) );
156 $nextSpecialPageId = -1;
158 if ( $params[
'redirects'] ===
null ) {
160 $resolveRedir = $this->
getFormat() !==
'json';
162 $resolveRedir = $params[
'redirects'] ===
'resolve';
165 if ( $resolveRedir ) {
168 $lb = $this->linkBatchFactory->newLinkBatch( $titles );
169 if ( !$lb->isEmpty() ) {
170 $db = $this->
getDB();
171 $res = $db->newSelectQueryBuilder()
172 ->select( [
'page_namespace',
'page_title',
'rd_namespace',
'rd_title' ] )
175 'rd_interwiki IS NULL OR rd_interwiki = ' . $db->addQuotes(
'' ),
176 $lb->constructSet(
'page', $db )
178 ->join(
'redirect',
null, [
'rd_from = page_id' ] )
179 ->caller( __METHOD__ )
181 foreach (
$res as $row ) {
182 $redirects[$row->page_namespace][$row->page_title] =
183 [ $row->rd_namespace, $row->rd_title ];
189 foreach ( $titles as
$title ) {
190 $ns =
$title->getNamespace();
191 $dbkey =
$title->getDBkey();
193 if ( isset( $redirects[$ns][$dbkey] ) ) {
194 list( $ns, $dbkey ) = $redirects[$ns][$dbkey];
198 if ( !isset( $seen[$ns][$dbkey] ) ) {
199 $seen[$ns][$dbkey] =
true;
200 $resultId =
$title->getArticleID();
201 if ( $resultId === 0 ) {
202 $resultId = $nextSpecialPageId;
203 $nextSpecialPageId--;
205 $results[$resultId] = [
207 'redirect from' => $from,
209 'extract trimmed' =>
false,
216 foreach ( $titles as
$title ) {
217 $resultId =
$title->getArticleID();
218 if ( $resultId === 0 ) {
219 $resultId = $nextSpecialPageId;
220 $nextSpecialPageId--;
222 $results[$resultId] = [
224 'redirect from' =>
null,
226 'extract trimmed' =>
false,
246 $result->addArrayType(
null,
'array' );
247 $result->addValue(
null, 0, strval( $search ) );
251 foreach ( $results as $r ) {
252 $terms[] = $r[
'title']->getPrefixedText();
253 $descriptions[] = strval( $r[
'extract'] );
256 $result->addValue(
null, 1, $terms );
257 $result->addValue(
null, 2, $descriptions );
258 $result->addValue(
null, 3, $urls );
271 foreach ( $results as $r ) {
273 'Text' => $r[
'title']->getPrefixedText(),
276 if ( is_string( $r[
'extract'] ) && $r[
'extract'] !==
'' ) {
277 $item[
'Description'] = $r[
'extract'];
279 if ( is_array( $r[
'image'] ) && isset( $r[
'image'][
'source'] ) ) {
280 $item[
'Image'] = array_intersect_key( $r[
'image'], $imageKeys );
282 ApiResult::setSubelementsList( $item, array_keys( $item ) );
285 ApiResult::setIndexedTagName( $items,
'Item' );
286 $result->addValue(
null,
'version',
'2.0' );
287 $result->addValue(
null,
'xmlns',
'http://opensearch.org/searchsuggest2' );
288 $result->addValue(
null,
'Query', strval( $search ) );
289 $result->addSubelementsList(
null,
'Query' );
290 $result->addValue(
null,
'Section', $items );
299 if ( $this->allowedParams !==
null ) {
300 return $this->allowedParams;
304 ParamValidator::PARAM_DEFAULT =>
false,
306 ParamValidator::PARAM_DEPRECATED =>
true,
309 ParamValidator::PARAM_TYPE => [
'return',
'resolve' ],
314 ParamValidator::PARAM_DEFAULT =>
'json',
315 ParamValidator::PARAM_TYPE => [
'json',
'jsonfm',
'xml',
'xmlfm' ],
317 'warningsaserror' =>
false,
321 $this->allowedParams[
'limit'][ParamValidator::PARAM_DEFAULT] = $this->
getConfig()->get(
322 MainConfigNames::OpenSearchDefaultLimit
325 return $this->allowedParams;
331 'profile-type' => SearchEngine::COMPLETION_PROFILE_TYPE,
332 'help-message' =>
'apihelp-query+prefixsearch-param-profile'
339 'action=opensearch&search=Te'
340 =>
'apihelp-opensearch-example-te',
345 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Opensearch';
359 static $regex =
null;
361 if ( $regex ===
null ) {
363 '([^\d])\.\s',
'\!\s',
'\?\s',
368 $endgroup = implode(
'|', $endchars );
369 $end =
"(?:$endgroup)";
370 $sentence =
".{{$length},}?$end+";
371 $regex =
"/^($sentence)/u";
375 if ( preg_match( $regex, $text,
$matches ) ) {
379 return trim( explode(
"\n", $text )[0] );
391 $config = MediaWikiServices::getInstance()->getSearchEngineConfig();
392 $template = $config->getConfig()->get( MainConfigNames::OpenSearchTemplate );
394 if ( $template &&
$type ===
'application/x-suggestions+json' ) {
398 $ns = implode(
'|', $config->defaultNamespaces() );
404 case 'application/x-suggestions+json':
405 return $config->getConfig()->get( MainConfigNames::CanonicalServer ) .
406 wfScript(
'api' ) .
'?action=opensearch&search={searchTerms}&namespace=' . $ns;
408 case 'application/x-suggestions+xml':
409 return $config->getConfig()->get( MainConfigNames::CanonicalServer ) .
411 '?action=opensearch&format=xml&search={searchTerms}&namespace=' . $ns;
414 throw new MWException( __METHOD__ .
": Unknown type '$type'" );
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
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.
This abstract class implements many basic API functions, and is the base of all API classes.
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
getDB()
Gets a default replica DB connection object.
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
getMain()
Get the main module.
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
getResult()
Get the result object.
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
getHookRunner()
Get an ApiHookRunner for running core API hooks.
This is the main API class, used for both external and internal processing.
static trimExtract( $text, $length)
Trim an extract to a sensible length.
getHelpUrls()
Return links to more detailed help pages about the module.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getCustomPrinter()
If the module may only be used with a certain format module, it should override this method to return...
getExamplesMessages()
Returns usage examples for this module.
populateResult( $search, &$results)
__construct(ApiMain $mainModule, $moduleName, LinkBatchFactory $linkBatchFactory, SearchEngineConfig $searchEngineConfig, SearchEngineFactory $searchEngineFactory)
getFormat()
Get the output format.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
static getOpenSearchTemplate( $type)
Fetch the template for a type.
A class containing constants representing the names of configuration variables.
Configuration handling class for SearchEngine.
Factory class for SearchEngine.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
trait SearchApi
Traits for API components that use a SearchEngine.