MediaWiki master
ApiQueryDeletedrevs.php
Go to the documentation of this file.
1<?php
9namespace MediaWiki\Api;
10
28use Wikimedia\Timestamp\TimestampFormat as TS;
29
37
38 private CommentStore $commentStore;
39 private RowCommentFormatter $commentFormatter;
40 private RevisionStore $revisionStore;
41 private NameTableStore $changeTagDefStore;
42 private ChangeTagsStore $changeTagsStore;
43 private LinkBatchFactory $linkBatchFactory;
44
45 public function __construct(
46 ApiQuery $query,
47 string $moduleName,
48 CommentStore $commentStore,
49 RowCommentFormatter $commentFormatter,
50 RevisionStore $revisionStore,
51 NameTableStore $changeTagDefStore,
52 ChangeTagsStore $changeTagsStore,
53 LinkBatchFactory $linkBatchFactory
54 ) {
55 parent::__construct( $query, $moduleName, 'dr' );
56 $this->commentStore = $commentStore;
57 $this->commentFormatter = $commentFormatter;
58 $this->revisionStore = $revisionStore;
59 $this->changeTagDefStore = $changeTagDefStore;
60 $this->changeTagsStore = $changeTagsStore;
61 $this->linkBatchFactory = $linkBatchFactory;
62 }
63
64 public function execute() {
65 // Before doing anything at all, let's check permissions
66 $this->checkUserRightsAny( 'deletedhistory' );
67
68 $this->addDeprecation( 'apiwarn-deprecation-deletedrevs', 'action=query&list=deletedrevs' );
69
70 $user = $this->getUser();
71 $db = $this->getDB();
72 $params = $this->extractRequestParams( false );
73 $prop = array_fill_keys( $params['prop'], true );
74 $fld_parentid = isset( $prop['parentid'] );
75 $fld_revid = isset( $prop['revid'] );
76 $fld_user = isset( $prop['user'] );
77 $fld_userid = isset( $prop['userid'] );
78 $fld_comment = isset( $prop['comment'] );
79 $fld_parsedcomment = isset( $prop['parsedcomment'] );
80 $fld_minor = isset( $prop['minor'] );
81 $fld_len = isset( $prop['len'] );
82 $fld_sha1 = isset( $prop['sha1'] );
83 $fld_content = isset( $prop['content'] );
84 $fld_token = isset( $prop['token'] );
85 $fld_tags = isset( $prop['tags'] );
86
87 // If we're in a mode that breaks the same-origin policy, no tokens can
88 // be obtained
89 if ( $this->lacksSameOriginSecurity() ||
90 // If user can't undelete, no tokens
91 !$this->getAuthority()->isAllowed( 'undelete' )
92 ) {
93 $fld_token = false;
94 }
95
96 $result = $this->getResult();
97 $pageSet = $this->getPageSet();
98 $titles = $pageSet->getPages();
99
100 // This module operates in three modes:
101 // 'revs': List deleted revs for certain titles (1)
102 // 'user': List deleted revs by a certain user (2)
103 // 'all': List all deleted revs in NS (3)
104 $mode = 'all';
105 if ( count( $titles ) > 0 ) {
106 $mode = 'revs';
107 } elseif ( $params['user'] !== null ) {
108 $mode = 'user';
109 }
110
111 if ( $mode == 'revs' || $mode == 'user' ) {
112 // Ignore namespace and unique due to inability to know whether they were purposely set
113 foreach ( [ 'from', 'to', 'prefix', /*'namespace', 'unique'*/ ] as $p ) {
114 if ( $params[$p] !== null ) {
115 $this->dieWithError( [ 'apierror-deletedrevs-param-not-1-2', $p ], 'badparams' );
116 }
117 }
118 } else {
119 foreach ( [ 'start', 'end' ] as $p ) {
120 if ( $params[$p] !== null ) {
121 $this->dieWithError( [ 'apierror-deletedrevs-param-not-3', $p ], 'badparams' );
122 }
123 }
124 }
125
126 if ( $params['user'] !== null && $params['excludeuser'] !== null ) {
127 $this->dieWithError( 'user and excludeuser cannot be used together', 'badparams' );
128 }
129
130 $arQuery = $this->revisionStore->getArchiveQueryInfo();
131 $this->addTables( $arQuery['tables'] );
132 $this->addFields( $arQuery['fields'] );
133 $this->addJoinConds( $arQuery['joins'] );
134 $this->addFields( [ 'ar_title', 'ar_namespace' ] );
135
136 if ( $fld_tags ) {
137 $this->addFields( [
138 'ts_tags' => $this->changeTagsStore->makeTagSummarySubquery( 'archive' )
139 ] );
140 }
141
142 if ( $fld_sha1 ) {
143 $pairExpr = $db->buildGroupConcat(
144 $db->buildConcat( [ 'sr.role_name', $db->addQuotes( ':' ), 'c.content_sha1' ] ),
145 ','
146 );
147 $sha1Subquery = $db->newSelectQueryBuilder()
148 ->select( [
149 'ar_rev_id',
150 'ar_deleted',
151 'ar_slot_pairs' => $pairExpr,
152 ] )
153 ->from( 'archive' )
154 ->join( 'slots', 's', [ 'ar_rev_id = s.slot_revision_id' ] )
155 ->join( 'content', 'c', [ 's.slot_content_id = c.content_id' ] )
156 ->join( 'slot_roles', 'sr', [ 's.slot_role_id = sr.role_id' ] )
157 ->groupBy( [ 'ar_rev_id', 'ar_deleted' ] )
158 ->caller( __METHOD__ )
159 ->getSQL();
160
161 $this->addTables( [ 'arsha1' => new Subquery( $sha1Subquery ) ] );
162 $this->addFields( [
163 'ar_deleted' => 'arsha1.ar_deleted',
164 'ar_slot_pairs' => 'arsha1.ar_slot_pairs'
165 ] );
166 $this->addJoinConds( [ 'arsha1' => [ 'LEFT JOIN', [ 'ar_rev_id = arsha1.ar_rev_id' ] ] ] );
167 }
168
169 if ( $params['tag'] !== null ) {
170 $this->addTables( 'change_tag' );
171 $this->addJoinConds(
172 [ 'change_tag' => [ 'JOIN', [ 'ar_rev_id=ct_rev_id' ] ] ]
173 );
174 try {
175 $this->addWhereFld( 'ct_tag_id', $this->changeTagDefStore->getId( $params['tag'] ) );
176 } catch ( NameTableAccessException ) {
177 // Return nothing.
178 $this->addWhere( '1=0' );
179 }
180 }
181
182 // This means stricter restrictions
183 if ( $fld_content ) {
184 $this->checkUserRightsAny( [ 'deletedtext', 'undelete' ] );
185 }
186 // Check limits
187 $userMax = $fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1;
188 $botMax = $fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2;
189
190 $limit = $params['limit'];
191
192 if ( $limit == 'max' ) {
193 $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
194 $this->getResult()->addParsedLimit( $this->getModuleName(), $limit );
195 }
196
197 $limit = $this->getMain()->getParamValidator()->validateValue(
198 $this, 'limit', $limit, [
199 ParamValidator::PARAM_TYPE => 'limit',
200 IntegerDef::PARAM_MIN => 1,
201 IntegerDef::PARAM_MAX => $userMax,
202 IntegerDef::PARAM_MAX2 => $botMax,
203 IntegerDef::PARAM_IGNORE_RANGE => true,
204 ]
205 );
206
207 if ( $fld_token ) {
208 // Undelete tokens are identical for all pages, so we cache one here
209 $token = $user->getEditToken( '', $this->getMain()->getRequest() );
210 }
211
212 $dir = $params['dir'];
213
214 // We need a custom WHERE clause that matches all titles.
215 if ( $mode == 'revs' ) {
216 $lb = $this->linkBatchFactory->newLinkBatch( $titles );
217 $where = $lb->constructSet( 'ar', $db );
218 $this->addWhere( $where );
219 } elseif ( $mode == 'all' ) {
220 $this->addWhereFld( 'ar_namespace', $params['namespace'] );
221
222 $from = $params['from'] === null
223 ? null
224 : $this->titlePartToKey( $params['from'], $params['namespace'] );
225 $to = $params['to'] === null
226 ? null
227 : $this->titlePartToKey( $params['to'], $params['namespace'] );
228 $this->addWhereRange( 'ar_title', $dir, $from, $to );
229
230 if ( isset( $params['prefix'] ) ) {
231 $this->addWhere(
232 $db->expr(
233 'ar_title',
234 IExpression::LIKE,
235 new LikeValue(
236 $this->titlePartToKey( $params['prefix'], $params['namespace'] ),
237 $db->anyString()
238 )
239 )
240 );
241 }
242 }
243
244 if ( $params['user'] !== null ) {
245 // We already join on actor due to getArchiveQueryInfo()
246 $this->addWhereFld( 'actor_name', $params['user'] );
247 } elseif ( $params['excludeuser'] !== null ) {
248 $this->addWhere( $db->expr( 'actor_name', '!=', $params['excludeuser'] ) );
249 }
250
251 if ( $params['user'] !== null || $params['excludeuser'] !== null ) {
252 // Paranoia: avoid brute force searches (T19342)
253 // (shouldn't be able to get here without 'deletedhistory', but
254 // check it again just in case)
255 if ( !$this->getAuthority()->isAllowed( 'deletedhistory' ) ) {
256 $bitmask = RevisionRecord::DELETED_USER;
257 } elseif ( !$this->getAuthority()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
258 $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
259 } else {
260 $bitmask = 0;
261 }
262 if ( $bitmask ) {
263 $this->addWhere( $db->bitAnd( 'ar_deleted', $bitmask ) . " != $bitmask" );
264 }
265 }
266
267 if ( $params['continue'] !== null ) {
268 $op = ( $dir == 'newer' ? '>=' : '<=' );
269 if ( $mode == 'all' || $mode == 'revs' ) {
270 $cont = $this->parseContinueParamOrDie( $params['continue'], [ 'int', 'string', 'timestamp', 'int' ] );
271 $this->addWhere( $db->buildComparison( $op, [
272 'ar_namespace' => $cont[0],
273 'ar_title' => $cont[1],
274 'ar_timestamp' => $db->timestamp( $cont[2] ),
275 'ar_id' => $cont[3],
276 ] ) );
277 } else {
278 $cont = $this->parseContinueParamOrDie( $params['continue'], [ 'timestamp', 'int' ] );
279 $this->addWhere( $db->buildComparison( $op, [
280 'ar_timestamp' => $db->timestamp( $cont[0] ),
281 'ar_id' => $cont[1],
282 ] ) );
283 }
284 }
285
286 $this->addOption( 'LIMIT', $limit + 1 );
287 if ( $mode == 'all' ) {
288 if ( $params['unique'] ) {
289 // @todo Does this work on non-MySQL?
290 $this->addOption( 'GROUP BY', 'ar_title' );
291 } else {
292 $sort = ( $dir == 'newer' ? '' : ' DESC' );
293 $this->addOption( 'ORDER BY', [
294 'ar_title' . $sort,
295 'ar_timestamp' . $sort,
296 'ar_id' . $sort,
297 ] );
298 }
299 } else {
300 if ( $mode == 'revs' ) {
301 // Sort by ns and title in the same order as timestamp for efficiency
302 $this->addWhereRange( 'ar_namespace', $dir, null, null );
303 $this->addWhereRange( 'ar_title', $dir, null, null );
304 }
305 $this->addTimestampWhereRange( 'ar_timestamp', $dir, $params['start'], $params['end'] );
306 // Include in ORDER BY for uniqueness
307 $this->addWhereRange( 'ar_id', $dir, null, null );
308 }
309 $res = $this->select( __METHOD__ );
310
311 $formattedComments = [];
312 if ( $fld_parsedcomment ) {
313 $formattedComments = $this->commentFormatter->formatItems(
314 $this->commentFormatter->rows( $res )
315 ->indexField( 'ar_id' )
316 ->commentKey( 'ar_comment' )
317 ->namespaceField( 'ar_namespace' )
318 ->titleField( 'ar_title' )
319 );
320 }
321
322 $pageMap = []; // Maps ns&title to (fake) pageid
323 $count = 0;
324 $newPageID = 0;
325 foreach ( $res as $row ) {
326 if ( ++$count > $limit ) {
327 // We've had enough
328 if ( $mode == 'all' || $mode == 'revs' ) {
329 $this->setContinueEnumParameter( 'continue',
330 "$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id"
331 );
332 } else {
333 $this->setContinueEnumParameter( 'continue', "$row->ar_timestamp|$row->ar_id" );
334 }
335 break;
336 }
337
338 $rev = [];
339 $anyHidden = false;
340
341 $rev['timestamp'] = wfTimestamp( TS::ISO_8601, $row->ar_timestamp );
342 if ( $fld_revid ) {
343 $rev['revid'] = (int)$row->ar_rev_id;
344 }
345 if ( $fld_parentid && $row->ar_parent_id !== null ) {
346 $rev['parentid'] = (int)$row->ar_parent_id;
347 }
348 if ( $fld_user || $fld_userid ) {
349 if ( $row->ar_deleted & RevisionRecord::DELETED_USER ) {
350 $rev['userhidden'] = true;
351 $anyHidden = true;
352 }
353 if ( RevisionRecord::userCanBitfield(
354 $row->ar_deleted,
355 RevisionRecord::DELETED_USER,
356 $user
357 ) ) {
358 if ( $fld_user ) {
359 $rev['user'] = $row->ar_user_text;
360 }
361 if ( $fld_userid ) {
362 $rev['userid'] = (int)$row->ar_user;
363 }
364 }
365 }
366
367 if ( $fld_comment || $fld_parsedcomment ) {
368 if ( $row->ar_deleted & RevisionRecord::DELETED_COMMENT ) {
369 $rev['commenthidden'] = true;
370 $anyHidden = true;
371 }
372 if ( RevisionRecord::userCanBitfield(
373 $row->ar_deleted,
374 RevisionRecord::DELETED_COMMENT,
375 $user
376 ) ) {
377 $comment = $this->commentStore->getComment( 'ar_comment', $row )->text;
378 if ( $fld_comment ) {
379 $rev['comment'] = $comment;
380 }
381 if ( $fld_parsedcomment ) {
382 $rev['parsedcomment'] = $formattedComments[$row->ar_id];
383 }
384 }
385 }
386
387 if ( $fld_minor ) {
388 $rev['minor'] = $row->ar_minor_edit == 1;
389 }
390 if ( $fld_len ) {
391 $rev['len'] = $row->ar_len;
392 }
393 if ( $fld_sha1 ) {
394 if ( $row->ar_deleted & RevisionRecord::DELETED_TEXT ) {
395 $rev['sha1hidden'] = true;
396 $anyHidden = true;
397 }
398 if ( RevisionRecord::userCanBitfield(
399 $row->ar_deleted,
400 RevisionRecord::DELETED_TEXT,
401 $user
402 ) ) {
403 if ( $row->ar_slot_pairs !== null ) {
404 $combinedBase36 = '';
405 if ( $row->ar_slot_pairs !== '' ) {
406 $items = explode( ',', $row->ar_slot_pairs );
407 $slotHashes = [];
408 foreach ( $items as $item ) {
409 $parts = explode( ':', $item );
410 $slotHashes[$parts[0]] = $parts[1];
411 }
412 ksort( $slotHashes );
413
414 $accu = null;
415 foreach ( $slotHashes as $slotHash ) {
416 $accu = $accu === null
417 ? $slotHash
418 : SlotRecord::base36Sha1( $accu . $slotHash );
419 }
420 $combinedBase36 = $accu ?? SlotRecord::base36Sha1( '' );
421 }
422
423 $rev['sha1'] = $combinedBase36 !== ''
424 ? \Wikimedia\base_convert( $combinedBase36, 36, 16, 40 )
425 : '';
426 }
427 }
428 }
429 if ( $fld_content ) {
430 if ( $row->ar_deleted & RevisionRecord::DELETED_TEXT ) {
431 $rev['texthidden'] = true;
432 $anyHidden = true;
433 }
434 if ( RevisionRecord::userCanBitfield(
435 $row->ar_deleted,
436 RevisionRecord::DELETED_TEXT,
437 $user
438 ) ) {
439 ApiResult::setContentValue( $rev, 'text',
440 $this->revisionStore->newRevisionFromArchiveRow( $row )
441 ->getContent( SlotRecord::MAIN )->serialize() );
442 }
443 }
444
445 if ( $fld_tags ) {
446 if ( $row->ts_tags ) {
447 $tags = explode( ',', $row->ts_tags );
448 ApiResult::setIndexedTagName( $tags, 'tag' );
449 $rev['tags'] = $tags;
450 } else {
451 $rev['tags'] = [];
452 }
453 }
454
455 if ( $anyHidden && ( $row->ar_deleted & RevisionRecord::DELETED_RESTRICTED ) ) {
456 $rev['suppressed'] = true;
457 }
458
459 if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {
460 $pageID = $newPageID++;
461 $pageMap[$row->ar_namespace][$row->ar_title] = $pageID;
462 $a = [ 'revisions' => [ $rev ] ];
463 ApiResult::setIndexedTagName( $a['revisions'], 'rev' );
464 $title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
465 ApiQueryBase::addTitleInfo( $a, $title );
466 if ( $fld_token ) {
467 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable token is set when used
468 $a['token'] = $token;
469 }
470 $fit = $result->addValue( [ 'query', $this->getModuleName() ], $pageID, $a );
471 } else {
472 $pageID = $pageMap[$row->ar_namespace][$row->ar_title];
473 $fit = $result->addValue(
474 [ 'query', $this->getModuleName(), $pageID, 'revisions' ],
475 null, $rev );
476 }
477 if ( !$fit ) {
478 if ( $mode == 'all' || $mode == 'revs' ) {
479 $this->setContinueEnumParameter( 'continue',
480 "$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id"
481 );
482 } else {
483 $this->setContinueEnumParameter( 'continue', "$row->ar_timestamp|$row->ar_id" );
484 }
485 break;
486 }
487 }
488 $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'page' );
489 }
490
492 public function isDeprecated() {
493 return true;
494 }
495
497 public function getAllowedParams() {
498 $smallLimit = $this->getMain()->canApiHighLimits() ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_SML1;
499 return [
500 'start' => [
501 ParamValidator::PARAM_TYPE => 'timestamp',
502 ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 1, 2 ] ],
503 ],
504 'end' => [
505 ParamValidator::PARAM_TYPE => 'timestamp',
506 ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 1, 2 ] ],
507 ],
508 'dir' => [
509 ParamValidator::PARAM_TYPE => [
510 'newer',
511 'older'
512 ],
513 ParamValidator::PARAM_DEFAULT => 'older',
514 ApiBase::PARAM_HELP_MSG => 'api-help-param-direction',
516 'newer' => 'api-help-paramvalue-direction-newer',
517 'older' => 'api-help-paramvalue-direction-older',
518 ],
519 ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 1, 3 ] ],
520 ],
521 'from' => [
522 ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
523 ],
524 'to' => [
525 ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
526 ],
527 'prefix' => [
528 ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
529 ],
530 'unique' => [
531 ParamValidator::PARAM_DEFAULT => false,
532 ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
533 ],
534 'namespace' => [
535 ParamValidator::PARAM_TYPE => 'namespace',
536 ParamValidator::PARAM_DEFAULT => NS_MAIN,
537 ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
538 ],
539 'tag' => null,
540 'user' => [
541 ParamValidator::PARAM_TYPE => 'user',
542 UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'temp', 'id', 'interwiki' ],
543 ],
544 'excludeuser' => [
545 ParamValidator::PARAM_TYPE => 'user',
546 UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'temp', 'id', 'interwiki' ],
547 ],
548 'prop' => [
549 ParamValidator::PARAM_DEFAULT => 'user|comment',
550 ParamValidator::PARAM_TYPE => [
551 'revid',
552 'parentid',
553 'user',
554 'userid',
555 'comment',
556 'parsedcomment',
557 'minor',
558 'len',
559 'sha1',
560 'content',
561 'token',
562 'tags'
563 ],
564 ParamValidator::PARAM_ISMULTI => true,
566 'content' => [ 'apihelp-query+deletedrevs-paramvalue-prop-content', $smallLimit ],
567 ],
568 EnumDef::PARAM_DEPRECATED_VALUES => [
569 'token' => true,
570 ],
571 ],
572 'limit' => [
573 ParamValidator::PARAM_DEFAULT => 10,
574 ParamValidator::PARAM_TYPE => 'limit',
575 IntegerDef::PARAM_MIN => 1,
576 IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
577 IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2,
578 ApiBase::PARAM_HELP_MSG => [ 'apihelp-query+deletedrevs-param-limit', $smallLimit ],
579 ],
580 'continue' => [
581 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
582 ],
583 ];
584 }
585
587 protected function getExamplesMessages() {
588 $title = Title::newMainPage();
589 $talkTitle = $title->getTalkPageIfDefined();
590 $examples = [];
591
592 if ( $talkTitle ) {
593 $title = rawurlencode( $title->getPrefixedText() );
594 $talkTitle = rawurlencode( $talkTitle->getPrefixedText() );
595 $examples = [
596 "action=query&list=deletedrevs&titles={$title}|{$talkTitle}&" .
597 'drprop=user|comment|content'
598 => 'apihelp-query+deletedrevs-example-mode1',
599 ];
600 }
601
602 return array_merge( $examples, [
603 'action=query&list=deletedrevs&druser=Bob&drlimit=50'
604 => 'apihelp-query+deletedrevs-example-mode2',
605 'action=query&list=deletedrevs&drdir=newer&drlimit=50'
606 => 'apihelp-query+deletedrevs-example-mode3-main',
607 'action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=1&drunique='
608 => 'apihelp-query+deletedrevs-example-mode3-talk',
609 ] );
610 }
611
613 public function getHelpUrls() {
614 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Deletedrevs';
615 }
616}
617
619class_alias( ApiQueryDeletedrevs::class, 'ApiQueryDeletedrevs' );
const NS_MAIN
Definition Defines.php:51
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
const LIMIT_SML1
Slow query, standard limit.
Definition ApiBase.php:236
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1511
checkUserRightsAny( $rights)
Helper function for permission-denied errors.
Definition ApiBase.php:1620
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:543
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
Definition ApiBase.php:185
getMain()
Get the main module.
Definition ApiBase.php:561
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
Definition ApiBase.php:1696
getResult()
Get the result object.
Definition ApiBase.php:682
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:207
const LIMIT_SML2
Slow query, apihighlimits limit.
Definition ApiBase.php:238
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition ApiBase.php:609
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:167
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:234
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition ApiBase.php:1443
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:823
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:232
This is a base class for all Query modules.
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
getDB()
Get the Query database connection (read-only).
select( $method, $extraQuery=[], ?array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
titlePartToKey( $titlePart, $namespace=NS_MAIN)
Convert an input title or title prefix into a dbkey.
addWhere( $value)
Add a set of WHERE clauses to the internal array.
getPageSet()
Get the PageSet object to work on.
addTimestampWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, similar to addWhereRange, but converts $start and $end t...
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
addFields( $value)
Add a set of fields to select to the internal array.
addWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, and an ORDER BY clause to sort in the right direction.
Query module to enumerate all deleted revisions.
isDeprecated()
Indicates whether this module is deprecated.1.25 to override bool
getHelpUrls()
Return links to more detailed help pages about the module.1.25, returning boolean false is deprecated...
__construct(ApiQuery $query, string $moduleName, CommentStore $commentStore, RowCommentFormatter $commentFormatter, RevisionStore $revisionStore, NameTableStore $changeTagDefStore, ChangeTagsStore $changeTagsStore, LinkBatchFactory $linkBatchFactory)
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getExamplesMessages()
Returns usage examples for this module.Return value has query strings as keys, with values being eith...
This is the main query class.
Definition ApiQuery.php:36
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
static setContentValue(array &$arr, $name, $value, $flags=0)
Add an output value to the array by name and mark as META_CONTENT.
Read-write access to the change_tags table.
This is basically a CommentFormatter with a CommentStore dependency, allowing it to retrieve comment ...
Handle database storage of comments such as edit summaries and log reasons.
makeTitle( $linkId)
Convert a link ID to a Title.to override Title
Factory for LinkBatch objects to batch query page metadata.
Type definition for user types.
Definition UserDef.php:27
Page revision base class.
Service for looking up page revisions.
Value object representing a content slot associated with a page revision.
Exception representing a failure to look up a row from a name table.
Represents a title within MediaWiki.
Definition Title.php:69
Service for formatting and validating API parameters.
Type definition for enumeration types.
Definition EnumDef.php:32
Type definition for integer types.
Content of like value.
Definition LikeValue.php:14