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