MediaWiki  master
ApiQueryRevisionsBase.php
Go to the documentation of this file.
1 <?php
41 
50 
51  // region Constants for internal use. Don't use externally.
54  // Bits to indicate the results of the revdel permission check on a revision,
55  // see self::checkRevDel()
56  private const IS_DELETED = 1; // Whether the field is revision-deleted
57  private const CANNOT_VIEW = 2; // Whether the user cannot view the field due to revdel
58 
59  // endregion
60 
64 
65  protected $fld_ids = false, $fld_flags = false, $fld_timestamp = false,
66  $fld_size = false, $fld_slotsize = false, $fld_sha1 = false, $fld_slotsha1 = false,
67  $fld_comment = false, $fld_parsedcomment = false, $fld_user = false, $fld_userid = false,
68  $fld_content = false, $fld_tags = false, $fld_contentmodel = false, $fld_roles = false,
69  $fld_parsetree = false;
70 
75  private $numUncachedDiffs = 0;
76 
78  private $revisionStore;
79 
81  private $contentHandlerFactory;
82 
84  private $parserFactory;
85 
87  private $slotRoleRegistry;
88 
90  private $contentRenderer;
91 
93  private $contentTransformer;
94 
96  private $commentFormatter;
97 
99  private $tempUserCreator;
100 
102  private $userFactory;
103 
120  public function __construct(
121  ApiQuery $queryModule,
122  $moduleName,
123  $paramPrefix = '',
124  RevisionStore $revisionStore = null,
125  IContentHandlerFactory $contentHandlerFactory = null,
126  ParserFactory $parserFactory = null,
127  SlotRoleRegistry $slotRoleRegistry = null,
128  ContentRenderer $contentRenderer = null,
129  ContentTransformer $contentTransformer = null,
130  CommentFormatter $commentFormatter = null,
131  TempUserCreator $tempUserCreator = null,
132  UserFactory $userFactory = null
133  ) {
134  parent::__construct( $queryModule, $moduleName, $paramPrefix );
135  // This class is part of the stable interface and
136  // therefor fallback to global state, if services are not provided
137  $services = MediaWikiServices::getInstance();
138  $this->revisionStore = $revisionStore ?? $services->getRevisionStore();
139  $this->contentHandlerFactory = $contentHandlerFactory ?? $services->getContentHandlerFactory();
140  $this->parserFactory = $parserFactory ?? $services->getParserFactory();
141  $this->slotRoleRegistry = $slotRoleRegistry ?? $services->getSlotRoleRegistry();
142  $this->contentRenderer = $contentRenderer ?? $services->getContentRenderer();
143  $this->contentTransformer = $contentTransformer ?? $services->getContentTransformer();
144  $this->commentFormatter = $commentFormatter ?? $services->getCommentFormatter();
145  $this->tempUserCreator = $tempUserCreator ?? $services->getTempUserCreator();
146  $this->userFactory = $userFactory ?? $services->getUserFactory();
147  }
148 
149  public function execute() {
150  $this->run();
151  }
152 
153  public function executeGenerator( $resultPageSet ) {
154  $this->run( $resultPageSet );
155  }
156 
161  abstract protected function run( ApiPageSet $resultPageSet = null );
162 
168  protected function parseParameters( $params ) {
169  $prop = array_fill_keys( $params['prop'], true );
170 
171  $this->fld_ids = isset( $prop['ids'] );
172  $this->fld_flags = isset( $prop['flags'] );
173  $this->fld_timestamp = isset( $prop['timestamp'] );
174  $this->fld_comment = isset( $prop['comment'] );
175  $this->fld_parsedcomment = isset( $prop['parsedcomment'] );
176  $this->fld_size = isset( $prop['size'] );
177  $this->fld_slotsize = isset( $prop['slotsize'] );
178  $this->fld_sha1 = isset( $prop['sha1'] );
179  $this->fld_slotsha1 = isset( $prop['slotsha1'] );
180  $this->fld_content = isset( $prop['content'] );
181  $this->fld_contentmodel = isset( $prop['contentmodel'] );
182  $this->fld_userid = isset( $prop['userid'] );
183  $this->fld_user = isset( $prop['user'] );
184  $this->fld_tags = isset( $prop['tags'] );
185  $this->fld_roles = isset( $prop['roles'] );
186  $this->fld_parsetree = isset( $prop['parsetree'] );
187 
188  $this->slotRoles = $params['slots'];
189 
190  if ( $this->slotRoles !== null ) {
191  if ( $this->fld_parsetree ) {
192  $this->dieWithError( [
193  'apierror-invalidparammix-cannotusewith',
194  $this->encodeParamName( 'prop=parsetree' ),
195  $this->encodeParamName( 'slots' ),
196  ], 'invalidparammix' );
197  }
198  foreach ( [
199  'expandtemplates', 'generatexml', 'parse', 'diffto', 'difftotext', 'difftotextpst',
200  'contentformat'
201  ] as $p ) {
202  if ( $params[$p] !== null && $params[$p] !== false ) {
203  $this->dieWithError( [
204  'apierror-invalidparammix-cannotusewith',
205  $this->encodeParamName( $p ),
206  $this->encodeParamName( 'slots' ),
207  ], 'invalidparammix' );
208  }
209  }
210  }
211 
212  if ( !empty( $params['contentformat'] ) ) {
213  $this->contentFormat = $params['contentformat'];
214  }
215 
216  $this->limit = $params['limit'];
217 
218  if ( $params['difftotext'] !== null ) {
219  $this->difftotext = $params['difftotext'];
220  $this->difftotextpst = $params['difftotextpst'];
221  } elseif ( $params['diffto'] !== null ) {
222  if ( $params['diffto'] == 'cur' ) {
223  $params['diffto'] = 0;
224  }
225  if ( ( !ctype_digit( $params['diffto'] ) || $params['diffto'] < 0 )
226  && $params['diffto'] != 'prev' && $params['diffto'] != 'next'
227  ) {
228  $p = $this->getModulePrefix();
229  $this->dieWithError( [ 'apierror-baddiffto', $p ], 'diffto' );
230  }
231  // Check whether the revision exists and is readable,
232  // DifferenceEngine returns a rather ambiguous empty
233  // string if that's not the case
234  if ( is_numeric( $params['diffto'] ) && $params['diffto'] != 0 ) {
235  $difftoRev = $this->revisionStore->getRevisionById( $params['diffto'] );
236  if ( !$difftoRev ) {
237  $this->dieWithError( [ 'apierror-nosuchrevid', $params['diffto'] ] );
238  }
239  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable T240141
240  $revDel = $this->checkRevDel( $difftoRev, RevisionRecord::DELETED_TEXT );
241  if ( $revDel & self::CANNOT_VIEW ) {
242  $this->addWarning( [ 'apiwarn-difftohidden', $difftoRev->getId() ] );
243  $params['diffto'] = null;
244  }
245  }
246  $this->diffto = $params['diffto'];
247  }
248 
249  $this->fetchContent = $this->fld_content || $this->diffto !== null
250  || $this->difftotext !== null || $this->fld_parsetree;
251 
252  $smallLimit = false;
253  if ( $this->fetchContent ) {
254  $smallLimit = true;
255  $this->expandTemplates = $params['expandtemplates'];
256  $this->generateXML = $params['generatexml'];
257  $this->parseContent = $params['parse'];
258  if ( $this->parseContent ) {
259  // Must manually initialize unset limit
260  $this->limit ??= 1;
261  }
262  $this->section = $params['section'] ?? false;
263  }
264 
265  $userMax = $this->parseContent ? 1 : ( $smallLimit ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1 );
266  $botMax = $this->parseContent ? 1 : ( $smallLimit ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2 );
267  if ( $this->limit == 'max' ) {
268  $this->limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
269  if ( $this->setParsedLimit ) {
270  $this->getResult()->addParsedLimit( $this->getModuleName(), $this->limit );
271  }
272  }
273 
274  $this->limit = $this->getMain()->getParamValidator()->validateValue(
275  $this, 'limit', $this->limit ?? 10, [
276  ParamValidator::PARAM_TYPE => 'limit',
277  IntegerDef::PARAM_MIN => 1,
278  IntegerDef::PARAM_MAX => $userMax,
279  IntegerDef::PARAM_MAX2 => $botMax,
280  IntegerDef::PARAM_IGNORE_RANGE => true,
281  ]
282  );
283 
284  $this->needSlots = $this->fetchContent || $this->fld_contentmodel ||
285  $this->fld_slotsize || $this->fld_slotsha1;
286  if ( $this->needSlots && $this->slotRoles === null ) {
287  $encParam = $this->encodeParamName( 'slots' );
288  $name = $this->getModuleName();
289  $parent = $this->getParent();
290  $parentParam = $parent->encodeParamName( $parent->getModuleManager()->getModuleGroup( $name ) );
291  $this->addDeprecation(
292  [ 'apiwarn-deprecation-missingparam', $encParam ],
293  "action=query&{$parentParam}={$name}&!{$encParam}"
294  );
295  }
296  }
297 
305  private function checkRevDel( RevisionRecord $revision, $field ) {
306  $ret = $revision->isDeleted( $field ) ? self::IS_DELETED : 0;
307  if ( $ret ) {
308  $canSee = $revision->userCan( $field, $this->getAuthority() );
309  $ret |= ( $canSee ? 0 : self::CANNOT_VIEW );
310  }
311  return $ret;
312  }
313 
322  protected function extractRevisionInfo( RevisionRecord $revision, $row ) {
323  $vals = [];
324  $anyHidden = false;
325 
326  if ( $this->fld_ids ) {
327  $vals['revid'] = (int)$revision->getId();
328  if ( $revision->getParentId() !== null ) {
329  $vals['parentid'] = (int)$revision->getParentId();
330  }
331  }
332 
333  if ( $this->fld_flags ) {
334  $vals['minor'] = $revision->isMinor();
335  }
336 
337  if ( $this->fld_user || $this->fld_userid ) {
338  $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_USER );
339  if ( $revDel & self::IS_DELETED ) {
340  $vals['userhidden'] = true;
341  $anyHidden = true;
342  }
343  if ( !( $revDel & self::CANNOT_VIEW ) ) {
344  $u = $revision->getUser( RevisionRecord::RAW );
345  if ( $this->fld_user ) {
346  $vals['user'] = $u->getName();
347  }
348  if ( !$u->isRegistered() ) {
349  $vals['anon'] = true;
350  }
351 
352  if ( $this->fld_userid ) {
353  $vals['userid'] = $u->getId();
354  }
355  }
356  }
357 
358  if ( $this->fld_timestamp ) {
359  $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $revision->getTimestamp() );
360  }
361 
362  if ( $this->fld_size ) {
363  try {
364  $vals['size'] = (int)$revision->getSize();
365  } catch ( RevisionAccessException $e ) {
366  // Back compat: If there's no size, return 0.
367  // @todo: GergÅ‘ says to mention T198099 as a "todo" here.
368  $vals['size'] = 0;
369  }
370  }
371 
372  if ( $this->fld_sha1 ) {
373  $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_TEXT );
374  if ( $revDel & self::IS_DELETED ) {
375  $vals['sha1hidden'] = true;
376  $anyHidden = true;
377  }
378  if ( !( $revDel & self::CANNOT_VIEW ) ) {
379  try {
380  $vals['sha1'] = Wikimedia\base_convert( $revision->getSha1(), 36, 16, 40 );
381  } catch ( RevisionAccessException $e ) {
382  // Back compat: If there's no sha1, return empty string.
383  // @todo: GergÅ‘ says to mention T198099 as a "todo" here.
384  $vals['sha1'] = '';
385  }
386  }
387  }
388 
389  try {
390  if ( $this->fld_roles ) {
391  $vals['roles'] = $revision->getSlotRoles();
392  }
393 
394  if ( $this->needSlots ) {
395  $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_TEXT );
396  if ( ( $this->fld_slotsha1 || $this->fetchContent ) && ( $revDel & self::IS_DELETED ) ) {
397  $anyHidden = true;
398  }
399  $vals = array_merge( $vals, $this->extractAllSlotInfo( $revision, $revDel ) );
400  }
401  } catch ( RevisionAccessException $ex ) {
402  // This is here so T212428 doesn't spam the log.
403  // TODO: find out why T212428 happens in the first place!
404  $vals['slotsmissing'] = true;
405 
406  LoggerFactory::getInstance( 'api-warning' )->error(
407  'Failed to access revision slots',
408  [ 'revision' => $revision->getId(), 'exception' => $ex, ]
409  );
410  }
411 
412  if ( $this->fld_comment || $this->fld_parsedcomment ) {
413  $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_COMMENT );
414  if ( $revDel & self::IS_DELETED ) {
415  $vals['commenthidden'] = true;
416  $anyHidden = true;
417  }
418  if ( !( $revDel & self::CANNOT_VIEW ) ) {
419  $comment = $revision->getComment( RevisionRecord::RAW );
420  $comment = $comment->text ?? '';
421 
422  if ( $this->fld_comment ) {
423  $vals['comment'] = $comment;
424  }
425 
426  if ( $this->fld_parsedcomment ) {
427  $vals['parsedcomment'] = $this->commentFormatter->format(
428  $comment, Title::newFromLinkTarget( $revision->getPageAsLinkTarget() )
429  );
430  }
431  }
432  }
433 
434  if ( $this->fld_tags ) {
435  if ( $row->ts_tags ) {
436  $tags = explode( ',', $row->ts_tags );
437  ApiResult::setIndexedTagName( $tags, 'tag' );
438  $vals['tags'] = $tags;
439  } else {
440  $vals['tags'] = [];
441  }
442  }
443 
444  if ( $anyHidden && $revision->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ) {
445  $vals['suppressed'] = true;
446  }
447 
448  return $vals;
449  }
450 
460  private function extractAllSlotInfo( RevisionRecord $revision, $revDel ): array {
461  $vals = [];
462 
463  if ( $this->slotRoles === null ) {
464  try {
465  $slot = $revision->getSlot( SlotRecord::MAIN, RevisionRecord::RAW );
466  } catch ( RevisionAccessException $e ) {
467  // Back compat: If there's no slot, there's no content, so set 'textmissing'
468  // @todo: GergÅ‘ says to mention T198099 as a "todo" here.
469  $vals['textmissing'] = true;
470  $slot = null;
471  }
472 
473  if ( $slot ) {
474  $content = null;
475  $vals += $this->extractSlotInfo( $slot, $revDel, $content );
476  if ( !empty( $vals['nosuchsection'] ) ) {
477  $this->dieWithError(
478  [
479  'apierror-nosuchsection-what',
480  wfEscapeWikiText( $this->section ),
481  $this->msg( 'revid', $revision->getId() )
482  ],
483  'nosuchsection'
484  );
485  }
486  if ( $content ) {
487  $vals += $this->extractDeprecatedContent( $content, $revision );
488  }
489  }
490  } else {
491  $roles = array_intersect( $this->slotRoles, $revision->getSlotRoles() );
492  $vals['slots'] = [
494  ];
495  foreach ( $roles as $role ) {
496  try {
497  $slot = $revision->getSlot( $role, RevisionRecord::RAW );
498  } catch ( RevisionAccessException $e ) {
499  // Don't error out here so the client can still process other slots/revisions.
500  // @todo: GergÅ‘ says to mention T198099 as a "todo" here.
501  $vals['slots'][$role]['missing'] = true;
502  continue;
503  }
504  $content = null;
505  $vals['slots'][$role] = $this->extractSlotInfo( $slot, $revDel, $content );
506  // @todo Move this into extractSlotInfo() (and remove its $content parameter)
507  // when extractDeprecatedContent() is no more.
508  if ( $content ) {
510  $vals['slots'][$role]['contentmodel'] = $content->getModel();
511  $vals['slots'][$role]['contentformat'] = $content->getDefaultFormat();
513  $vals['slots'][$role],
514  'content',
515  $content->serialize()
516  );
517  }
518  }
519  ApiResult::setArrayType( $vals['slots'], 'kvp', 'role' );
520  ApiResult::setIndexedTagName( $vals['slots'], 'slot' );
521  }
522  return $vals;
523  }
524 
534  private function extractSlotInfo( SlotRecord $slot, $revDel, &$content = null ) {
535  $vals = [];
536  ApiResult::setArrayType( $vals, 'assoc' );
537 
538  if ( $this->fld_slotsize ) {
539  $vals['size'] = (int)$slot->getSize();
540  }
541 
542  if ( $this->fld_slotsha1 ) {
543  if ( $revDel & self::IS_DELETED ) {
544  $vals['sha1hidden'] = true;
545  }
546  if ( !( $revDel & self::CANNOT_VIEW ) ) {
547  if ( $slot->getSha1() != '' ) {
548  $vals['sha1'] = Wikimedia\base_convert( $slot->getSha1(), 36, 16, 40 );
549  } else {
550  $vals['sha1'] = '';
551  }
552  }
553  }
554 
555  if ( $this->fld_contentmodel ) {
556  $vals['contentmodel'] = $slot->getModel();
557  }
558 
559  $content = null;
560  if ( $this->fetchContent ) {
561  if ( $revDel & self::IS_DELETED ) {
562  $vals['texthidden'] = true;
563  }
564  if ( !( $revDel & self::CANNOT_VIEW ) ) {
565  try {
566  $content = $slot->getContent();
567  } catch ( RevisionAccessException $e ) {
568  // @todo: GergÅ‘ says to mention T198099 as a "todo" here.
569  $vals['textmissing'] = true;
570  }
571  // Expand templates after getting section content because
572  // template-added sections don't count and Parser::preprocess()
573  // will have less input
574  if ( $content && $this->section !== false ) {
575  $content = $content->getSection( $this->section );
576  if ( !$content ) {
577  $vals['nosuchsection'] = true;
578  }
579  }
580  }
581  }
582 
583  return $vals;
584  }
585 
592  private function extractDeprecatedContent( Content $content, RevisionRecord $revision ) {
593  $vals = [];
594  $title = Title::newFromLinkTarget( $revision->getPageAsLinkTarget() );
595 
596  if ( $this->fld_parsetree || ( $this->fld_content && $this->generateXML ) ) {
597  if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
599  '@phan-var WikitextContent $content';
600  $t = $content->getText(); # note: don't set $text
601 
602  $parser = $this->parserFactory->create();
603  $parser->startExternalParse(
604  $title,
605  ParserOptions::newFromContext( $this->getContext() ),
606  Parser::OT_PREPROCESS
607  );
608  $dom = $parser->preprocessToDom( $t );
609  // @phan-suppress-next-line PhanUndeclaredMethodInCallable
610  if ( is_callable( [ $dom, 'saveXML' ] ) ) {
611  // @phan-suppress-next-line PhanUndeclaredMethod
612  $xml = $dom->saveXML();
613  } else {
614  // @phan-suppress-next-line PhanUndeclaredMethod
615  $xml = $dom->__toString();
616  }
617  $vals['parsetree'] = $xml;
618  } else {
619  $vals['badcontentformatforparsetree'] = true;
620  $this->addWarning(
621  [
622  'apierror-parsetree-notwikitext-title',
623  wfEscapeWikiText( $title->getPrefixedText() ),
624  $content->getModel()
625  ],
626  'parsetree-notwikitext'
627  );
628  }
629  }
630 
631  if ( $this->fld_content ) {
632  $text = null;
633 
634  if ( $this->expandTemplates && !$this->parseContent ) {
635  if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
637  '@phan-var WikitextContent $content';
638  $text = $content->getText();
639 
640  $text = $this->parserFactory->create()->preprocess(
641  $text,
642  $title,
643  ParserOptions::newFromContext( $this->getContext() )
644  );
645  } else {
646  $this->addWarning( [
647  'apierror-templateexpansion-notwikitext',
648  wfEscapeWikiText( $title->getPrefixedText() ),
649  $content->getModel()
650  ] );
651  $vals['badcontentformat'] = true;
652  $text = false;
653  }
654  }
655  if ( $this->parseContent ) {
656  $po = $this->contentRenderer->getParserOutput(
657  $content,
658  $title,
659  $revision->getId(),
660  ParserOptions::newFromContext( $this->getContext() )
661  );
662  $text = $po->getText();
663  }
664 
665  if ( $text === null ) {
666  $format = $this->contentFormat ?: $content->getDefaultFormat();
667  $model = $content->getModel();
668 
669  if ( !$content->isSupportedFormat( $format ) ) {
670  $name = wfEscapeWikiText( $title->getPrefixedText() );
671  $this->addWarning( [ 'apierror-badformat', $this->contentFormat, $model, $name ] );
672  $vals['badcontentformat'] = true;
673  $text = false;
674  } else {
675  $text = $content->serialize( $format );
676  // always include format and model.
677  // Format is needed to deserialize, model is needed to interpret.
678  $vals['contentformat'] = $format;
679  $vals['contentmodel'] = $model;
680  }
681  }
682 
683  if ( $text !== false ) {
684  ApiResult::setContentValue( $vals, 'content', $text );
685  }
686  }
687 
688  if ( $content && ( $this->diffto !== null || $this->difftotext !== null ) ) {
689  if ( $this->numUncachedDiffs < $this->getConfig()->get( MainConfigNames::APIMaxUncachedDiffs ) ) {
690  $vals['diff'] = [];
691  $context = new DerivativeContext( $this->getContext() );
692  $context->setTitle( $title );
693  $handler = $content->getContentHandler();
694 
695  if ( $this->difftotext !== null ) {
696  $model = $title->getContentModel();
697 
698  if ( $this->contentFormat
699  && !$this->contentHandlerFactory->getContentHandler( $model )
700  ->isSupportedFormat( $this->contentFormat )
701  ) {
702  $name = wfEscapeWikiText( $title->getPrefixedText() );
703  $this->addWarning( [ 'apierror-badformat', $this->contentFormat, $model, $name ] );
704  $vals['diff']['badcontentformat'] = true;
705  $engine = null;
706  } else {
707  $difftocontent = $this->contentHandlerFactory->getContentHandler( $model )
708  ->unserializeContent( $this->difftotext, $this->contentFormat );
709 
710  if ( $this->difftotextpst ) {
711  $popts = ParserOptions::newFromContext( $this->getContext() );
712  $difftocontent = $this->contentTransformer->preSaveTransform(
713  $difftocontent,
714  $title,
715  $this->getUserForPreview(),
716  $popts
717  );
718  }
719 
720  $engine = $handler->createDifferenceEngine( $context );
721  $engine->setContent( $content, $difftocontent );
722  }
723  } else {
724  $engine = $handler->createDifferenceEngine( $context, $revision->getId(), $this->diffto );
725  $vals['diff']['from'] = $engine->getOldid();
726  $vals['diff']['to'] = $engine->getNewid();
727  }
728  if ( $engine ) {
729  $difftext = $engine->getDiffBody();
730  ApiResult::setContentValue( $vals['diff'], 'body', $difftext );
731  if ( !$engine->wasCacheHit() ) {
732  $this->numUncachedDiffs++;
733  }
734  foreach ( $engine->getRevisionLoadErrors() as $msg ) {
735  $this->addWarning( $msg );
736  }
737  }
738  } else {
739  $vals['diff']['notcached'] = true;
740  }
741  }
742 
743  return $vals;
744  }
745 
746  private function getUserForPreview() {
747  $user = $this->getUser();
748  if ( $this->tempUserCreator->shouldAutoCreate( $user, 'edit' ) ) {
749  return $this->userFactory->newUnsavedTempUser(
750  $this->tempUserCreator->getStashedNameOrPlaceholder( $this->getRequest()->getSession() )
751  );
752  }
753  return $user;
754  }
755 
762  public function getCacheMode( $params ) {
763  if ( $this->userCanSeeRevDel() ) {
764  return 'private';
765  }
766 
767  return 'public';
768  }
769 
775  public function getAllowedParams() {
776  $slotRoles = $this->slotRoleRegistry->getKnownRoles();
777  sort( $slotRoles, SORT_STRING );
778 
779  return [
780  'prop' => [
781  ParamValidator::PARAM_ISMULTI => true,
782  ParamValidator::PARAM_DEFAULT => 'ids|timestamp|flags|comment|user',
783  ParamValidator::PARAM_TYPE => [
784  'ids',
785  'flags',
786  'timestamp',
787  'user',
788  'userid',
789  'size',
790  'slotsize',
791  'sha1',
792  'slotsha1',
793  'contentmodel',
794  'comment',
795  'parsedcomment',
796  'content',
797  'tags',
798  'roles',
799  'parsetree',
800  ],
801  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-prop',
802  ApiBase::PARAM_HELP_MSG_PER_VALUE => [
803  'ids' => 'apihelp-query+revisions+base-paramvalue-prop-ids',
804  'flags' => 'apihelp-query+revisions+base-paramvalue-prop-flags',
805  'timestamp' => 'apihelp-query+revisions+base-paramvalue-prop-timestamp',
806  'user' => 'apihelp-query+revisions+base-paramvalue-prop-user',
807  'userid' => 'apihelp-query+revisions+base-paramvalue-prop-userid',
808  'size' => 'apihelp-query+revisions+base-paramvalue-prop-size',
809  'slotsize' => 'apihelp-query+revisions+base-paramvalue-prop-slotsize',
810  'sha1' => 'apihelp-query+revisions+base-paramvalue-prop-sha1',
811  'slotsha1' => 'apihelp-query+revisions+base-paramvalue-prop-slotsha1',
812  'contentmodel' => 'apihelp-query+revisions+base-paramvalue-prop-contentmodel',
813  'comment' => 'apihelp-query+revisions+base-paramvalue-prop-comment',
814  'parsedcomment' => 'apihelp-query+revisions+base-paramvalue-prop-parsedcomment',
815  'content' => 'apihelp-query+revisions+base-paramvalue-prop-content',
816  'tags' => 'apihelp-query+revisions+base-paramvalue-prop-tags',
817  'roles' => 'apihelp-query+revisions+base-paramvalue-prop-roles',
818  'parsetree' => [ 'apihelp-query+revisions+base-paramvalue-prop-parsetree',
819  CONTENT_MODEL_WIKITEXT ],
820  ],
821  EnumDef::PARAM_DEPRECATED_VALUES => [
822  'parsetree' => true,
823  ],
824  ],
825  'slots' => [
826  ParamValidator::PARAM_TYPE => $slotRoles,
827  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-slots',
828  ParamValidator::PARAM_ISMULTI => true,
829  ParamValidator::PARAM_ALL => true,
830  ],
831  'limit' => [
832  ParamValidator::PARAM_TYPE => 'limit',
833  IntegerDef::PARAM_MIN => 1,
834  IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
835  IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2,
836  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-limit',
837  ],
838  'expandtemplates' => [
839  ParamValidator::PARAM_DEFAULT => false,
840  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-expandtemplates',
841  ParamValidator::PARAM_DEPRECATED => true,
842  ],
843  'generatexml' => [
844  ParamValidator::PARAM_DEFAULT => false,
845  ParamValidator::PARAM_DEPRECATED => true,
846  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-generatexml',
847  ],
848  'parse' => [
849  ParamValidator::PARAM_DEFAULT => false,
850  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-parse',
851  ParamValidator::PARAM_DEPRECATED => true,
852  ],
853  'section' => [
854  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-section',
855  ],
856  'diffto' => [
857  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-diffto',
858  ParamValidator::PARAM_DEPRECATED => true,
859  ],
860  'difftotext' => [
861  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-difftotext',
862  ParamValidator::PARAM_DEPRECATED => true,
863  ],
864  'difftotextpst' => [
865  ParamValidator::PARAM_DEFAULT => false,
866  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-difftotextpst',
867  ParamValidator::PARAM_DEPRECATED => true,
868  ],
869  'contentformat' => [
870  ParamValidator::PARAM_TYPE => $this->contentHandlerFactory->getAllContentFormats(),
871  ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-contentformat',
872  ParamValidator::PARAM_DEPRECATED => true,
873  ],
874  ];
875  }
876 }
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:211
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition: ApiBase.php:1469
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:513
getMain()
Get the main module.
Definition: ApiBase.php:521
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition: ApiBase.php:1401
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:228
const LIMIT_SML2
Slow query, apihighlimits limit.
Definition: ApiBase.php:234
getResult()
Get the result object.
Definition: ApiBase.php:636
const LIMIT_SML1
Slow query, standard limit.
Definition: ApiBase.php:232
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1387
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:230
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:505
This class contains a list of pages that the client has requested.
Definition: ApiPageSet.php:53
getParent()
Get the parent of this module.Stability: stableto override 1.25 ApiBase|null
encodeParamName( $paramName)
Overrides ApiBase to prepend 'g' to every generator parameter.
A base class for functions common to producing a list of revisions.
$fld_userid
The number of uncached diffs that had to be generated for this request.
$diffto
The number of uncached diffs that had to be generated for this request.
executeGenerator( $resultPageSet)
The number of uncached diffs that had to be generated for this request.
$parseContent
The number of uncached diffs that had to be generated for this request.
$difftotext
The number of uncached diffs that had to be generated for this request.
$fld_sha1
The number of uncached diffs that had to be generated for this request.
$fld_ids
The number of uncached diffs that had to be generated for this request.
$fld_size
The number of uncached diffs that had to be generated for this request.
$fld_tags
The number of uncached diffs that had to be generated for this request.
$generateXML
The number of uncached diffs that had to be generated for this request.
$limit
The number of uncached diffs that had to be generated for this request.
$fld_comment
The number of uncached diffs that had to be generated for this request.
parseParameters( $params)
Parse the parameters into the various instance fields.
$needSlots
The number of uncached diffs that had to be generated for this request.
$expandTemplates
The number of uncached diffs that had to be generated for this request.
__construct(ApiQuery $queryModule, $moduleName, $paramPrefix='', RevisionStore $revisionStore=null, IContentHandlerFactory $contentHandlerFactory=null, ParserFactory $parserFactory=null, SlotRoleRegistry $slotRoleRegistry=null, ContentRenderer $contentRenderer=null, ContentTransformer $contentTransformer=null, CommentFormatter $commentFormatter=null, TempUserCreator $tempUserCreator=null, UserFactory $userFactory=null)
$fld_parsetree
The number of uncached diffs that had to be generated for this request.
$fld_slotsha1
The number of uncached diffs that had to be generated for this request.
$fetchContent
The number of uncached diffs that had to be generated for this request.
$fld_user
The number of uncached diffs that had to be generated for this request.
$fld_roles
The number of uncached diffs that had to be generated for this request.
execute()
The number of uncached diffs that had to be generated for this request.
$section
The number of uncached diffs that had to be generated for this request.
$fld_contentmodel
The number of uncached diffs that had to be generated for this request.
$setParsedLimit
The number of uncached diffs that had to be generated for this request.
$difftotextpst
The number of uncached diffs that had to be generated for this request.
$fld_parsedcomment
The number of uncached diffs that had to be generated for this request.
$fld_timestamp
The number of uncached diffs that had to be generated for this request.
$fld_content
The number of uncached diffs that had to be generated for this request.
$slotRoles
The number of uncached diffs that had to be generated for this request.
$fld_slotsize
The number of uncached diffs that had to be generated for this request.
run(ApiPageSet $resultPageSet=null)
$contentFormat
The number of uncached diffs that had to be generated for this request.
extractRevisionInfo(RevisionRecord $revision, $row)
Extract information from the RevisionRecord.
$fld_flags
The number of uncached diffs that had to be generated for this request.
This is the main query class.
Definition: ApiQuery.php:42
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
Definition: ApiResult.php:716
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:604
const META_KVP_MERGE
Key for the metadata item that indicates that the KVP key should be added into an assoc value,...
Definition: ApiResult.php:129
static setContentValue(array &$arr, $name, $value, $flags=0)
Add an output value to the array by name and mark as META_CONTENT.
Definition: ApiResult.php:467
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
This is the main service interface for converting single-line comments from various DB comment fields...
PSR-3 logger instance factory.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Exception representing a failure to look up a revision.
Page revision base class.
getUser( $audience=self::FOR_PUBLIC, Authority $performer=null)
Fetch revision's author's user identity, if it's available to the specified audience.
getSize()
Returns the nominal size of this revision, in bogo-bytes.
getSlotRoles()
Returns the slot names (roles) of all slots present in this revision.
getParentId( $wikiId=self::LOCAL)
Get parent revision ID (the original previous page revision).
getTimestamp()
MCR migration note: this replaced Revision::getTimestamp.
getComment( $audience=self::FOR_PUBLIC, Authority $performer=null)
Fetch revision comment, if it's available to the specified audience.
getSlot( $role, $audience=self::FOR_PUBLIC, Authority $performer=null)
Returns meta-data for the given slot.
getSha1()
Returns the base36 sha1 of this revision.
isMinor()
MCR migration note: this replaced Revision::isMinor.
getPageAsLinkTarget()
Returns the title of the page this revision is associated with as a LinkTarget object.
userCan( $field, Authority $performer)
Determine if the give authority is allowed to view a particular field of this revision,...
isDeleted( $field)
MCR migration note: this replaced Revision::isDeleted.
getId( $wikiId=self::LOCAL)
Get revision ID.
Service for looking up page revisions.
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:40
getContent()
Returns the Content of the given slot.
Definition: SlotRecord.php:319
getSha1()
Returns the content size.
Definition: SlotRecord.php:558
getSize()
Returns the content size.
Definition: SlotRecord.php:542
getModel()
Returns the content model.
Definition: SlotRecord.php:586
A registry service for SlotRoleHandlers, used to define which slot roles are available on which page.
Represents a title within MediaWiki.
Definition: Title.php:82
Service for temporary user creation.
Creates User objects.
Definition: UserFactory.php:42
Service for formatting and validating API parameters.
Type definition for enumeration types.
Definition: EnumDef.php:32
Type definition for integer types.
Definition: IntegerDef.php:23
Content object for wiki text pages.
Base interface for representing page content.
Definition: Content.php:37
$content
Definition: router.php:76