MediaWiki REL1_40
ApiQueryWatchlist.php
Go to the documentation of this file.
1<?php
31
39
41 private $commentStore;
42
44 private $watchedItemQueryService;
45
47 private $contentLanguage;
48
50 private $namespaceInfo;
51
53 private $genderCache;
54
56 private $commentFormatter;
57
68 public function __construct(
69 ApiQuery $query,
70 $moduleName,
71 CommentStore $commentStore,
72 WatchedItemQueryService $watchedItemQueryService,
73 Language $contentLanguage,
74 NamespaceInfo $namespaceInfo,
75 GenderCache $genderCache,
76 CommentFormatter $commentFormatter
77 ) {
78 parent::__construct( $query, $moduleName, 'wl' );
79 $this->commentStore = $commentStore;
80 $this->watchedItemQueryService = $watchedItemQueryService;
81 $this->contentLanguage = $contentLanguage;
82 $this->namespaceInfo = $namespaceInfo;
83 $this->genderCache = $genderCache;
84 $this->commentFormatter = $commentFormatter;
85 }
86
87 public function execute() {
88 $this->run();
89 }
90
91 public function executeGenerator( $resultPageSet ) {
92 $this->run( $resultPageSet );
93 }
94
95 private $fld_ids = false, $fld_title = false, $fld_patrol = false,
96 $fld_flags = false, $fld_timestamp = false, $fld_user = false,
97 $fld_comment = false, $fld_parsedcomment = false, $fld_sizes = false,
98 $fld_notificationtimestamp = false, $fld_userid = false,
99 $fld_loginfo = false, $fld_tags;
100
102 private $fld_expiry = false;
103
108 private function run( $resultPageSet = null ) {
109 $params = $this->extractRequestParams();
110
111 $user = $this->getUser();
112 $wlowner = $this->getWatchlistUser( $params );
113
114 if ( $params['prop'] !== null && $resultPageSet === null ) {
115 $prop = array_fill_keys( $params['prop'], true );
116
117 $this->fld_ids = isset( $prop['ids'] );
118 $this->fld_title = isset( $prop['title'] );
119 $this->fld_flags = isset( $prop['flags'] );
120 $this->fld_user = isset( $prop['user'] );
121 $this->fld_userid = isset( $prop['userid'] );
122 $this->fld_comment = isset( $prop['comment'] );
123 $this->fld_parsedcomment = isset( $prop['parsedcomment'] );
124 $this->fld_timestamp = isset( $prop['timestamp'] );
125 $this->fld_sizes = isset( $prop['sizes'] );
126 $this->fld_patrol = isset( $prop['patrol'] );
127 $this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] );
128 $this->fld_loginfo = isset( $prop['loginfo'] );
129 $this->fld_tags = isset( $prop['tags'] );
130 $this->fld_expiry = isset( $prop['expiry'] );
131
132 if ( $this->fld_patrol && !$user->useRCPatrol() && !$user->useNPPatrol() ) {
133 $this->dieWithError( 'apierror-permissiondenied-patrolflag', 'patrol' );
134 }
135 }
136
137 $options = [
138 'dir' => $params['dir'] === 'older'
141 ];
142
143 if ( $resultPageSet === null ) {
144 $options['includeFields'] = $this->getFieldsToInclude();
145 } else {
146 $options['usedInGenerator'] = true;
147 }
148
149 if ( $params['start'] ) {
150 $options['start'] = $params['start'];
151 }
152 if ( $params['end'] ) {
153 $options['end'] = $params['end'];
154 }
155
156 $startFrom = null;
157 if ( $params['continue'] !== null ) {
158 $cont = $this->parseContinueParamOrDie( $params['continue'], [ 'string', 'int' ] );
159 $startFrom = $cont;
160 }
161
162 if ( $wlowner !== $user ) {
163 $options['watchlistOwner'] = $wlowner;
164 $options['watchlistOwnerToken'] = $params['token'];
165 }
166
167 if ( $params['namespace'] !== null ) {
168 $options['namespaceIds'] = $params['namespace'];
169 }
170
171 if ( $params['allrev'] ) {
172 $options['allRevisions'] = true;
173 }
174
175 if ( $params['show'] !== null ) {
176 $show = array_fill_keys( $params['show'], true );
177
178 /* Check for conflicting parameters. */
179 if ( $this->showParamsConflicting( $show ) ) {
180 $this->dieWithError( 'apierror-show' );
181 }
182
183 // Check permissions.
184 if ( isset( $show[WatchedItemQueryService::FILTER_PATROLLED] )
185 || isset( $show[WatchedItemQueryService::FILTER_NOT_PATROLLED] )
186 ) {
187 if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) {
188 $this->dieWithError( 'apierror-permissiondenied-patrolflag', 'permissiondenied' );
189 }
190 }
191
192 $options['filters'] = array_keys( $show );
193 }
194
195 if ( $params['type'] !== null ) {
196 try {
197 $rcTypes = RecentChange::parseToRCType( $params['type'] );
198 if ( $rcTypes ) {
199 $options['rcTypes'] = $rcTypes;
200 }
201 } catch ( Exception $e ) {
202 ApiBase::dieDebug( __METHOD__, $e->getMessage() );
203 }
204 }
205
206 $this->requireMaxOneParameter( $params, 'user', 'excludeuser' );
207 if ( $params['user'] !== null ) {
208 $options['onlyByUser'] = $params['user'];
209 }
210 if ( $params['excludeuser'] !== null ) {
211 $options['notByUser'] = $params['excludeuser'];
212 }
213
214 $options['limit'] = $params['limit'];
215
216 $this->getHookRunner()->onApiQueryWatchlistPrepareWatchedItemQueryServiceOptions(
217 $this, $params, $options );
218
219 $ids = [];
220 $items = $this->watchedItemQueryService->getWatchedItemsWithRecentChangeInfo( $wlowner, $options, $startFrom );
221
222 // Get gender information
223 if ( $items !== [] && $resultPageSet === null && $this->fld_title &&
224 $this->contentLanguage->needsGenderDistinction()
225 ) {
226 $usernames = [];
227 foreach ( $items as [ $watchedItem, ] ) {
229 $linkTarget = $watchedItem->getTarget();
230 if ( $this->namespaceInfo->hasGenderDistinction( $linkTarget->getNamespace() ) ) {
231 $usernames[] = $linkTarget->getText();
232 }
233 }
234 if ( $usernames !== [] ) {
235 $this->genderCache->doQuery( $usernames, __METHOD__ );
236 }
237 }
238
239 foreach ( $items as [ $watchedItem, $recentChangeInfo ] ) {
241 if ( $resultPageSet === null ) {
242 $vals = $this->extractOutputData( $watchedItem, $recentChangeInfo );
243 $fit = $this->getResult()->addValue( [ 'query', $this->getModuleName() ], null, $vals );
244 if ( !$fit ) {
245 $startFrom = [ $recentChangeInfo['rc_timestamp'], $recentChangeInfo['rc_id'] ];
246 break;
247 }
248 } elseif ( $params['allrev'] ) {
249 $ids[] = (int)$recentChangeInfo['rc_this_oldid'];
250 } else {
251 $ids[] = (int)$recentChangeInfo['rc_cur_id'];
252 }
253 }
254
255 if ( $startFrom !== null ) {
256 $this->setContinueEnumParameter( 'continue', implode( '|', $startFrom ) );
257 }
258
259 if ( $resultPageSet === null ) {
260 $this->getResult()->addIndexedTagName(
261 [ 'query', $this->getModuleName() ],
262 'item'
263 );
264 } elseif ( $params['allrev'] ) {
265 $resultPageSet->populateFromRevisionIDs( $ids );
266 } else {
267 $resultPageSet->populateFromPageIDs( $ids );
268 }
269 }
270
271 private function getFieldsToInclude() {
272 $includeFields = [];
273 if ( $this->fld_flags ) {
275 }
276 if ( $this->fld_user || $this->fld_userid || $this->fld_loginfo ) {
278 }
279 if ( $this->fld_user || $this->fld_loginfo ) {
280 $includeFields[] = WatchedItemQueryService::INCLUDE_USER;
281 }
282 if ( $this->fld_comment || $this->fld_parsedcomment ) {
284 }
285 if ( $this->fld_patrol ) {
288 }
289 if ( $this->fld_sizes ) {
291 }
292 if ( $this->fld_loginfo ) {
294 }
295 if ( $this->fld_tags ) {
296 $includeFields[] = WatchedItemQueryService::INCLUDE_TAGS;
297 }
298 return $includeFields;
299 }
300
301 private function showParamsConflicting( array $show ) {
302 return ( isset( $show[WatchedItemQueryService::FILTER_MINOR] )
303 && isset( $show[WatchedItemQueryService::FILTER_NOT_MINOR] ) )
304 || ( isset( $show[WatchedItemQueryService::FILTER_BOT] )
305 && isset( $show[WatchedItemQueryService::FILTER_NOT_BOT] ) )
306 || ( isset( $show[WatchedItemQueryService::FILTER_ANON] )
307 && isset( $show[WatchedItemQueryService::FILTER_NOT_ANON] ) )
308 || ( isset( $show[WatchedItemQueryService::FILTER_PATROLLED] )
309 && isset( $show[WatchedItemQueryService::FILTER_NOT_PATROLLED] ) )
310 || ( isset( $show[WatchedItemQueryService::FILTER_AUTOPATROLLED] )
311 && isset( $show[WatchedItemQueryService::FILTER_NOT_AUTOPATROLLED] ) )
312 || ( isset( $show[WatchedItemQueryService::FILTER_AUTOPATROLLED] )
313 && isset( $show[WatchedItemQueryService::FILTER_NOT_PATROLLED] ) )
314 || ( isset( $show[WatchedItemQueryService::FILTER_UNREAD] )
315 && isset( $show[WatchedItemQueryService::FILTER_NOT_UNREAD] ) );
316 }
317
318 private function extractOutputData( WatchedItem $watchedItem, array $recentChangeInfo ) {
319 /* Determine the title of the page that has been changed. */
320 $target = $watchedItem->getTarget();
321 if ( $target instanceof LinkTarget ) {
322 $title = Title::newFromLinkTarget( $target );
323 } else {
324 $title = Title::castFromPageIdentity( $target );
325 }
326 $user = $this->getUser();
327
328 /* Our output data. */
329 $vals = [];
330 $type = (int)$recentChangeInfo['rc_type'];
331 $vals['type'] = RecentChange::parseFromRCType( $type );
332 $anyHidden = false;
333
334 /* Create a new entry in the result for the title. */
335 if ( $this->fld_title || $this->fld_ids ) {
336 // These should already have been filtered out of the query, but just in case.
337 if ( $type === RC_LOG && ( $recentChangeInfo['rc_deleted'] & LogPage::DELETED_ACTION ) ) {
338 $vals['actionhidden'] = true;
339 $anyHidden = true;
340 }
341 if ( $type !== RC_LOG ||
342 LogEventsList::userCanBitfield(
343 $recentChangeInfo['rc_deleted'],
344 LogPage::DELETED_ACTION,
345 $user
346 )
347 ) {
348 if ( $this->fld_title ) {
349 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here
351 }
352 if ( $this->fld_ids ) {
353 $vals['pageid'] = (int)$recentChangeInfo['rc_cur_id'];
354 $vals['revid'] = (int)$recentChangeInfo['rc_this_oldid'];
355 $vals['old_revid'] = (int)$recentChangeInfo['rc_last_oldid'];
356 }
357 }
358 }
359
360 /* Add user data and 'anon' flag, if user is anonymous. */
361 if ( $this->fld_user || $this->fld_userid ) {
362 if ( $recentChangeInfo['rc_deleted'] & RevisionRecord::DELETED_USER ) {
363 $vals['userhidden'] = true;
364 $anyHidden = true;
365 }
366 if ( RevisionRecord::userCanBitfield(
367 $recentChangeInfo['rc_deleted'],
368 RevisionRecord::DELETED_USER,
369 $user
370 ) ) {
371 if ( $this->fld_userid ) {
372 $vals['userid'] = (int)$recentChangeInfo['rc_user'];
373 // for backwards compatibility
374 $vals['user'] = (int)$recentChangeInfo['rc_user'];
375 }
376
377 if ( $this->fld_user ) {
378 $vals['user'] = $recentChangeInfo['rc_user_text'];
379 }
380
381 $vals['anon'] = !$recentChangeInfo['rc_user'];
382 }
383 }
384
385 /* Add flags, such as new, minor, bot. */
386 if ( $this->fld_flags ) {
387 $vals['bot'] = (bool)$recentChangeInfo['rc_bot'];
388 $vals['new'] = $recentChangeInfo['rc_type'] == RC_NEW;
389 $vals['minor'] = (bool)$recentChangeInfo['rc_minor'];
390 }
391
392 /* Add sizes of each revision. (Only available on 1.10+) */
393 if ( $this->fld_sizes ) {
394 $vals['oldlen'] = (int)$recentChangeInfo['rc_old_len'];
395 $vals['newlen'] = (int)$recentChangeInfo['rc_new_len'];
396 }
397
398 /* Add the timestamp. */
399 if ( $this->fld_timestamp ) {
400 $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $recentChangeInfo['rc_timestamp'] );
401 }
402
403 if ( $this->fld_notificationtimestamp ) {
404 $vals['notificationtimestamp'] = ( $watchedItem->getNotificationTimestamp() == null )
405 ? ''
406 : wfTimestamp( TS_ISO_8601, $watchedItem->getNotificationTimestamp() );
407 }
408
409 /* Add edit summary / log summary. */
410 if ( $this->fld_comment || $this->fld_parsedcomment ) {
411 if ( $recentChangeInfo['rc_deleted'] & RevisionRecord::DELETED_COMMENT ) {
412 $vals['commenthidden'] = true;
413 $anyHidden = true;
414 }
415 if ( RevisionRecord::userCanBitfield(
416 $recentChangeInfo['rc_deleted'],
417 RevisionRecord::DELETED_COMMENT,
418 $user
419 ) ) {
420 $comment = $this->commentStore->getComment( 'rc_comment', $recentChangeInfo )->text;
421 if ( $this->fld_comment ) {
422 $vals['comment'] = $comment;
423 }
424
425 if ( $this->fld_parsedcomment ) {
426 $vals['parsedcomment'] = $this->commentFormatter->format( $comment, $title );
427 }
428 }
429 }
430
431 /* Add the patrolled flag */
432 if ( $this->fld_patrol ) {
433 $vals['patrolled'] = $recentChangeInfo['rc_patrolled'] != RecentChange::PRC_UNPATROLLED;
434 $vals['unpatrolled'] = ChangesList::isUnpatrolled( (object)$recentChangeInfo, $user );
435 $vals['autopatrolled'] = $recentChangeInfo['rc_patrolled'] == RecentChange::PRC_AUTOPATROLLED;
436 }
437
438 if ( $this->fld_loginfo && $recentChangeInfo['rc_type'] == RC_LOG ) {
439 if ( $recentChangeInfo['rc_deleted'] & LogPage::DELETED_ACTION ) {
440 $vals['actionhidden'] = true;
441 $anyHidden = true;
442 }
443 if ( LogEventsList::userCanBitfield(
444 $recentChangeInfo['rc_deleted'],
445 LogPage::DELETED_ACTION,
446 $user
447 ) ) {
448 $vals['logid'] = (int)$recentChangeInfo['rc_logid'];
449 $vals['logtype'] = $recentChangeInfo['rc_log_type'];
450 $vals['logaction'] = $recentChangeInfo['rc_log_action'];
451
452 $logFormatter = LogFormatter::newFromRow( $recentChangeInfo );
453 $vals['logparams'] = $logFormatter->formatParametersForApi();
454 $vals['logdisplay'] = $logFormatter->getActionText();
455 }
456 }
457
458 if ( $this->fld_tags ) {
459 if ( $recentChangeInfo['rc_tags'] ) {
460 $tags = explode( ',', $recentChangeInfo['rc_tags'] );
461 ApiResult::setIndexedTagName( $tags, 'tag' );
462 $vals['tags'] = $tags;
463 } else {
464 $vals['tags'] = [];
465 }
466 }
467
468 if ( $this->fld_expiry ) {
469 // Add expiration, T263796
470 $expiry = $watchedItem->getExpiry( TS_ISO_8601 );
471 $vals['expiry'] = ( $expiry ?? false );
472 }
473
474 if ( $anyHidden && ( $recentChangeInfo['rc_deleted'] & RevisionRecord::DELETED_RESTRICTED ) ) {
475 $vals['suppressed'] = true;
476 }
477
478 $this->getHookRunner()->onApiQueryWatchlistExtractOutputData(
479 $this, $watchedItem, $recentChangeInfo, $vals );
480
481 return $vals;
482 }
483
484 public function getAllowedParams() {
485 return [
486 'allrev' => false,
487 'start' => [
488 ParamValidator::PARAM_TYPE => 'timestamp'
489 ],
490 'end' => [
491 ParamValidator::PARAM_TYPE => 'timestamp'
492 ],
493 'namespace' => [
494 ParamValidator::PARAM_ISMULTI => true,
495 ParamValidator::PARAM_TYPE => 'namespace'
496 ],
497 'user' => [
498 ParamValidator::PARAM_TYPE => 'user',
499 UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'id', 'interwiki' ],
500 ],
501 'excludeuser' => [
502 ParamValidator::PARAM_TYPE => 'user',
503 UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'id', 'interwiki' ],
504 ],
505 'dir' => [
506 ParamValidator::PARAM_DEFAULT => 'older',
507 ParamValidator::PARAM_TYPE => [
508 'newer',
509 'older'
510 ],
511 ApiBase::PARAM_HELP_MSG => 'api-help-param-direction',
513 'newer' => 'api-help-paramvalue-direction-newer',
514 'older' => 'api-help-paramvalue-direction-older',
515 ],
516 ],
517 'limit' => [
518 ParamValidator::PARAM_DEFAULT => 10,
519 ParamValidator::PARAM_TYPE => 'limit',
520 IntegerDef::PARAM_MIN => 1,
521 IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
522 IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2
523 ],
524 'prop' => [
525 ParamValidator::PARAM_ISMULTI => true,
526 ParamValidator::PARAM_DEFAULT => 'ids|title|flags',
528 ParamValidator::PARAM_TYPE => [
529 'ids',
530 'title',
531 'flags',
532 'user',
533 'userid',
534 'comment',
535 'parsedcomment',
536 'timestamp',
537 'patrol',
538 'sizes',
539 'notificationtimestamp',
540 'loginfo',
541 'tags',
542 'expiry',
543 ]
544 ],
545 'show' => [
546 ParamValidator::PARAM_ISMULTI => true,
547 ParamValidator::PARAM_TYPE => [
548 WatchedItemQueryService::FILTER_MINOR,
549 WatchedItemQueryService::FILTER_NOT_MINOR,
550 WatchedItemQueryService::FILTER_BOT,
551 WatchedItemQueryService::FILTER_NOT_BOT,
552 WatchedItemQueryService::FILTER_ANON,
553 WatchedItemQueryService::FILTER_NOT_ANON,
554 WatchedItemQueryService::FILTER_PATROLLED,
555 WatchedItemQueryService::FILTER_NOT_PATROLLED,
556 WatchedItemQueryService::FILTER_AUTOPATROLLED,
557 WatchedItemQueryService::FILTER_NOT_AUTOPATROLLED,
558 WatchedItemQueryService::FILTER_UNREAD,
559 WatchedItemQueryService::FILTER_NOT_UNREAD,
560 ]
561 ],
562 'type' => [
563 ParamValidator::PARAM_DEFAULT => 'edit|new|log|categorize',
564 ParamValidator::PARAM_ISMULTI => true,
566 ParamValidator::PARAM_TYPE => RecentChange::getChangeTypes()
567 ],
568 'owner' => [
569 ParamValidator::PARAM_TYPE => 'user',
570 UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name' ],
571 ],
572 'token' => [
573 ParamValidator::PARAM_TYPE => 'string',
574 ParamValidator::PARAM_SENSITIVE => true,
575 ],
576 'continue' => [
577 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
578 ],
579 ];
580 }
581
582 protected function getExamplesMessages() {
583 return [
584 'action=query&list=watchlist'
585 => 'apihelp-query+watchlist-example-simple',
586 'action=query&list=watchlist&wlprop=ids|title|timestamp|user|comment'
587 => 'apihelp-query+watchlist-example-props',
588 'action=query&list=watchlist&wlprop=ids|title|timestamp|user|comment|expiry'
589 => 'apihelp-query+watchlist-example-expiry',
590 'action=query&list=watchlist&wlallrev=&wlprop=ids|title|timestamp|user|comment'
591 => 'apihelp-query+watchlist-example-allrev',
592 'action=query&generator=watchlist&prop=info'
593 => 'apihelp-query+watchlist-example-generator',
594 'action=query&generator=watchlist&gwlallrev=&prop=revisions&rvprop=timestamp|user'
595 => 'apihelp-query+watchlist-example-generator-rev',
596 'action=query&list=watchlist&wlowner=Example&wltoken=123ABC'
597 => 'apihelp-query+watchlist-example-wlowner',
598 ];
599 }
600
601 public function getHelpUrls() {
602 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watchlist';
603 }
604}
getUser()
const RC_NEW
Definition Defines.php:117
const RC_LOG
Definition Defines.php:118
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:1460
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition ApiBase.php:1701
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
Definition ApiBase.php:1649
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:204
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:229
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition ApiBase.php:946
getResult()
Get the result object.
Definition ApiBase.php:637
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:166
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:231
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:506
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition ApiBase.php:719
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
setContinueEnumParameter( $paramName, $paramValue)
Overridden to set the generator param if in generator mode.
This query action allows clients to retrieve a list of recently modified pages that are part of the l...
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
__construct(ApiQuery $query, $moduleName, CommentStore $commentStore, WatchedItemQueryService $watchedItemQueryService, Language $contentLanguage, NamespaceInfo $namespaceInfo, GenderCache $genderCache, CommentFormatter $commentFormatter)
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getExamplesMessages()
Returns usage examples for this module.
getHelpUrls()
Return links to more detailed help pages about the module.
executeGenerator( $resultPageSet)
Execute this module as a generator.
This is the main query class.
Definition ApiQuery.php:42
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
static isUnpatrolled( $rc, User $user)
Caches user genders when needed to use correct namespace aliases.
Base class for language-specific code.
Definition Language.php:56
static newFromRow( $row)
Handy shortcut for constructing a formatter directly from database row.
This is the main service interface for converting single-line comments from various DB comment fields...
Handle database storage of comments such as edit summaries and log reasons.
Type definition for user types.
Definition UserDef.php:27
Page revision base class.
Represents a title within MediaWiki.
Definition Title.php:82
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
const PRC_UNPATROLLED
static parseToRCType( $type)
Parsing text to RC_* constants.
static parseFromRCType( $rcType)
Parsing RC_* constants to human-readable test.
const PRC_AUTOPATROLLED
Representation of a pair of user and title for watchlist entries.
getExpiry(?int $style=TS_MW)
When the watched item will expire.
getNotificationTimestamp()
Get the notification timestamp of this entry.
Service for formatting and validating API parameters.
Type definition for integer types.