66 'linktbl' =>
'pagelinks',
67 'helpurl' =>
'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Backlinks',
72 'linktbl' =>
'templatelinks',
73 'helpurl' =>
'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Embeddedin',
78 'linktbl' =>
'imagelinks',
79 'helpurl' =>
'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Imageusage',
88 $settings = $this->backlinksSettings[$moduleName];
89 $prefix = $settings[
'prefix'];
90 $code = $settings[
'code'];
91 $this->resultArr = [];
93 parent::__construct( $query, $moduleName, $code );
94 $this->bl_ns = $prefix .
'_namespace';
95 $this->bl_from = $prefix .
'_from';
96 $this->bl_from_ns = $prefix .
'_from_namespace';
97 $this->bl_table = $settings[
'linktbl'];
98 $this->bl_code = $code;
99 $this->helpUrl = $settings[
'helpurl'];
101 $this->hasNS = $moduleName !==
'imageusage';
102 if ( $this->hasNS ) {
103 $this->bl_title = $prefix .
'_title';
109 $this->bl_title = $prefix .
'_to';
125 $this->
run( $resultPageSet );
133 $this->
addTables( [ $this->bl_table,
'page' ] );
134 $this->
addWhere(
"{$this->bl_from}=page_id" );
135 if ( $resultPageSet ===
null ) {
136 $this->
addFields( [
'page_id',
'page_title',
'page_namespace' ] );
138 $this->
addFields( $resultPageSet->getPageTableFields() );
140 $this->
addFields( [
'page_is_redirect',
'from_ns' =>
'page_namespace' ] );
142 $this->
addWhereFld( $this->bl_title, $this->rootTitle->getDBkey() );
143 if ( $this->hasNS ) {
144 $this->
addWhereFld( $this->bl_ns, $this->rootTitle->getNamespace() );
146 $this->
addWhereFld( $this->bl_from_ns, $this->params[
'namespace'] );
148 if ( count( $this->cont ) >= 2 ) {
149 $op = $this->params[
'dir'] ==
'descending' ?
'<' :
'>';
150 if ( $this->params[
'namespace'] !==
null && count( $this->params[
'namespace'] ) > 1 ) {
152 "{$this->bl_from_ns} $op {$this->cont[0]} OR " .
153 "({$this->bl_from_ns} = {$this->cont[0]} AND " .
154 "{$this->bl_from} $op= {$this->cont[1]})"
157 $this->
addWhere(
"{$this->bl_from} $op= {$this->cont[1]}" );
161 if ( $this->params[
'filterredir'] ==
'redirects' ) {
163 } elseif ( $this->params[
'filterredir'] ==
'nonredirects' && !$this->redirect ) {
169 $this->
addOption(
'LIMIT', $this->params[
'limit'] + 1 );
170 $sort = ( $this->params[
'dir'] ==
'descending' ?
' DESC' :
'' );
172 if ( $this->params[
'namespace'] !==
null && count( $this->params[
'namespace'] ) > 1 ) {
173 $orderBy[] = $this->bl_from_ns . $sort;
175 $orderBy[] = $this->bl_from . $sort;
176 $this->
addOption(
'ORDER BY', $orderBy );
181 if ( $resultPageSet ===
null ) {
186 foreach (
$res as $row ) {
187 if ( ++$count > $this->params[
'limit'] ) {
191 $this->continueStr =
"{$row->from_ns}|{$row->page_id}";
196 if ( count( $this->cont ) < 2 ) {
197 $this->cont[] = $row->from_ns;
198 $this->cont[] = $row->page_id;
201 $this->pageMap[$row->page_namespace][$row->page_title] = $row->page_id;
203 if ( $row->page_is_redirect ) {
204 $this->redirTitles[] =
$t;
207 if ( $resultPageSet ===
null ) {
208 $a = [
'pageid' => (int)$row->page_id ];
210 if ( $row->page_is_redirect ) {
211 $a[
'redirect'] =
true;
214 $this->resultArr[$a[
'pageid']] = $a;
216 $resultPageSet->processDbRow( $row );
226 $db = $this->
getDB();
227 $this->
addTables( [ $this->bl_table,
'page' ] );
228 $this->
addWhere(
"{$this->bl_from}=page_id" );
230 if ( $resultPageSet ===
null ) {
231 $this->
addFields( [
'page_id',
'page_title',
'page_namespace',
'page_is_redirect' ] );
233 $this->
addFields( $resultPageSet->getPageTableFields() );
236 $this->
addFields( [ $this->bl_title,
'from_ns' =>
'page_namespace' ] );
237 if ( $this->hasNS ) {
246 foreach ( $this->redirTitles as
$t ) {
247 $redirNs =
$t->getNamespace();
248 $redirDBkey =
$t->getDBkey();
249 $titleWhere[] =
"{$this->bl_title} = " . $db->addQuotes( $redirDBkey ) .
250 ( $this->hasNS ?
" AND {$this->bl_ns} = {$redirNs}" :
'' );
251 $allRedirNs[$redirNs] =
true;
252 $allRedirDBkey[$redirDBkey] =
true;
255 $this->
addWhereFld(
'page_namespace', $this->params[
'namespace'] );
257 if ( count( $this->cont ) >= 6 ) {
258 $op = $this->params[
'dir'] ==
'descending' ?
'<' :
'>';
260 $where =
"{$this->bl_from} $op= {$this->cont[5]}";
263 if ( $this->params[
'namespace'] !==
null && count( $this->params[
'namespace'] ) > 1 ) {
264 $where =
"{$this->bl_from_ns} $op {$this->cont[4]} OR " .
265 "({$this->bl_from_ns} = {$this->cont[4]} AND ($where))";
267 if ( count( $allRedirDBkey ) > 1 ) {
268 $title = $db->addQuotes( $this->cont[3] );
269 $where =
"{$this->bl_title} $op $title OR " .
270 "({$this->bl_title} = $title AND ($where))";
272 if ( $this->hasNS && count( $allRedirNs ) > 1 ) {
273 $where =
"{$this->bl_ns} $op {$this->cont[2]} OR " .
274 "({$this->bl_ns} = {$this->cont[2]} AND ($where))";
279 if ( $this->params[
'filterredir'] ==
'redirects' ) {
281 } elseif ( $this->params[
'filterredir'] ==
'nonredirects' ) {
285 $this->
addOption(
'LIMIT', $this->params[
'limit'] + 1 );
287 $sort = ( $this->params[
'dir'] ==
'descending' ?
' DESC' :
'' );
289 if ( $this->hasNS && count( $allRedirNs ) > 1 ) {
290 $orderBy[] = $this->bl_ns . $sort;
292 if ( count( $allRedirDBkey ) > 1 ) {
293 $orderBy[] = $this->bl_title . $sort;
295 if ( $this->params[
'namespace'] !==
null && count( $this->params[
'namespace'] ) > 1 ) {
296 $orderBy[] = $this->bl_from_ns . $sort;
298 $orderBy[] = $this->bl_from . $sort;
299 $this->
addOption(
'ORDER BY', $orderBy );
300 $this->
addOption(
'USE INDEX', [
'page' =>
'PRIMARY' ] );
306 if ( $resultPageSet ===
null ) {
311 foreach (
$res as $row ) {
312 $ns = $this->hasNS ? $row->{$this->bl_ns} :
NS_FILE;
314 if ( ++$count > $this->params[
'limit'] ) {
319 $title = $row->{$this->bl_title};
320 $this->continueStr = implode(
'|', array_slice( $this->cont, 0, 2 ) ) .
321 "|$ns|$title|{$row->from_ns}|{$row->page_id}";
326 if ( count( $this->cont ) < 6 ) {
328 $this->cont[] = $row->{$this->bl_title};
329 $this->cont[] = $row->from_ns;
330 $this->cont[] = $row->page_id;
333 if ( $resultPageSet ===
null ) {
334 $a = [
'pageid' => (int)$row->page_id ];
336 if ( $row->page_is_redirect ) {
337 $a[
'redirect'] =
true;
339 $parentID = $this->pageMap[$ns][$row->{$this->bl_title}];
341 $this->resultArr[$parentID][
'redirlinks'][$row->page_id] = $a;
343 $resultPageSet->processDbRow( $row );
352 private function run( $resultPageSet =
null ) {
353 $this->params = $this->extractRequestParams(
false );
354 $this->redirect = isset( $this->params[
'redirect'] ) && $this->params[
'redirect'];
358 $result = $this->getResult();
360 if ( $this->params[
'limit'] ==
'max' ) {
361 $this->params[
'limit'] = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
362 $result->addParsedLimit( $this->getModuleName(), $this->params[
'limit'] );
364 $this->params[
'limit'] = $this->getMain()->getParamValidator()->validateValue(
365 $this,
'limit', (
int)$this->params[
'limit'], [
366 ParamValidator::PARAM_TYPE =>
'limit',
367 IntegerDef::PARAM_MIN => 1,
368 IntegerDef::PARAM_MAX => $userMax,
369 IntegerDef::PARAM_MAX2 => $botMax,
370 IntegerDef::PARAM_IGNORE_RANGE =>
true,
375 $this->rootTitle = $this->getTitleFromTitleOrPageId( $this->params );
378 if ( !$this->hasNS && $this->rootTitle->getNamespace() !==
NS_FILE ) {
380 [
'apierror-imageusage-badtitle', $this->getModuleName() ],
387 if ( $this->params[
'continue'] !==
null ) {
388 $cont = explode(
'|', $this->params[
'continue'] );
390 switch ( count( $cont ) ) {
393 $this->cont[7] = (int)$cont[7];
394 $this->dieContinueUsageIf( $cont[7] !== (
string)$this->cont[7] );
400 $this->cont[6] = (int)$cont[6];
401 $this->dieContinueUsageIf( $cont[6] !== (
string)$this->cont[6] );
407 $this->cont[2] = (int)$cont[2];
408 $this->dieContinueUsageIf( $cont[2] !== (
string)$this->cont[2] );
411 $this->cont[3] = $cont[3];
414 $this->cont[4] = (int)$cont[4];
415 $this->dieContinueUsageIf( $cont[4] !== (
string)$this->cont[4] );
418 $this->cont[5] = (int)$cont[5];
419 $this->dieContinueUsageIf( $cont[5] !== (
string)$this->cont[5] );
425 $this->cont[0] = (int)$cont[0];
426 $this->dieContinueUsageIf( $cont[0] !== (
string)$this->cont[0] );
429 $this->cont[1] = (int)$cont[1];
430 $this->dieContinueUsageIf( $cont[1] !== (
string)$this->cont[1] );
436 $this->dieContinueUsageIf(
true );
439 ksort( $this->cont );
442 $this->runFirstQuery( $resultPageSet );
443 if ( $this->redirect && count( $this->redirTitles ) ) {
444 $this->resetQueryParams();
445 $this->runSecondQuery( $resultPageSet );
449 $this->cont += [ 0, 0, 0,
'', 0, 0, 0 ];
451 if ( $resultPageSet ===
null ) {
453 $code = $this->bl_code;
454 $data = array_map(
static function ( $arr ) use ( $code ) {
455 if ( isset( $arr[
'redirlinks'] ) ) {
456 $arr[
'redirlinks'] = array_values( $arr[
'redirlinks'] );
460 }, array_values( $this->resultArr ) );
461 $fit = $result->addValue(
'query', $this->getModuleName(), $data );
465 ksort( $this->resultArr );
467 if ( count( $this->cont ) >= 7 ) {
468 $startAt = $this->cont[6];
470 reset( $this->resultArr );
471 $startAt = key( $this->resultArr );
474 foreach ( $this->resultArr as $pageID => $arr ) {
475 if ( $pageID < $startAt ) {
480 $fit = $result->addValue(
481 [
'query', $this->getModuleName() ],
482 $idx, array_diff_key( $arr, [
'redirlinks' =>
'' ] ) );
484 $this->continueStr = implode(
'|', array_slice( $this->cont, 0, 6 ) ) .
490 $redirLinks = isset( $arr[
'redirlinks'] ) ? (array)$arr[
'redirlinks'] : [];
491 ksort( $redirLinks );
493 if ( count( $this->cont ) >= 8 && $pageID == $startAt ) {
494 $redirStartAt = $this->cont[7];
496 reset( $redirLinks );
497 $redirStartAt = key( $redirLinks );
499 foreach ( $redirLinks as $key => $redir ) {
500 if ( $key < $redirStartAt ) {
504 $fit = $result->addValue(
505 [
'query', $this->getModuleName(), $idx,
'redirlinks' ],
508 $this->continueStr = implode(
'|', array_slice( $this->cont, 0, 6 ) ) .
515 $result->addIndexedTagName(
516 [
'query', $this->getModuleName(), $idx,
'redirlinks' ],
527 $result->addIndexedTagName(
528 [
'query', $this->getModuleName() ],
532 if ( $this->continueStr !==
null ) {
533 $this->setContinueEnumParameter(
'continue', $this->continueStr );
575 if ( $this->getModuleName() !==
'embeddedin' ) {
576 $retval[
'redirect'] =
false;
585 'action=query&list=backlinks&bltitle=Main%20Page'
586 =>
'apihelp-query+backlinks-example-simple',
587 'action=query&generator=backlinks&gbltitle=Main%20Page&prop=info'
588 =>
'apihelp-query+backlinks-example-generator',
591 'action=query&list=embeddedin&eititle=Template:Stub'
592 =>
'apihelp-query+embeddedin-example-simple',
593 'action=query&generator=embeddedin&geititle=Template:Stub&prop=info'
594 =>
'apihelp-query+embeddedin-example-generator',
597 'action=query&list=imageusage&iutitle=File:Albert%20Einstein%20Head.jpg'
598 =>
'apihelp-query+imageusage-example-simple',
599 'action=query&generator=imageusage&giutitle=File:Albert%20Einstein%20Head.jpg&prop=info'
600 =>
'apihelp-query+imageusage-example-generator',
604 return $examples[$this->getModuleName()];
608 return $this->helpUrl;
const LIMIT_BIG1
Fast query, standard limit.
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
const LIMIT_BIG2
Fast query, apihighlimits limit.
This is a three-in-one module to query:
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
array $pageMap
Maps ns and title to pageid.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getHelpUrls()
Return links to more detailed help pages about the module.
runFirstQuery( $resultPageSet=null)
run( $resultPageSet=null)
runSecondQuery( $resultPageSet=null)
__construct(ApiQuery $query, $moduleName)
getExamplesMessages()
Returns usage examples for this module.
getCacheMode( $params)
Get the cache mode for the data generated by this module.
string[][] $backlinksSettings
output element name, database column field prefix, database table
executeGenerator( $resultPageSet)
Execute this module as a generator.
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
addFields( $value)
Add a set of fields to select to the internal array.
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
getDB()
Get the Query database connection (read-only)
executeGenderCacheFromResultWrapper(IResultWrapper $res, $fname=__METHOD__, $fieldPrefix='page')
Preprocess the result set to fill the GenderCache with the necessary information before using self::a...
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
addWhere( $value)
Add a set of WHERE clauses to the internal array.
This is the main query class.
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.