MediaWiki  master
PageHistoryCountHandler.php
Go to the documentation of this file.
1 <?php
2 
3 namespace MediaWiki\Rest\Handler;
4 
6 use ChangeTags;
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 $pageLookup;
61 
63  private $cache;
64 
66  private $actorMigration;
67 
69  private $revision = false;
70 
73 
75  private $page = false;
76 
86  public function __construct(
88  NameTableStoreFactory $nameTableStoreFactory,
94  ) {
95  $this->revisionStore = $revisionStore;
96  $this->changeTagDefStore = $nameTableStoreFactory->getChangeTagDef();
97  $this->groupPermissionsLookup = $groupPermissionsLookup;
98  $this->loadBalancer = $loadBalancer;
99  $this->cache = $cache;
100  $this->pageLookup = $pageLookup;
101  $this->actorMigration = $actorMigration;
102  }
103 
104  private function normalizeType( $type ) {
105  return self::DEPRECATED_COUNT_TYPES[$type] ?? $type;
106  }
107 
114  private function validateParameterCombination( $type ) {
115  $params = $this->getValidatedParams();
116  if ( !$params ) {
117  return;
118  }
119 
120  if ( $params['from'] || $params['to'] ) {
121  if ( $type === 'edits' || $type === 'editors' ) {
122  if ( !$params['from'] || !$params['to'] ) {
123  throw new LocalizedHttpException(
124  new MessageValue( 'rest-pagehistorycount-parameters-invalid' ),
125  400
126  );
127  }
128  } else {
129  throw new LocalizedHttpException(
130  new MessageValue( 'rest-pagehistorycount-parameters-invalid' ),
131  400
132  );
133  }
134  }
135  }
136 
143  public function run( $title, $type ) {
144  $normalizedType = $this->normalizeType( $type );
145  $this->validateParameterCombination( $normalizedType );
146  $page = $this->getPage();
147  if ( !$page ) {
148  throw new LocalizedHttpException(
149  new MessageValue( 'rest-nonexistent-title',
150  [ new ScalarParam( ParamType::PLAINTEXT, $title ) ]
151  ),
152  404
153  );
154  }
155 
156  if ( !$this->getAuthority()->authorizeRead( 'read', $page ) ) {
157  throw new LocalizedHttpException(
158  new MessageValue( 'rest-permission-denied-title',
159  [ new ScalarParam( ParamType::PLAINTEXT, $title ) ]
160  ),
161  403
162  );
163  }
164 
165  $count = $this->getCount( $normalizedType );
166  $countLimit = self::COUNT_LIMITS[$normalizedType];
167  $response = $this->getResponseFactory()->createJson( [
168  'count' => $count > $countLimit ? $countLimit : $count,
169  'limit' => $count > $countLimit
170  ] );
171  $response->setHeader( 'Cache-Control', 'max-age=' . self::MAX_AGE_200 );
172 
173  // Inform clients who use a deprecated "type" value, so they can adjust
174  if ( isset( self::DEPRECATED_COUNT_TYPES[$type] ) ) {
175  $docs = '<https://www.mediawiki.org/wiki/API:REST/History_API' .
176  '#Get_page_history_counts>; rel="deprecation"';
177  $response->setHeader( 'Deprecation', 'version="v1"' );
178  $response->setHeader( 'Link', $docs );
179  }
180 
181  return $response;
182  }
183 
189  private function getCount( $type ) {
190  $pageId = $this->getPage()->getId();
191  switch ( $type ) {
192  case 'anonymous':
193  return $this->getCachedCount( $type,
194  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
195  return $this->getAnonCount( $pageId, $fromRev );
196  }
197  );
198 
199  case 'bot':
200  return $this->getCachedCount( $type,
201  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
202  return $this->getBotCount( $pageId, $fromRev );
203  }
204  );
205 
206  case 'editors':
207  $from = $this->getValidatedParams()['from'] ?? null;
208  $to = $this->getValidatedParams()['to'] ?? null;
209  if ( $from || $to ) {
210  return $this->getEditorsCount(
211  $pageId,
212  $from ? $this->getRevisionOrThrow( $from ) : null,
213  $to ? $this->getRevisionOrThrow( $to ) : null
214  );
215  } else {
216  return $this->getCachedCount( $type,
217  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
218  return $this->getEditorsCount( $pageId, $fromRev );
219  } );
220  }
221 
222  case 'edits':
223  $from = $this->getValidatedParams()['from'] ?? null;
224  $to = $this->getValidatedParams()['to'] ?? null;
225  if ( $from || $to ) {
226  return $this->getEditsCount(
227  $pageId,
228  $from ? $this->getRevisionOrThrow( $from ) : null,
229  $to ? $this->getRevisionOrThrow( $to ) : null
230  );
231  } else {
232  return $this->getCachedCount( $type,
233  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
234  return $this->getEditsCount( $pageId, $fromRev );
235  }
236  );
237  }
238 
239  case 'reverted':
240  return $this->getCachedCount( $type,
241  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
242  return $this->getRevertedCount( $pageId, $fromRev );
243  }
244  );
245 
246  case 'minor':
247  // The query for minor counts is inefficient for the database for pages with many revisions.
248  // If the specified title contains more revisions than allowed, we will return an error.
249  $editsCount = $this->getCachedCount( 'edits',
250  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
251  return $this->getEditsCount( $pageId, $fromRev );
252  }
253  );
254  if ( $editsCount > self::COUNT_LIMITS[$type] * 2 ) {
255  throw new LocalizedHttpException(
256  new MessageValue( 'rest-pagehistorycount-too-many-revisions' ),
257  500
258  );
259  }
260  return $this->getCachedCount( $type,
261  function ( RevisionRecord $fromRev = null ) use ( $pageId ) {
262  return $this->getMinorCount( $pageId, $fromRev );
263  }
264  );
265 
266  default:
267  throw new LocalizedHttpException(
268  new MessageValue( 'rest-pagehistorycount-type-unrecognized',
269  [ new ScalarParam( ParamType::PLAINTEXT, $type ) ]
270  ),
271  500
272  );
273  }
274  }
275 
279  private function getCurrentRevision(): ?RevisionRecord {
280  if ( $this->revision === false ) {
281  $page = $this->getPage();
282  if ( $page ) {
283  $this->revision = $this->revisionStore->getKnownCurrentRevision( $page ) ?: null;
284  } else {
285  $this->revision = null;
286  }
287  }
288  return $this->revision;
289  }
290 
294  private function getPage(): ?ExistingPageRecord {
295  if ( $this->page === false ) {
296  $this->page = $this->pageLookup->getExistingPageByText(
297  $this->getValidatedParams()['title']
298  );
299  }
300  return $this->page;
301  }
302 
309  protected function getLastModified() {
311  if ( $lastModifiedTimes ) {
312  return max( array_values( $lastModifiedTimes ) );
313  }
314  return null;
315  }
316 
323  protected function getLastModifiedTimes() {
324  $currentRev = $this->getCurrentRevision();
325  if ( !$currentRev ) {
326  return null;
327  }
328  if ( $this->lastModifiedTimes === null ) {
329  $currentRevTime = (int)wfTimestampOrNull( TS_UNIX, $currentRev->getTimestamp() );
330  $loggingTableTime = $this->loggingTableTime( $currentRev->getPageId() );
331  $this->lastModifiedTimes = [
332  'currentRevTS' => $currentRevTime,
333  'dependencyModTS' => $loggingTableTime
334  ];
335  }
337  }
338 
344  private function loggingTableTime( $pageId ) {
345  $res = $this->loadBalancer->getConnectionRef( DB_REPLICA )->selectField(
346  'logging',
347  'MAX(log_timestamp)',
348  [ 'log_page' => $pageId ],
349  __METHOD__
350  );
351  return $res ? (int)wfTimestamp( TS_UNIX, $res ) : null;
352  }
353 
364  protected function getEtag() {
365  return null;
366  }
367 
373  private function getCachedCount( $type,
374  callable $fetchCount
375  ) {
376  $pageId = $this->getPage()->getId();
377  return $this->cache->getWithSetCallback(
378  $this->cache->makeKey( 'rest', 'pagehistorycount', $pageId, $type ),
379  WANObjectCache::TTL_WEEK,
380  function ( $oldValue ) use ( $fetchCount ) {
381  $currentRev = $this->getCurrentRevision();
382  if ( $oldValue ) {
383  // Last modified timestamp was NOT a dependency change (e.g. revdel)
384  $doIncrementalUpdate = (
385  $this->getLastModified() != $this->getLastModifiedTimes()['dependencyModTS']
386  );
387  if ( $doIncrementalUpdate ) {
388  $rev = $this->revisionStore->getRevisionById( $oldValue['revision'] );
389  if ( $rev ) {
390  $additionalCount = $fetchCount( $rev );
391  return [
392  'revision' => $currentRev->getId(),
393  'count' => $oldValue['count'] + $additionalCount,
394  'dependencyModTS' => $this->getLastModifiedTimes()['dependencyModTS']
395  ];
396  }
397  }
398  }
399  // Nothing was previously stored, or incremental update was done for too long,
400  // recalculate from scratch.
401  return [
402  'revision' => $currentRev->getId(),
403  'count' => $fetchCount(),
404  'dependencyModTS' => $this->getLastModifiedTimes()['dependencyModTS']
405  ];
406  },
407  [
408  'touchedCallback' => function (){
409  return $this->getLastModified();
410  },
411  'version' => 2,
412  'lockTSE' => WANObjectCache::TTL_MINUTE * 5
413  ]
414  )['count'];
415  }
416 
422  protected function getAnonCount( $pageId, RevisionRecord $fromRev = null ) {
423  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
424 
425  $revQuery = $this->actorMigration->getJoin( 'rev_user' );
426 
427  $cond = [
428  'rev_page' => $pageId,
429  'actor_user IS NULL',
430  $dbr->bitAnd( 'rev_deleted',
432  ];
433 
434  if ( $fromRev ) {
435  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
436  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
437  "OR rev_timestamp > {$oldTs}";
438  }
439 
440  // This redundant join condition tells MySQL that rev_page and revactor_page are the
441  // same, so it can propagate the condition
442  if ( isset( $revQuery['tables']['temp_rev_user'] ) /* SCHEMA_COMPAT_READ_TEMP */ ) {
443  $revQuery['joins']['temp_rev_user'][1] =
444  "temp_rev_user.revactor_rev = rev_id AND revactor_page = rev_page";
445  }
446 
447  $edits = $dbr->selectRowCount(
448  [
449  'revision',
450  ] + $revQuery['tables'],
451  '1',
452  $cond,
453  __METHOD__,
454  [ 'LIMIT' => self::COUNT_LIMITS['anonymous'] + 1 ], // extra to detect truncation
455  $revQuery['joins']
456  );
457  return $edits;
458  }
459 
465  protected function getBotCount( $pageId, RevisionRecord $fromRev = null ) {
466  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
467 
468  $revQuery = $this->actorMigration->getJoin( 'rev_user' );
469 
470  // This redundant join condition tells MySQL that rev_page and revactor_page are the
471  // same, so it can propagate the condition
472  if ( isset( $revQuery['tables']['temp_rev_user'] ) /* SCHEMA_COMPAT_READ_TEMP */ ) {
473  $revQuery['joins']['temp_rev_user'][1] =
474  "temp_rev_user.revactor_rev = rev_id AND revactor_page = rev_page";
475  }
476 
477  $cond = [
478  'rev_page=' . intval( $pageId ),
479  $dbr->bitAnd( 'rev_deleted',
481  'EXISTS(' .
482  $dbr->selectSQLText(
483  'user_groups',
484  '1',
485  [
486  $revQuery['fields']['rev_user'] . ' = ug_user',
487  'ug_group' => $this->groupPermissionsLookup->getGroupsWithPermission( 'bot' ),
488  'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
489  ],
490  __METHOD__
491  ) .
492  ')'
493  ];
494  if ( $fromRev ) {
495  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
496  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
497  "OR rev_timestamp > {$oldTs}";
498  }
499 
500  $edits = $dbr->selectRowCount(
501  [
502  'revision',
503  ] + $revQuery['tables'],
504  '1',
505  $cond,
506  __METHOD__,
507  [ 'LIMIT' => self::COUNT_LIMITS['bot'] + 1 ], // extra to detect truncation
508  $revQuery['joins']
509  );
510  return $edits;
511  }
512 
519  protected function getEditorsCount( $pageId,
520  RevisionRecord $fromRev = null,
521  RevisionRecord $toRev = null
522  ) {
523  list( $fromRev, $toRev ) = $this->orderRevisions( $fromRev, $toRev );
524  return $this->revisionStore->countAuthorsBetween( $pageId, $fromRev,
525  $toRev, $this->getAuthority(), self::COUNT_LIMITS['editors'] );
526  }
527 
533  protected function getRevertedCount( $pageId, RevisionRecord $fromRev = null ) {
534  $tagIds = [];
535 
536  foreach ( ChangeTags::REVERT_TAGS as $tagName ) {
537  try {
538  $tagIds[] = $this->changeTagDefStore->getId( $tagName );
539  } catch ( NameTableAccessException $e ) {
540  // If no revisions are tagged with a name, no tag id will be present
541  }
542  }
543  if ( !$tagIds ) {
544  return 0;
545  }
546 
547  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
548 
549  $cond = [
550  'rev_page' => $pageId,
551  $dbr->bitAnd( 'rev_deleted', RevisionRecord::DELETED_TEXT ) . " = 0"
552  ];
553  if ( $fromRev ) {
554  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
555  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
556  "OR rev_timestamp > {$oldTs}";
557  }
558  $edits = $dbr->selectRowCount(
559  [
560  'revision',
561  'change_tag'
562  ],
563  '1',
564  [ 'rev_page' => $pageId ],
565  __METHOD__,
566  [
567  'LIMIT' => self::COUNT_LIMITS['reverted'] + 1, // extra to detect truncation
568  'GROUP BY' => 'rev_id'
569  ],
570  [
571  'change_tag' => [
572  'JOIN',
573  [
574  'ct_rev_id = rev_id',
575  'ct_tag_id' => $tagIds,
576  ]
577  ],
578  ]
579  );
580  return $edits;
581  }
582 
588  protected function getMinorCount( $pageId, RevisionRecord $fromRev = null ) {
589  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
590  $cond = [
591  'rev_page' => $pageId,
592  'rev_minor_edit != 0',
593  $dbr->bitAnd( 'rev_deleted', RevisionRecord::DELETED_TEXT ) . " = 0"
594  ];
595  if ( $fromRev ) {
596  $oldTs = $dbr->addQuotes( $dbr->timestamp( $fromRev->getTimestamp() ) );
597  $cond[] = "(rev_timestamp = {$oldTs} AND rev_id > {$fromRev->getId()}) " .
598  "OR rev_timestamp > {$oldTs}";
599  }
600  $edits = $dbr->selectRowCount( 'revision', '1',
601  $cond,
602  __METHOD__,
603  [ 'LIMIT' => self::COUNT_LIMITS['minor'] + 1 ] // extra to detect truncation
604  );
605 
606  return $edits;
607  }
608 
615  protected function getEditsCount(
616  $pageId,
617  RevisionRecord $fromRev = null,
618  RevisionRecord $toRev = null
619  ) {
620  list( $fromRev, $toRev ) = $this->orderRevisions( $fromRev, $toRev );
621  return $this->revisionStore->countRevisionsBetween(
622  $pageId,
623  $fromRev,
624  $toRev,
625  self::COUNT_LIMITS['edits'] // Will be increased by 1 to detect truncation
626  );
627  }
628 
634  private function getRevisionOrThrow( $revId ) {
635  $rev = $this->revisionStore->getRevisionById( $revId );
636  if ( !$rev ) {
637  throw new LocalizedHttpException(
638  new MessageValue( 'rest-nonexistent-revision', [ $revId ] ),
639  404
640  );
641  }
642  return $rev;
643  }
644 
652  private function orderRevisions(
653  RevisionRecord $fromRev = null,
654  RevisionRecord $toRev = null
655  ) {
656  if ( $fromRev && $toRev && ( $fromRev->getTimestamp() > $toRev->getTimestamp() ||
657  ( $fromRev->getTimestamp() === $toRev->getTimestamp()
658  && $fromRev->getId() > $toRev->getId() ) )
659  ) {
660  return [ $toRev, $fromRev ];
661  }
662  return [ $fromRev, $toRev ];
663  }
664 
665  public function needsWriteAccess() {
666  return false;
667  }
668 
669  public function getParamSettings() {
670  return [
671  'title' => [
672  self::PARAM_SOURCE => 'path',
673  ParamValidator::PARAM_TYPE => 'string',
674  ParamValidator::PARAM_REQUIRED => true,
675  ],
676  'type' => [
677  self::PARAM_SOURCE => 'path',
678  ParamValidator::PARAM_TYPE => array_merge(
679  array_keys( self::COUNT_LIMITS ),
680  array_keys( self::DEPRECATED_COUNT_TYPES )
681  ),
682  ParamValidator::PARAM_REQUIRED => true,
683  ],
684  'from' => [
685  self::PARAM_SOURCE => 'query',
686  ParamValidator::PARAM_TYPE => 'integer',
687  ParamValidator::PARAM_REQUIRED => false
688  ],
689  'to' => [
690  self::PARAM_SOURCE => 'query',
691  ParamValidator::PARAM_TYPE => 'integer',
692  ParamValidator::PARAM_REQUIRED => false
693  ]
694  ];
695  }
696 }
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:102
MediaWiki\Rest\Handler\PageHistoryCountHandler\run
run( $title, $type)
Definition: PageHistoryCountHandler.php:143
MediaWiki\Rest\Handler
Definition: AbstractContributionHandler.php:3
MediaWiki\Rest\Handler\PageHistoryCountHandler\$cache
WANObjectCache $cache
Definition: PageHistoryCountHandler.php:63
MediaWiki\Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:47
MediaWiki\Revision\RevisionRecord\DELETED_USER
const DELETED_USER
Definition: RevisionRecord.php:55
MediaWiki\Rest\Handler\PageHistoryCountHandler\getBotCount
getBotCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:465
MediaWiki\Rest\Handler\getResponseFactory
getResponseFactory()
Get the ResponseFactory which can be used to generate Response objects.
Definition: Handler.php:170
MediaWiki\Permissions\GroupPermissionsLookup
Definition: GroupPermissionsLookup.php:30
MediaWiki\Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:89
MediaWiki\Rest\Handler\PageHistoryCountHandler\getEditsCount
getEditsCount( $pageId, RevisionRecord $fromRev=null, RevisionRecord $toRev=null)
Definition: PageHistoryCountHandler.php:615
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1649
MediaWiki\Rest\Handler\PageHistoryCountHandler\getAnonCount
getAnonCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:422
MediaWiki\Rest\Handler\PageHistoryCountHandler\$revision
RevisionRecord false null $revision
Definition: PageHistoryCountHandler.php:69
MediaWiki\Rest\Handler\PageHistoryCountHandler\getParamSettings
getParamSettings()
Fetch ParamValidator settings for parameters.
Definition: PageHistoryCountHandler.php:669
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:323
Wikimedia\Message\ScalarParam
Value object representing a message parameter holding a single value.
Definition: ScalarParam.php:14
ActorMigration
This is not intended to be a long-term part of MediaWiki; it will be deprecated and removed once acto...
Definition: ActorMigration.php:15
$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:364
$revQuery
$revQuery
Definition: testCompression.php:56
Wikimedia\Message\MessageValue
Value object representing a message for i18n.
Definition: MessageValue.php:18
MediaWiki\Rest\Handler\PageHistoryCountHandler\$page
ExistingPageRecord false null $page
Definition: PageHistoryCountHandler.php:75
$dbr
$dbr
Definition: testCompression.php:54
MediaWiki\Rest\Handler\PageHistoryCountHandler\getLastModified
getLastModified()
Returns latest of 2 timestamps:
Definition: PageHistoryCountHandler.php:309
MediaWiki\Revision\RevisionRecord\DELETED_TEXT
const DELETED_TEXT
Definition: RevisionRecord.php:53
MediaWiki\Rest\Handler\PageHistoryCountHandler\validateParameterCombination
validateParameterCombination( $type)
Validates that the provided parameter combination is supported.
Definition: PageHistoryCountHandler.php:114
MediaWiki\Rest\Handler\PageHistoryCountHandler\DEPRECATED_COUNT_TYPES
const DEPRECATED_COUNT_TYPES
Definition: PageHistoryCountHandler.php:39
MediaWiki\Rest\Handler\PageHistoryCountHandler\$groupPermissionsLookup
GroupPermissionsLookup $groupPermissionsLookup
Definition: PageHistoryCountHandler.php:54
MediaWiki\Rest\Handler\PageHistoryCountHandler\__construct
__construct(RevisionStore $revisionStore, NameTableStoreFactory $nameTableStoreFactory, GroupPermissionsLookup $groupPermissionsLookup, ILoadBalancer $loadBalancer, WANObjectCache $cache, PageLookup $pageLookup, ActorMigration $actorMigration)
Definition: PageHistoryCountHandler.php:86
MediaWiki\Rest\Handler\PageHistoryCountHandler\getRevisionOrThrow
getRevisionOrThrow( $revId)
Definition: PageHistoryCountHandler.php:634
MediaWiki\Rest\Handler\PageHistoryCountHandler\getRevertedCount
getRevertedCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:533
ChangeTags
Definition: ChangeTags.php:32
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:652
MediaWiki\Rest\Handler\PageHistoryCountHandler\getEditorsCount
getEditorsCount( $pageId, RevisionRecord $fromRev=null, RevisionRecord $toRev=null)
Definition: PageHistoryCountHandler.php:519
MediaWiki\Rest\Handler\PageHistoryCountHandler\$pageLookup
PageLookup $pageLookup
Definition: PageHistoryCountHandler.php:60
wfTimestampOrNull
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
Definition: GlobalFunctions.php:1665
MediaWiki\Rest\Handler\PageHistoryCountHandler\getPage
getPage()
Definition: PageHistoryCountHandler.php:294
MediaWiki\Rest\Handler\PageHistoryCountHandler\getMinorCount
getMinorCount( $pageId, RevisionRecord $fromRev=null)
Definition: PageHistoryCountHandler.php:588
MediaWiki\Rest\Response
Definition: Response.php:8
$title
$title
Definition: testCompression.php:38
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
MediaWiki\Rest\Handler\getValidatedParams
getValidatedParams()
Fetch the validated parameters.
Definition: Handler.php:282
MediaWiki\Rest\Handler\PageHistoryCountHandler\$lastModifiedTimes
array $lastModifiedTimes
Definition: PageHistoryCountHandler.php:72
Page\ExistingPageRecord
Data record representing a page that currently exists as an editable page on a wiki.
Definition: ExistingPageRecord.php:15
Page\PageLookup
Service interface for looking up information about wiki pages.
Definition: PageLookup.php:14
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:131
MediaWiki\Storage\NameTableStore
Definition: NameTableStore.php:36
MediaWiki\Rest\Handler\PageHistoryCountHandler\getCount
getCount( $type)
Definition: PageHistoryCountHandler.php:189
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
MediaWiki\Rest\Handler\PageHistoryCountHandler\$actorMigration
ActorMigration $actorMigration
Definition: PageHistoryCountHandler.php:66
MediaWiki\Rest\Handler\PageHistoryCountHandler\loggingTableTime
loggingTableTime( $pageId)
Return timestamp of latest entry in logging table for given page id.
Definition: PageHistoryCountHandler.php:344
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:665
MediaWiki\Rest\Handler\PageHistoryCountHandler\getCachedCount
getCachedCount( $type, callable $fetchCount)
Definition: PageHistoryCountHandler.php:373
MediaWiki\Rest\Handler\getAuthority
getAuthority()
Get the current acting authority.
Definition: Handler.php:148
MediaWiki\Rest\Handler\PageHistoryCountHandler\normalizeType
normalizeType( $type)
Definition: PageHistoryCountHandler.php:104
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
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:279
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