MediaWiki  master
PageHistoryCountHandler.php
Go to the documentation of this file.
1 <?php
2 
3 namespace MediaWiki\Rest\Handler;
4 
5 use ChangeTags;
15 use RequestContext;
16 use Title;
17 use User;
18 use WANObjectCache;
24 
30  private const COUNT_LIMITS = [
31  'anonymous' => 10000,
32  'bot' => 10000,
33  'editors' => 25000,
34  'edits' => 30000,
35  'minor' => 1000,
36  'reverted' => 30000
37  ];
38 
39  private const DEPRECATED_COUNT_TYPES = [
40  'anonedits' => 'anonymous',
41  'botedits' => 'bot',
42  'revertededits' => 'reverted'
43  ];
44 
45  private const MAX_AGE_200 = 60;
46 
48  private $revisionStore;
49 
52 
55 
57  private $loadBalancer;
58 
60  private $cache;
61 
63  private $user;
64 
66  private $revision;
67 
70 
72  private $titleObject;
73 
81  public function __construct(
83  NameTableStoreFactory $nameTableStoreFactory,
87  ) {
88  $this->revisionStore = $revisionStore;
89  $this->changeTagDefStore = $nameTableStoreFactory->getChangeTagDef();
90  $this->permissionManager = $permissionManager;
91  $this->loadBalancer = $loadBalancer;
92  $this->cache = $cache;
93 
94  // @todo Inject this, when there is a good way to do that
95  $this->user = RequestContext::getMain()->getUser();
96  }
97 
98  private function normalizeType( $type ) {
99  return self::DEPRECATED_COUNT_TYPES[$type] ?? $type;
100  }
101 
108  private function validateParameterCombination( $type ) {
109  $params = $this->getValidatedParams();
110  if ( !$params ) {
111  return;
112  }
113 
114  if ( $params['from'] || $params['to'] ) {
115  if ( $type === 'edits' || $type === 'editors' ) {
116  if ( !$params['from'] || !$params['to'] ) {
117  throw new LocalizedHttpException(
118  new MessageValue( 'rest-pagehistorycount-parameters-invalid' ),
119  400
120  );
121  }
122  } else {
123  throw new LocalizedHttpException(
124  new MessageValue( 'rest-pagehistorycount-parameters-invalid' ),
125  400
126  );
127  }
128  }
129  }
130 
137  public function run( $title, $type ) {
138  $normalizedType = $this->normalizeType( $type );
139  $this->validateParameterCombination( $normalizedType );
140  $titleObj = $this->getTitle();
141  if ( !$titleObj || !$titleObj->getArticleID() ) {
142  throw new LocalizedHttpException(
143  new MessageValue( 'rest-nonexistent-title',
144  [ new ScalarParam( ParamType::PLAINTEXT, $title ) ]
145  ),
146  404
147  );
148  }
149 
150  if ( !$this->permissionManager->userCan( 'read', $this->user, $titleObj ) ) {
151  throw new LocalizedHttpException(
152  new MessageValue( 'rest-permission-denied-title',
153  [ new ScalarParam( ParamType::PLAINTEXT, $title ) ]
154  ),
155  403
156  );
157  }
158 
159  $count = $this->getCount( $normalizedType );
160  $countLimit = self::COUNT_LIMITS[$normalizedType];
161  $response = $this->getResponseFactory()->createJson( [
162  'count' => $count > $countLimit ? $countLimit : $count,
163  'limit' => $count > $countLimit
164  ] );
165  $response->setHeader( 'Cache-Control', 'max-age=' . self::MAX_AGE_200 );
166 
167  // Inform clients who use a deprecated "type" value, so they can adjust
168  if ( isset( self::DEPRECATED_COUNT_TYPES[$type] ) ) {
169  $docs = '<https://www.mediawiki.org/wiki/API:REST/History_API' .
170  '#Get_page_history_counts>; rel="deprecation"';
171  $response->setHeader( 'Deprecation', 'version="v1"' );
172  $response->setHeader( 'Link', $docs );
173  }
174 
175  return $response;
176  }
177 
183  private function getCount( $type ) {
184  $pageId = $this->getTitle()->getArticleID();
185  switch ( $type ) {
186  case 'anonymous':
187  return $this->getCachedCount( $type,
188  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
189  return $this->getAnonCount( $pageId, $fromRev );
190  }
191  );
192 
193  case 'bot':
194  return $this->getCachedCount( $type,
195  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
196  return $this->getBotCount( $pageId, $fromRev );
197  }
198  );
199 
200  case 'editors':
201  $from = $this->getValidatedParams()['from'] ?? null;
202  $to = $this->getValidatedParams()['to'] ?? null;
203  if ( $from || $to ) {
204  return $this->getEditorsCount(
205  $pageId,
206  $from ? $this->getRevisionOrThrow( $from ) : null,
207  $to ? $this->getRevisionOrThrow( $to ) : null
208  );
209  } else {
210  return $this->getCachedCount( $type,
211  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
212  return $this->getEditorsCount( $pageId, $fromRev );
213  } );
214  }
215 
216  case 'edits':
217  $from = $this->getValidatedParams()['from'] ?? null;
218  $to = $this->getValidatedParams()['to'] ?? null;
219  if ( $from || $to ) {
220  return $this->getEditsCount(
221  $pageId,
222  $from ? $this->getRevisionOrThrow( $from ) : null,
223  $to ? $this->getRevisionOrThrow( $to ) : null
224  );
225  } else {
226  return $this->getCachedCount( $type,
227  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
228  return $this->getEditsCount( $pageId, $fromRev );
229  }
230  );
231  }
232 
233  case 'reverted':
234  return $this->getCachedCount( $type,
235  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
236  return $this->getRevertedCount( $pageId, $fromRev );
237  }
238  );
239 
240  case 'minor':
241  // The query for minor counts is inefficient for the database for pages with many revisions.
242  // If the specified title contains more revisions than allowed, we will return an error.
243  $editsCount = $this->getCachedCount( 'edits',
244  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
245  return $this->getEditsCount( $pageId, $fromRev );
246  }
247  );
248  if ( $editsCount > self::COUNT_LIMITS[$type] * 2 ) {
249  throw new LocalizedHttpException(
250  new MessageValue( 'rest-pagehistorycount-too-many-revisions' ),
251  500
252  );
253  }
254  return $this->getCachedCount( $type,
255  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
256  return $this->getMinorCount( $pageId, $fromRev );
257  }
258  );
259 
260  // Sanity check
261  default:
262  throw new LocalizedHttpException(
263  new MessageValue( 'rest-pagehistorycount-type-unrecognized',
264  [ new ScalarParam( ParamType::PLAINTEXT, $type ) ]
265  ),
266  500
267  );
268  }
269  }
270 
274  private function getCurrentRevision() {
275  if ( $this->revision === null ) {
276  $title = $this->getTitle();
277  if ( $title && $title->getArticleID() ) {
278  $this->revision = $this->revisionStore->getKnownCurrentRevision( $title );
279  } else {
280  $this->revision = false;
281  }
282  }
283  return $this->revision;
284  }
285 
289  private function getTitle() {
290  if ( $this->titleObject === null ) {
291  $this->titleObject = Title::newFromText( $this->getValidatedParams()['title'] );
292  }
293  return $this->titleObject;
294  }
295 
302  protected function getLastModified() {
304  if ( $lastModifiedTimes ) {
305  return max( array_values( $lastModifiedTimes ) );
306  }
307  }
308 
315  protected function getLastModifiedTimes() {
316  $currentRev = $this->getCurrentRevision();
317  if ( !$currentRev ) {
318  return null;
319  }
320  if ( $this->lastModifiedTimes === null ) {
321  $currentRevTime = (int)wfTimestampOrNull( TS_UNIX, $currentRev->getTimestamp() );
322  $loggingTableTime = $this->loggingTableTime( $currentRev->getPageId() );
323  $this->lastModifiedTimes = [
324  'currentRevTS' => $currentRevTime,
325  'dependencyModTS' => $loggingTableTime
326  ];
327  }
329  }
330 
336  private function loggingTableTime( $pageId ) {
337  $res = $this->loadBalancer->getConnectionRef( DB_REPLICA )->selectField(
338  'logging',
339  'MAX(log_timestamp)',
340  [ 'log_page' => $pageId ],
341  __METHOD__
342  );
343  return $res ? (int)wfTimestamp( TS_UNIX, $res ) : null;
344  }
345 
356  protected function getEtag() {
357  return null;
358  }
359 
365  private function getCachedCount( $type,
366  callable $fetchCount
367  ) {
368  $titleObj = $this->getTitle();
369  $pageId = $titleObj->getArticleID();
370  return $this->cache->getWithSetCallback(
371  $this->cache->makeKey( 'rest', 'pagehistorycount', $pageId, $type ),
372  WANObjectCache::TTL_WEEK,
373  function ( $oldValue ) use ( $fetchCount ) {
374  $currentRev = $this->getCurrentRevision();
375  if ( $oldValue ) {
376  // Last modified timestamp was NOT a dependency change (e.g. revdel)
377  $doIncrementalUpdate = (
378  $this->getLastModified() != $this->getLastModifiedTimes()['dependencyModTS']
379  );
380  if ( $doIncrementalUpdate ) {
381  $rev = $this->revisionStore->getRevisionById( $oldValue['revision'] );
382  if ( $rev ) {
383  $additionalCount = $fetchCount( $rev );
384  return [
385  'revision' => $currentRev->getId(),
386  'count' => $oldValue['count'] + $additionalCount,
387  'dependencyModTS' => $this->getLastModifiedTimes()['dependencyModTS']
388  ];
389  }
390  }
391  }
392  // Nothing was previously stored, or incremental update was done for too long,
393  // recalculate from scratch.
394  return [
395  'revision' => $currentRev->getId(),
396  'count' => $fetchCount(),
397  'dependencyModTS' => $this->getLastModifiedTimes()['dependencyModTS']
398  ];
399  },
400  [
401  'touchedCallback' => function (){
402  return $this->getLastModified();
403  },
404  'version' => 2,
405  'lockTSE' => WANObjectCache::TTL_MINUTE * 5
406  ]
407  )['count'];
408  }
409 
415  protected function getAnonCount( $pageId, RevisionRecord $fromRev = null ) {
416  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
417 
418  $cond = [
419  'rev_page' => $pageId,
420  'actor_user IS NULL',
421  $dbr->bitAnd( 'rev_deleted',
423  ];
424 
425  if ( $fromRev ) {
426  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
427  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
428  "OR rev_timestamp > {$oldTs}";
429  }
430 
431  $edits = $dbr->selectRowCount(
432  [
433  'revision_actor_temp',
434  'revision',
435  'actor'
436  ],
437  '1',
438  $cond,
439  __METHOD__,
440  [ 'LIMIT' => self::COUNT_LIMITS['anonymous'] + 1 ], // extra to detect truncation
441  [
442  'revision' => [
443  'JOIN',
444  'revactor_rev = rev_id AND revactor_page = rev_page'
445  ],
446  'actor' => [
447  'JOIN',
448  'revactor_actor = actor_id'
449  ]
450  ]
451  );
452  return $edits;
453  }
454 
460  protected function getBotCount( $pageId, RevisionRecord $fromRev = null ) {
461  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
462 
463  $cond = [
464  'rev_page=' . intval( $pageId ),
465  $dbr->bitAnd( 'rev_deleted',
467  'EXISTS(' .
468  $dbr->selectSQLText(
469  'user_groups',
470  '1',
471  [
472  'actor.actor_user = ug_user',
473  'ug_group' => $this->permissionManager->getGroupsWithPermission( 'bot' ),
474  'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
475  ],
476  __METHOD__
477  ) .
478  ')'
479  ];
480  if ( $fromRev ) {
481  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
482  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
483  "OR rev_timestamp > {$oldTs}";
484  }
485 
486  $edits = $dbr->selectRowCount(
487  [
488  'revision_actor_temp',
489  'revision',
490  'actor',
491  ],
492  '1',
493  $cond,
494  __METHOD__,
495  [ 'LIMIT' => self::COUNT_LIMITS['bot'] + 1 ], // extra to detect truncation
496  [
497  'revision' => [
498  'JOIN',
499  'revactor_rev = rev_id AND revactor_page = rev_page'
500  ],
501  'actor' => [
502  'JOIN',
503  'revactor_actor = actor_id'
504  ],
505  ]
506  );
507  return $edits;
508  }
509 
516  protected function getEditorsCount( $pageId,
517  RevisionRecord $fromRev = null,
518  RevisionRecord $toRev = null
519  ) {
520  list( $fromRev, $toRev ) = $this->orderRevisions( $fromRev, $toRev );
521  return $this->revisionStore->countAuthorsBetween( $pageId, $fromRev,
522  $toRev, $this->user, self::COUNT_LIMITS['editors'] );
523  }
524 
530  protected function getRevertedCount( $pageId, RevisionRecord $fromRev = null ) {
531  $tagIds = [];
532 
533  foreach ( ChangeTags::REVERT_TAGS as $tagName ) {
534  try {
535  $tagIds[] = $this->changeTagDefStore->getId( $tagName );
536  } catch ( NameTableAccessException $e ) {
537  // If no revisions are tagged with a name, no tag id will be present
538  }
539  }
540  if ( !$tagIds ) {
541  return 0;
542  }
543 
544  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
545 
546  $cond = [
547  'rev_page' => $pageId,
548  $dbr->bitAnd( 'rev_deleted', RevisionRecord::DELETED_TEXT ) . " = 0"
549  ];
550  if ( $fromRev ) {
551  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
552  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
553  "OR rev_timestamp > {$oldTs}";
554  }
555  $edits = $dbr->selectRowCount(
556  [
557  'revision',
558  'change_tag'
559  ],
560  '1',
561  [ 'rev_page' => $pageId ],
562  __METHOD__,
563  [
564  'LIMIT' => self::COUNT_LIMITS['reverted'] + 1, // extra to detect truncation
565  'GROUP BY' => 'rev_id'
566  ],
567  [
568  'change_tag' => [
569  'JOIN',
570  [
571  'ct_rev_id = rev_id',
572  'ct_tag_id' => $tagIds,
573  ]
574  ],
575  ]
576  );
577  return $edits;
578  }
579 
585  protected function getMinorCount( $pageId, RevisionRecord $fromRev = null ) {
586  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
587  $cond = [
588  'rev_page' => $pageId,
589  'rev_minor_edit != 0',
590  $dbr->bitAnd( 'rev_deleted', RevisionRecord::DELETED_TEXT ) . " = 0"
591  ];
592  if ( $fromRev ) {
593  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
594  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
595  "OR rev_timestamp > {$oldTs}";
596  }
597  $edits = $dbr->selectRowCount( 'revision', '1',
598  $cond,
599  __METHOD__,
600  [ 'LIMIT' => self::COUNT_LIMITS['minor'] + 1 ] // extra to detect truncation
601  );
602 
603  return $edits;
604  }
605 
612  protected function getEditsCount(
613  $pageId,
614  RevisionRecord $fromRev = null,
615  RevisionRecord $toRev = null
616  ) {
617  list( $fromRev, $toRev ) = $this->orderRevisions( $fromRev, $toRev );
618  return $this->revisionStore->countRevisionsBetween(
619  $pageId,
620  $fromRev,
621  $toRev,
622  self::COUNT_LIMITS['edits'] // Will be increased by 1 to detect truncation
623  );
624  }
625 
631  private function getRevisionOrThrow( $revId ) {
632  $rev = $this->revisionStore->getRevisionById( $revId );
633  if ( !$rev ) {
634  throw new LocalizedHttpException(
635  new MessageValue( 'rest-nonexistent-revision', [ $revId ] ),
636  404
637  );
638  }
639  return $rev;
640  }
641 
649  private function orderRevisions(
650  RevisionRecord $fromRev = null,
651  RevisionRecord $toRev = null
652  ) {
653  if ( $fromRev && $toRev && ( $fromRev->getTimestamp() > $toRev->getTimestamp() ||
654  ( $fromRev->getTimestamp() === $toRev->getTimestamp()
655  && $fromRev->getId() > $toRev->getId() ) )
656  ) {
657  return [ $toRev, $fromRev ];
658  }
659  return [ $fromRev, $toRev ];
660  }
661 
662  public function needsWriteAccess() {
663  return false;
664  }
665 
666  public function getParamSettings() {
667  return [
668  'title' => [
669  self::PARAM_SOURCE => 'path',
670  ParamValidator::PARAM_TYPE => 'string',
671  ParamValidator::PARAM_REQUIRED => true,
672  ],
673  'type' => [
674  self::PARAM_SOURCE => 'path',
675  ParamValidator::PARAM_TYPE => array_merge(
676  array_keys( self::COUNT_LIMITS ),
677  array_keys( self::DEPRECATED_COUNT_TYPES )
678  ),
679  ParamValidator::PARAM_REQUIRED => true,
680  ],
681  'from' => [
682  self::PARAM_SOURCE => 'query',
683  ParamValidator::PARAM_TYPE => 'integer',
684  ParamValidator::PARAM_REQUIRED => false
685  ],
686  'to' => [
687  self::PARAM_SOURCE => 'query',
688  ParamValidator::PARAM_TYPE => 'integer',
689  ParamValidator::PARAM_REQUIRED => false
690  ]
691  ];
692  }
693 }
MediaWiki\Rest\Handler\PageHistoryCountHandler\$revisionStore
RevisionStore $revisionStore
Definition: PageHistoryCountHandler.php:48
ChangeTags\REVERT_TAGS
const REVERT_TAGS
List of tags which denote a revert of some sort.
Definition: ChangeTags.php:89
MediaWiki\Rest\Handler\PageHistoryCountHandler\run
run( $title, $type)
Definition: PageHistoryCountHandler.php:137
MediaWiki\Rest\Handler\PageHistoryCountHandler\$titleObject
Title $titleObject
Definition: PageHistoryCountHandler.php:72
MediaWiki\Rest\Handler
Definition: AbstractContributionHandler.php:3
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:361
MediaWiki\Rest\Handler\PageHistoryCountHandler\$cache
WANObjectCache $cache
Definition: PageHistoryCountHandler.php:60
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:46
MediaWiki\Rest\Handler\PageHistoryCountHandler\getBotCount
getBotCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:460
MediaWiki\Rest\Handler\getResponseFactory
getResponseFactory()
Get the ResponseFactory which can be used to generate Response objects.
Definition: Handler.php:154
Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:80
MediaWiki\Rest\Handler\PageHistoryCountHandler\getEditsCount
getEditsCount( $pageId, RevisionRecord $fromRev=null, RevisionRecord $toRev=null)
Definition: PageHistoryCountHandler.php:612
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1831
MediaWiki\Rest\Handler\PageHistoryCountHandler\getAnonCount
getAnonCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:415
MediaWiki\Rest\Handler\PageHistoryCountHandler\$revision
RevisionRecord bool $revision
Definition: PageHistoryCountHandler.php:66
MediaWiki\Rest\Handler\PageHistoryCountHandler\getParamSettings
getParamSettings()
Fetch ParamValidator settings for parameters.
Definition: PageHistoryCountHandler.php:666
MediaWiki\Rest\Handler\PageHistoryCountHandler\__construct
__construct(RevisionStore $revisionStore, NameTableStoreFactory $nameTableStoreFactory, PermissionManager $permissionManager, ILoadBalancer $loadBalancer, WANObjectCache $cache)
Definition: PageHistoryCountHandler.php:81
MediaWiki\Rest\Handler\PageHistoryCountHandler\COUNT_LIMITS
const COUNT_LIMITS
The maximum number of counts to return per type of revision.
Definition: PageHistoryCountHandler.php:30
MediaWiki\Rest\Handler\PageHistoryCountHandler\getLastModifiedTimes
getLastModifiedTimes()
Returns array with 2 timestamps:
Definition: PageHistoryCountHandler.php:315
Wikimedia\Message\ScalarParam
Value object representing a message parameter holding a single value.
Definition: ScalarParam.php:12
$res
$res
Definition: testCompression.php:57
MediaWiki\Rest\Handler\PageHistoryCountHandler\$changeTagDefStore
NameTableStore $changeTagDefStore
Definition: PageHistoryCountHandler.php:51
MediaWiki\Rest\Handler\PageHistoryCountHandler\getEtag
getEtag()
Choosing to not implement etags in this handler.
Definition: PageHistoryCountHandler.php:356
Wikimedia\Message\MessageValue
Value object representing a message for i18n.
Definition: MessageValue.php:16
$dbr
$dbr
Definition: testCompression.php:54
MediaWiki\Rest\Handler\PageHistoryCountHandler\getLastModified
getLastModified()
Returns latest of 2 timestamps:
Definition: PageHistoryCountHandler.php:302
MediaWiki\Rest\Handler\PageHistoryCountHandler\validateParameterCombination
validateParameterCombination( $type)
Validates that the provided parameter combination is supported.
Definition: PageHistoryCountHandler.php:108
MediaWiki\Rest\Handler\PageHistoryCountHandler\DEPRECATED_COUNT_TYPES
const DEPRECATED_COUNT_TYPES
Definition: PageHistoryCountHandler.php:39
MediaWiki\Rest\Handler\PageHistoryCountHandler\getRevisionOrThrow
getRevisionOrThrow( $revId)
Definition: PageHistoryCountHandler.php:631
MediaWiki\Rest\Handler\PageHistoryCountHandler\$permissionManager
PermissionManager $permissionManager
Definition: PageHistoryCountHandler.php:54
MediaWiki\Rest\Handler\PageHistoryCountHandler\getRevertedCount
getRevertedCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:530
ChangeTags
Definition: ChangeTags.php:30
MediaWiki\Rest\Handler\PageHistoryCountHandler
Handler class for Core REST API endpoints that perform operations on revisions.
Definition: PageHistoryCountHandler.php:28
MediaWiki\Rest\Handler\PageHistoryCountHandler\orderRevisions
orderRevisions(RevisionRecord $fromRev=null, RevisionRecord $toRev=null)
Reorders revisions if they are present.
Definition: PageHistoryCountHandler.php:649
MediaWiki\Rest\Handler\PageHistoryCountHandler\getEditorsCount
getEditorsCount( $pageId, RevisionRecord $fromRev=null, RevisionRecord $toRev=null)
Definition: PageHistoryCountHandler.php:516
MediaWiki\Rest\Handler\PageHistoryCountHandler\getTitle
getTitle()
Definition: PageHistoryCountHandler.php:289
wfTimestampOrNull
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
Definition: GlobalFunctions.php:1847
MediaWiki\Rest\Handler\PageHistoryCountHandler\getMinorCount
getMinorCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:585
MediaWiki\Rest\Response
Definition: Response.php:8
$title
$title
Definition: testCompression.php:38
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
RequestContext
Group all the pieces relevant to the context of a request into one instance @newable.
Definition: RequestContext.php:39
MediaWiki\Rest\Handler\getValidatedParams
getValidatedParams()
Fetch the validated parameters.
Definition: Handler.php:265
MediaWiki\Rest\Handler\PageHistoryCountHandler\$lastModifiedTimes
array $lastModifiedTimes
Definition: PageHistoryCountHandler.php:69
MediaWiki\Rest\Handler\PageHistoryCountHandler\$user
User $user
Definition: PageHistoryCountHandler.php:63
MediaWiki\Permissions\PermissionManager
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Definition: PermissionManager.php:51
Revision\RevisionRecord\DELETED_USER
const DELETED_USER
Definition: RevisionRecord.php:52
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:125
MediaWiki\Storage\NameTableStore
Definition: NameTableStore.php:36
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:454
MediaWiki\Rest\Handler\PageHistoryCountHandler\getCount
getCount( $type)
Definition: PageHistoryCountHandler.php:183
MediaWiki\Rest\Handler\PageHistoryCountHandler\$loadBalancer
ILoadBalancer $loadBalancer
Definition: PageHistoryCountHandler.php:57
MediaWiki\Storage\NameTableStoreFactory\getChangeTagDef
getChangeTagDef( $wiki=false)
Get a NameTableStore for the change_tag_def table.
Definition: NameTableStoreFactory.php:127
Title
Represents a title within MediaWiki.
Definition: Title.php:46
MediaWiki\Rest\Handler\PageHistoryCountHandler\loggingTableTime
loggingTableTime( $pageId)
Return timestamp of latest entry in logging table for given page id.
Definition: PageHistoryCountHandler.php:336
Revision\RevisionRecord\DELETED_TEXT
const DELETED_TEXT
Definition: RevisionRecord.php:50
MediaWiki\Storage\NameTableAccessException
Exception representing a failure to look up a row from a name table.
Definition: NameTableAccessException.php:33
MediaWiki\Storage\NameTableStoreFactory
Definition: NameTableStoreFactory.php:26
MediaWiki\Rest\Handler\PageHistoryCountHandler\needsWriteAccess
needsWriteAccess()
Indicates whether this route requires write access.
Definition: PageHistoryCountHandler.php:662
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:56
MediaWiki\Rest\Handler\PageHistoryCountHandler\getCachedCount
getCachedCount( $type, callable $fetchCount)
Definition: PageHistoryCountHandler.php:365
MediaWiki\Rest\Handler\PageHistoryCountHandler\normalizeType
normalizeType( $type)
Definition: PageHistoryCountHandler.php:98
Wikimedia\ParamValidator\ParamValidator
Service for formatting and validating API parameters.
Definition: ParamValidator.php:42
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81
MediaWiki\Rest\LocalizedHttpException
@newable
Definition: LocalizedHttpException.php:10
Wikimedia\Message\ParamType
The constants used to specify parameter types.
Definition: ParamType.php:11
MediaWiki\Rest\Handler\PageHistoryCountHandler\getCurrentRevision
getCurrentRevision()
Definition: PageHistoryCountHandler.php:274
MediaWiki\Rest\SimpleHandler
Definition: SimpleHandler.php:15
$type
$type
Definition: testCompression.php:52
MediaWiki\Rest\Handler\PageHistoryCountHandler\MAX_AGE_200
const MAX_AGE_200
Definition: PageHistoryCountHandler.php:45