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