Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 330 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
ApiQueryBacklinks | |
0.00% |
0 / 330 |
|
0.00% |
0 / 10 |
8372 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
12 | |||
execute | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getCacheMode | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
executeGenerator | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
runFirstQuery | |
0.00% |
0 / 56 |
|
0.00% |
0 / 1 |
462 | |||
runSecondQuery | |
0.00% |
0 / 80 |
|
0.00% |
0 / 1 |
812 | |||
run | |
0.00% |
0 / 109 |
|
0.00% |
0 / 1 |
1056 | |||
getAllowedParams | |
0.00% |
0 / 40 |
|
0.00% |
0 / 1 |
6 | |||
getExamplesMessages | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
2 | |||
getHelpUrls | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com" |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | */ |
22 | |
23 | use MediaWiki\Linker\LinksMigration; |
24 | use MediaWiki\Title\Title; |
25 | use Wikimedia\ParamValidator\ParamValidator; |
26 | use Wikimedia\ParamValidator\TypeDef\IntegerDef; |
27 | use Wikimedia\Rdbms\OrExpressionGroup; |
28 | |
29 | /** |
30 | * This is a three-in-one module to query: |
31 | * * backlinks - links pointing to the given page, |
32 | * * embeddedin - what pages transclude the given page within themselves, |
33 | * * imageusage - what pages use the given image |
34 | * |
35 | * @ingroup API |
36 | */ |
37 | class ApiQueryBacklinks extends ApiQueryGeneratorBase { |
38 | |
39 | /** |
40 | * @var Title |
41 | */ |
42 | private $rootTitle; |
43 | |
44 | /** |
45 | * @var LinksMigration |
46 | */ |
47 | private $linksMigration; |
48 | |
49 | private $params; |
50 | /** @var array */ |
51 | private $cont; |
52 | private $redirect; |
53 | private $bl_ns, $bl_from, $bl_from_ns, $bl_table, $bl_code, $bl_title, $hasNS; |
54 | |
55 | /** @var string */ |
56 | private $helpUrl; |
57 | |
58 | /** |
59 | * Maps ns and title to pageid |
60 | * |
61 | * @var array |
62 | */ |
63 | private $pageMap = []; |
64 | private $resultArr; |
65 | |
66 | private $redirTitles = []; |
67 | private $continueStr = null; |
68 | |
69 | /** @var string[][] output element name, database column field prefix, database table */ |
70 | private $backlinksSettings = [ |
71 | 'backlinks' => [ |
72 | 'code' => 'bl', |
73 | 'prefix' => 'pl', |
74 | 'linktbl' => 'pagelinks', |
75 | 'helpurl' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Backlinks', |
76 | ], |
77 | 'embeddedin' => [ |
78 | 'code' => 'ei', |
79 | 'prefix' => 'tl', |
80 | 'linktbl' => 'templatelinks', |
81 | 'helpurl' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Embeddedin', |
82 | ], |
83 | 'imageusage' => [ |
84 | 'code' => 'iu', |
85 | 'prefix' => 'il', |
86 | 'linktbl' => 'imagelinks', |
87 | 'helpurl' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Imageusage', |
88 | ] |
89 | ]; |
90 | |
91 | /** |
92 | * @param ApiQuery $query |
93 | * @param string $moduleName |
94 | * @param LinksMigration $linksMigration |
95 | */ |
96 | public function __construct( ApiQuery $query, $moduleName, LinksMigration $linksMigration ) { |
97 | $settings = $this->backlinksSettings[$moduleName]; |
98 | $prefix = $settings['prefix']; |
99 | $code = $settings['code']; |
100 | $this->resultArr = []; |
101 | |
102 | parent::__construct( $query, $moduleName, $code ); |
103 | $this->bl_table = $settings['linktbl']; |
104 | $this->hasNS = $moduleName !== 'imageusage'; |
105 | $this->linksMigration = $linksMigration; |
106 | if ( isset( $this->linksMigration::$mapping[$this->bl_table] ) ) { |
107 | [ $this->bl_ns, $this->bl_title ] = $this->linksMigration->getTitleFields( $this->bl_table ); |
108 | } else { |
109 | $this->bl_ns = $prefix . '_namespace'; |
110 | if ( $this->hasNS ) { |
111 | $this->bl_title = $prefix . '_title'; |
112 | } else { |
113 | $this->bl_title = $prefix . '_to'; |
114 | } |
115 | } |
116 | $this->bl_from = $prefix . '_from'; |
117 | $this->bl_from_ns = $prefix . '_from_namespace'; |
118 | $this->bl_code = $code; |
119 | $this->helpUrl = $settings['helpurl']; |
120 | } |
121 | |
122 | public function execute() { |
123 | $this->run(); |
124 | } |
125 | |
126 | public function getCacheMode( $params ) { |
127 | return 'public'; |
128 | } |
129 | |
130 | public function executeGenerator( $resultPageSet ) { |
131 | $this->run( $resultPageSet ); |
132 | } |
133 | |
134 | /** |
135 | * @param ApiPageSet|null $resultPageSet |
136 | * @return void |
137 | */ |
138 | private function runFirstQuery( $resultPageSet = null ) { |
139 | $this->addTables( [ $this->bl_table, 'page' ] ); |
140 | $this->addWhere( "{$this->bl_from}=page_id" ); |
141 | if ( $resultPageSet === null ) { |
142 | $this->addFields( [ 'page_id', 'page_title', 'page_namespace' ] ); |
143 | } else { |
144 | $this->addFields( $resultPageSet->getPageTableFields() ); |
145 | } |
146 | $this->addFields( [ 'page_is_redirect', 'from_ns' => 'page_namespace' ] ); |
147 | |
148 | if ( isset( $this->linksMigration::$mapping[$this->bl_table] ) ) { |
149 | $conds = $this->linksMigration->getLinksConditions( $this->bl_table, $this->rootTitle ); |
150 | $this->addWhere( $conds ); |
151 | } else { |
152 | $this->addWhereFld( $this->bl_title, $this->rootTitle->getDBkey() ); |
153 | if ( $this->hasNS ) { |
154 | $this->addWhereFld( $this->bl_ns, $this->rootTitle->getNamespace() ); |
155 | } |
156 | } |
157 | |
158 | $this->addWhereFld( $this->bl_from_ns, $this->params['namespace'] ); |
159 | |
160 | if ( count( $this->cont ) >= 2 ) { |
161 | $db = $this->getDB(); |
162 | $op = $this->params['dir'] == 'descending' ? '<=' : '>='; |
163 | if ( $this->params['namespace'] !== null && count( $this->params['namespace'] ) > 1 ) { |
164 | $this->addWhere( $db->buildComparison( $op, [ |
165 | $this->bl_from_ns => $this->cont[0], |
166 | $this->bl_from => $this->cont[1], |
167 | ] ) ); |
168 | } else { |
169 | $this->addWhere( $db->buildComparison( $op, [ $this->bl_from => $this->cont[1] ] ) ); |
170 | } |
171 | } |
172 | |
173 | if ( $this->params['filterredir'] == 'redirects' ) { |
174 | $this->addWhereFld( 'page_is_redirect', 1 ); |
175 | } elseif ( $this->params['filterredir'] == 'nonredirects' && !$this->redirect ) { |
176 | // T24245 - Check for !redirect, as filtering nonredirects, when |
177 | // getting what links to them is contradictory |
178 | $this->addWhereFld( 'page_is_redirect', 0 ); |
179 | } |
180 | |
181 | $this->addOption( 'LIMIT', $this->params['limit'] + 1 ); |
182 | $sort = ( $this->params['dir'] == 'descending' ? ' DESC' : '' ); |
183 | $orderBy = []; |
184 | if ( $this->params['namespace'] !== null && count( $this->params['namespace'] ) > 1 ) { |
185 | $orderBy[] = $this->bl_from_ns . $sort; |
186 | } |
187 | $orderBy[] = $this->bl_from . $sort; |
188 | $this->addOption( 'ORDER BY', $orderBy ); |
189 | $this->addOption( 'STRAIGHT_JOIN' ); |
190 | |
191 | $res = $this->select( __METHOD__ ); |
192 | |
193 | if ( $resultPageSet === null ) { |
194 | $this->executeGenderCacheFromResultWrapper( $res, __METHOD__ ); |
195 | } |
196 | |
197 | $count = 0; |
198 | foreach ( $res as $row ) { |
199 | if ( ++$count > $this->params['limit'] ) { |
200 | // We've reached the one extra which shows that there are |
201 | // additional pages to be had. Stop here... |
202 | // Continue string may be overridden at a later step |
203 | $this->continueStr = "{$row->from_ns}|{$row->page_id}"; |
204 | break; |
205 | } |
206 | |
207 | // Fill in continuation fields for later steps |
208 | if ( count( $this->cont ) < 2 ) { |
209 | $this->cont[] = $row->from_ns; |
210 | $this->cont[] = $row->page_id; |
211 | } |
212 | |
213 | $this->pageMap[$row->page_namespace][$row->page_title] = $row->page_id; |
214 | $t = Title::makeTitle( $row->page_namespace, $row->page_title ); |
215 | if ( $row->page_is_redirect ) { |
216 | $this->redirTitles[] = $t; |
217 | } |
218 | |
219 | if ( $resultPageSet === null ) { |
220 | $a = [ 'pageid' => (int)$row->page_id ]; |
221 | ApiQueryBase::addTitleInfo( $a, $t ); |
222 | if ( $row->page_is_redirect ) { |
223 | $a['redirect'] = true; |
224 | } |
225 | // Put all the results in an array first |
226 | $this->resultArr[$a['pageid']] = $a; |
227 | } else { |
228 | $resultPageSet->processDbRow( $row ); |
229 | } |
230 | } |
231 | } |
232 | |
233 | /** |
234 | * @param ApiPageSet|null $resultPageSet |
235 | * @return void |
236 | */ |
237 | private function runSecondQuery( $resultPageSet = null ) { |
238 | $db = $this->getDB(); |
239 | if ( isset( $this->linksMigration::$mapping[$this->bl_table] ) ) { |
240 | $queryInfo = $this->linksMigration->getQueryInfo( $this->bl_table, $this->bl_table ); |
241 | $this->addTables( $queryInfo['tables'] ); |
242 | $this->addJoinConds( $queryInfo['joins'] ); |
243 | } else { |
244 | $this->addTables( [ $this->bl_table ] ); |
245 | } |
246 | $this->addTables( [ 'page' ] ); |
247 | $this->addJoinConds( [ 'page' => [ 'JOIN', "{$this->bl_from}=page_id" ] ] ); |
248 | |
249 | if ( $resultPageSet === null ) { |
250 | $this->addFields( [ 'page_id', 'page_title', 'page_namespace', 'page_is_redirect' ] ); |
251 | } else { |
252 | $this->addFields( $resultPageSet->getPageTableFields() ); |
253 | } |
254 | |
255 | $this->addFields( [ $this->bl_title, 'from_ns' => 'page_namespace' ] ); |
256 | if ( $this->hasNS ) { |
257 | $this->addFields( $this->bl_ns ); |
258 | } |
259 | |
260 | // We can't use LinkBatch here because $this->hasNS may be false |
261 | $titleWhere = []; |
262 | $allRedirNs = []; |
263 | $allRedirDBkey = []; |
264 | /** @var Title $t */ |
265 | foreach ( $this->redirTitles as $t ) { |
266 | $redirNs = $t->getNamespace(); |
267 | $redirDBkey = $t->getDBkey(); |
268 | $expr = $db->expr( $this->bl_title, '=', $redirDBkey ); |
269 | if ( $this->hasNS ) { |
270 | $expr = $expr->and( $this->bl_ns, '=', $redirNs ); |
271 | } |
272 | $titleWhere[] = $expr; |
273 | $allRedirNs[$redirNs] = true; |
274 | $allRedirDBkey[$redirDBkey] = true; |
275 | } |
276 | $this->addWhere( new OrExpressionGroup( ...$titleWhere ) ); |
277 | $this->addWhereFld( 'page_namespace', $this->params['namespace'] ); |
278 | |
279 | if ( count( $this->cont ) >= 6 ) { |
280 | $op = $this->params['dir'] == 'descending' ? '<=' : '>='; |
281 | |
282 | $conds = []; |
283 | if ( $this->hasNS && count( $allRedirNs ) > 1 ) { |
284 | $conds[ $this->bl_ns ] = $this->cont[2]; |
285 | } |
286 | if ( count( $allRedirDBkey ) > 1 ) { |
287 | $conds[ $this->bl_title ] = $this->cont[3]; |
288 | } |
289 | // Don't bother with namespace, title, or from_namespace if it's |
290 | // otherwise constant in the where clause. |
291 | if ( $this->params['namespace'] !== null && count( $this->params['namespace'] ) > 1 ) { |
292 | $conds[ $this->bl_from_ns ] = $this->cont[4]; |
293 | } |
294 | $conds[ $this->bl_from ] = $this->cont[5]; |
295 | |
296 | $this->addWhere( $db->buildComparison( $op, $conds ) ); |
297 | } |
298 | if ( $this->params['filterredir'] == 'redirects' ) { |
299 | $this->addWhereFld( 'page_is_redirect', 1 ); |
300 | } elseif ( $this->params['filterredir'] == 'nonredirects' ) { |
301 | $this->addWhereFld( 'page_is_redirect', 0 ); |
302 | } |
303 | |
304 | $this->addOption( 'LIMIT', $this->params['limit'] + 1 ); |
305 | $orderBy = []; |
306 | $sort = ( $this->params['dir'] == 'descending' ? ' DESC' : '' ); |
307 | // Don't order by namespace/title/from_namespace if it's constant in the WHERE clause |
308 | if ( $this->hasNS && count( $allRedirNs ) > 1 ) { |
309 | $orderBy[] = $this->bl_ns . $sort; |
310 | } |
311 | if ( count( $allRedirDBkey ) > 1 ) { |
312 | $orderBy[] = $this->bl_title . $sort; |
313 | } |
314 | if ( $this->params['namespace'] !== null && count( $this->params['namespace'] ) > 1 ) { |
315 | $orderBy[] = $this->bl_from_ns . $sort; |
316 | } |
317 | $orderBy[] = $this->bl_from . $sort; |
318 | $this->addOption( 'ORDER BY', $orderBy ); |
319 | $this->addOption( 'USE INDEX', [ 'page' => 'PRIMARY' ] ); |
320 | // T290379: Avoid MariaDB deciding to scan all of `page`. |
321 | $this->addOption( 'STRAIGHT_JOIN' ); |
322 | |
323 | $res = $this->select( __METHOD__ ); |
324 | |
325 | if ( $resultPageSet === null ) { |
326 | $this->executeGenderCacheFromResultWrapper( $res, __METHOD__ ); |
327 | } |
328 | |
329 | $count = 0; |
330 | foreach ( $res as $row ) { |
331 | $ns = $this->hasNS ? $row->{$this->bl_ns} : NS_FILE; |
332 | |
333 | if ( ++$count > $this->params['limit'] ) { |
334 | // We've reached the one extra which shows that there are |
335 | // additional pages to be had. Stop here... |
336 | // Note we must keep the parameters for the first query constant |
337 | // This may be overridden at a later step |
338 | $title = $row->{$this->bl_title}; |
339 | $this->continueStr = implode( '|', array_slice( $this->cont, 0, 2 ) ) . |
340 | "|$ns|$title|{$row->from_ns}|{$row->page_id}"; |
341 | break; |
342 | } |
343 | |
344 | // Fill in continuation fields for later steps |
345 | if ( count( $this->cont ) < 6 ) { |
346 | $this->cont[] = $ns; |
347 | $this->cont[] = $row->{$this->bl_title}; |
348 | $this->cont[] = $row->from_ns; |
349 | $this->cont[] = $row->page_id; |
350 | } |
351 | |
352 | if ( $resultPageSet === null ) { |
353 | $a = [ 'pageid' => (int)$row->page_id ]; |
354 | ApiQueryBase::addTitleInfo( $a, Title::makeTitle( $row->page_namespace, $row->page_title ) ); |
355 | if ( $row->page_is_redirect ) { |
356 | $a['redirect'] = true; |
357 | } |
358 | $parentID = $this->pageMap[$ns][$row->{$this->bl_title}]; |
359 | // Put all the results in an array first |
360 | $this->resultArr[$parentID]['redirlinks'][$row->page_id] = $a; |
361 | } else { |
362 | $resultPageSet->processDbRow( $row ); |
363 | } |
364 | } |
365 | } |
366 | |
367 | /** |
368 | * @param ApiPageSet|null $resultPageSet |
369 | * @return void |
370 | */ |
371 | private function run( $resultPageSet = null ) { |
372 | $this->params = $this->extractRequestParams( false ); |
373 | $this->redirect = isset( $this->params['redirect'] ) && $this->params['redirect']; |
374 | $userMax = ( $this->redirect ? ApiBase::LIMIT_BIG1 / 2 : ApiBase::LIMIT_BIG1 ); |
375 | $botMax = ( $this->redirect ? ApiBase::LIMIT_BIG2 / 2 : ApiBase::LIMIT_BIG2 ); |
376 | |
377 | $result = $this->getResult(); |
378 | |
379 | if ( $this->params['limit'] == 'max' ) { |
380 | $this->params['limit'] = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; |
381 | $result->addParsedLimit( $this->getModuleName(), $this->params['limit'] ); |
382 | } else { |
383 | $this->params['limit'] = $this->getMain()->getParamValidator()->validateValue( |
384 | $this, 'limit', (int)$this->params['limit'], [ |
385 | ParamValidator::PARAM_TYPE => 'limit', |
386 | IntegerDef::PARAM_MIN => 1, |
387 | IntegerDef::PARAM_MAX => $userMax, |
388 | IntegerDef::PARAM_MAX2 => $botMax, |
389 | IntegerDef::PARAM_IGNORE_RANGE => true, |
390 | ] |
391 | ); |
392 | } |
393 | |
394 | $this->rootTitle = $this->getTitleFromTitleOrPageId( $this->params ); |
395 | |
396 | // only image titles are allowed for the root in imageinfo mode |
397 | if ( !$this->hasNS && $this->rootTitle->getNamespace() !== NS_FILE ) { |
398 | $this->dieWithError( |
399 | [ 'apierror-imageusage-badtitle', $this->getModuleName() ], |
400 | 'bad_image_title' |
401 | ); |
402 | } |
403 | |
404 | // Parse and validate continuation parameter |
405 | // (Can't use parseContinueParamOrDie(), because the length is variable) |
406 | $this->cont = []; |
407 | if ( $this->params['continue'] !== null ) { |
408 | $cont = explode( '|', $this->params['continue'] ); |
409 | |
410 | switch ( count( $cont ) ) { |
411 | case 8: |
412 | // redirect page ID for result adding |
413 | $this->cont[7] = (int)$cont[7]; |
414 | $this->dieContinueUsageIf( $cont[7] !== (string)$this->cont[7] ); |
415 | |
416 | /* Fall through */ |
417 | |
418 | case 7: |
419 | // top-level page ID for result adding |
420 | $this->cont[6] = (int)$cont[6]; |
421 | $this->dieContinueUsageIf( $cont[6] !== (string)$this->cont[6] ); |
422 | |
423 | /* Fall through */ |
424 | |
425 | case 6: |
426 | // ns for 2nd query (even for imageusage) |
427 | $this->cont[2] = (int)$cont[2]; |
428 | $this->dieContinueUsageIf( $cont[2] !== (string)$this->cont[2] ); |
429 | |
430 | // title for 2nd query |
431 | $this->cont[3] = $cont[3]; |
432 | |
433 | // from_ns for 2nd query |
434 | $this->cont[4] = (int)$cont[4]; |
435 | $this->dieContinueUsageIf( $cont[4] !== (string)$this->cont[4] ); |
436 | |
437 | // from_id for 1st query |
438 | $this->cont[5] = (int)$cont[5]; |
439 | $this->dieContinueUsageIf( $cont[5] !== (string)$this->cont[5] ); |
440 | |
441 | /* Fall through */ |
442 | |
443 | case 2: |
444 | // from_ns for 1st query |
445 | $this->cont[0] = (int)$cont[0]; |
446 | $this->dieContinueUsageIf( $cont[0] !== (string)$this->cont[0] ); |
447 | |
448 | // from_id for 1st query |
449 | $this->cont[1] = (int)$cont[1]; |
450 | $this->dieContinueUsageIf( $cont[1] !== (string)$this->cont[1] ); |
451 | |
452 | break; |
453 | |
454 | default: |
455 | // @phan-suppress-next-line PhanImpossibleCondition |
456 | $this->dieContinueUsageIf( true ); |
457 | } |
458 | |
459 | ksort( $this->cont ); |
460 | } |
461 | |
462 | $this->runFirstQuery( $resultPageSet ); |
463 | if ( $this->redirect && count( $this->redirTitles ) ) { |
464 | $this->resetQueryParams(); |
465 | $this->runSecondQuery( $resultPageSet ); |
466 | } |
467 | |
468 | // Fill in any missing fields in case it's needed below |
469 | $this->cont += [ 0, 0, 0, '', 0, 0, 0 ]; |
470 | |
471 | if ( $resultPageSet === null ) { |
472 | // Try to add the result data in one go and pray that it fits |
473 | $code = $this->bl_code; |
474 | $data = array_map( static function ( $arr ) use ( $code ) { |
475 | if ( isset( $arr['redirlinks'] ) ) { |
476 | $arr['redirlinks'] = array_values( $arr['redirlinks'] ); |
477 | ApiResult::setIndexedTagName( $arr['redirlinks'], $code ); |
478 | } |
479 | return $arr; |
480 | }, array_values( $this->resultArr ) ); |
481 | $fit = $result->addValue( 'query', $this->getModuleName(), $data ); |
482 | if ( !$fit ) { |
483 | // It didn't fit. Add elements one by one until the |
484 | // result is full. |
485 | ksort( $this->resultArr ); |
486 | // @phan-suppress-next-line PhanSuspiciousValueComparison |
487 | if ( count( $this->cont ) >= 7 ) { |
488 | $startAt = $this->cont[6]; |
489 | } else { |
490 | $startAt = array_key_first( $this->resultArr ); |
491 | } |
492 | $idx = 0; |
493 | foreach ( $this->resultArr as $pageID => $arr ) { |
494 | if ( $pageID < $startAt ) { |
495 | continue; |
496 | } |
497 | |
498 | // Add the basic entry without redirlinks first |
499 | $fit = $result->addValue( |
500 | [ 'query', $this->getModuleName() ], |
501 | $idx, array_diff_key( $arr, [ 'redirlinks' => '' ] ) ); |
502 | if ( !$fit ) { |
503 | $this->continueStr = implode( '|', array_slice( $this->cont, 0, 6 ) ) . |
504 | "|$pageID"; |
505 | break; |
506 | } |
507 | |
508 | $hasRedirs = false; |
509 | $redirLinks = isset( $arr['redirlinks'] ) ? (array)$arr['redirlinks'] : []; |
510 | ksort( $redirLinks ); |
511 | // @phan-suppress-next-line PhanSuspiciousValueComparisonInLoop |
512 | if ( count( $this->cont ) >= 8 && $pageID == $startAt ) { |
513 | $redirStartAt = $this->cont[7]; |
514 | } else { |
515 | $redirStartAt = array_key_first( $redirLinks ); |
516 | } |
517 | foreach ( $redirLinks as $key => $redir ) { |
518 | if ( $key < $redirStartAt ) { |
519 | continue; |
520 | } |
521 | |
522 | $fit = $result->addValue( |
523 | [ 'query', $this->getModuleName(), $idx, 'redirlinks' ], |
524 | null, $redir ); |
525 | if ( !$fit ) { |
526 | $this->continueStr = implode( '|', array_slice( $this->cont, 0, 6 ) ) . |
527 | "|$pageID|$key"; |
528 | break; |
529 | } |
530 | $hasRedirs = true; |
531 | } |
532 | if ( $hasRedirs ) { |
533 | $result->addIndexedTagName( |
534 | [ 'query', $this->getModuleName(), $idx, 'redirlinks' ], |
535 | $this->bl_code ); |
536 | } |
537 | if ( !$fit ) { |
538 | break; |
539 | } |
540 | |
541 | $idx++; |
542 | } |
543 | } |
544 | |
545 | $result->addIndexedTagName( |
546 | [ 'query', $this->getModuleName() ], |
547 | $this->bl_code |
548 | ); |
549 | } |
550 | if ( $this->continueStr !== null ) { |
551 | $this->setContinueEnumParameter( 'continue', $this->continueStr ); |
552 | } |
553 | } |
554 | |
555 | public function getAllowedParams() { |
556 | $retval = [ |
557 | 'title' => [ |
558 | ParamValidator::PARAM_TYPE => 'string', |
559 | ], |
560 | 'pageid' => [ |
561 | ParamValidator::PARAM_TYPE => 'integer', |
562 | ], |
563 | 'continue' => [ |
564 | ApiBase::PARAM_HELP_MSG => 'api-help-param-continue', |
565 | ], |
566 | 'namespace' => [ |
567 | ParamValidator::PARAM_ISMULTI => true, |
568 | ParamValidator::PARAM_TYPE => 'namespace' |
569 | ], |
570 | 'dir' => [ |
571 | ParamValidator::PARAM_DEFAULT => 'ascending', |
572 | ParamValidator::PARAM_TYPE => [ |
573 | 'ascending', |
574 | 'descending' |
575 | ] |
576 | ], |
577 | 'filterredir' => [ |
578 | ParamValidator::PARAM_DEFAULT => 'all', |
579 | ParamValidator::PARAM_TYPE => [ |
580 | 'all', |
581 | 'redirects', |
582 | 'nonredirects' |
583 | ] |
584 | ], |
585 | 'limit' => [ |
586 | ParamValidator::PARAM_DEFAULT => 10, |
587 | ParamValidator::PARAM_TYPE => 'limit', |
588 | IntegerDef::PARAM_MIN => 1, |
589 | IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1, |
590 | IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2 |
591 | ] |
592 | ]; |
593 | if ( $this->getModuleName() !== 'embeddedin' ) { |
594 | $retval['redirect'] = false; |
595 | } |
596 | |
597 | return $retval; |
598 | } |
599 | |
600 | protected function getExamplesMessages() { |
601 | $title = Title::newMainPage()->getPrefixedText(); |
602 | $mp = rawurlencode( $title ); |
603 | $examples = [ |
604 | 'backlinks' => [ |
605 | "action=query&list=backlinks&bltitle={$mp}" |
606 | => 'apihelp-query+backlinks-example-simple', |
607 | "action=query&generator=backlinks&gbltitle={$mp}&prop=info" |
608 | => 'apihelp-query+backlinks-example-generator', |
609 | ], |
610 | 'embeddedin' => [ |
611 | 'action=query&list=embeddedin&eititle=Template:Stub' |
612 | => 'apihelp-query+embeddedin-example-simple', |
613 | 'action=query&generator=embeddedin&geititle=Template:Stub&prop=info' |
614 | => 'apihelp-query+embeddedin-example-generator', |
615 | ], |
616 | 'imageusage' => [ |
617 | 'action=query&list=imageusage&iutitle=File:Albert%20Einstein%20Head.jpg' |
618 | => 'apihelp-query+imageusage-example-simple', |
619 | 'action=query&generator=imageusage&giutitle=File:Albert%20Einstein%20Head.jpg&prop=info' |
620 | => 'apihelp-query+imageusage-example-generator', |
621 | ] |
622 | ]; |
623 | |
624 | return $examples[$this->getModuleName()]; |
625 | } |
626 | |
627 | public function getHelpUrls() { |
628 | return $this->helpUrl; |
629 | } |
630 | } |