MediaWiki  master
RevisionRecord.php
Go to the documentation of this file.
1 <?php
23 namespace MediaWiki\Revision;
24 
26 use Content;
27 use InvalidArgumentException;
35 use Title;
36 use Wikimedia\NonSerializable\NonSerializableTrait;
37 
47 abstract class RevisionRecord implements WikiAwareEntity {
49  use NonSerializableTrait;
51 
52  // RevisionRecord deletion constants
53  public const DELETED_TEXT = 1;
54  public const DELETED_COMMENT = 2;
55  public const DELETED_USER = 4;
56  public const DELETED_RESTRICTED = 8;
57  public const SUPPRESSED_USER = self::DELETED_USER | self::DELETED_RESTRICTED; // convenience
58  public const SUPPRESSED_ALL = self::DELETED_TEXT | self::DELETED_COMMENT | self::DELETED_USER |
59  self::DELETED_RESTRICTED; // convenience
60 
61  // Audience options for accessors
62  public const FOR_PUBLIC = 1;
63  public const FOR_THIS_USER = 2;
64  public const RAW = 3;
65 
67  protected $wikiId = false;
69  protected $mId;
71  protected $mPageId;
73  protected $mUser;
75  protected $mMinorEdit = false;
77  protected $mTimestamp;
79  protected $mDeleted = 0;
81  protected $mSize;
83  protected $mSha1;
85  protected $mParentId;
87  protected $mComment;
88 
90  protected $mPage;
91 
93  protected $mSlots;
94 
103  public function __construct( PageIdentity $page, RevisionSlots $slots, $wikiId = self::LOCAL ) {
104  $this->assertWikiIdParam( $wikiId );
105 
106  $this->mPage = $page;
107  $this->mSlots = $slots;
108  $this->wikiId = $wikiId;
109  $this->mPageId = $this->getArticleId( $page );
110  }
111 
118  public function hasSameContent( RevisionRecord $rec ) {
119  if ( $rec === $this ) {
120  return true;
121  }
122 
123  if ( $this->getId() !== null && $this->getId() === $rec->getId() ) {
124  return true;
125  }
126 
127  // check size before hash, since size is quicker to compute
128  if ( $this->getSize() !== $rec->getSize() ) {
129  return false;
130  }
131 
132  // instead of checking the hash, we could also check the content addresses of all slots.
133 
134  if ( $this->getSha1() === $rec->getSha1() ) {
135  return true;
136  }
137 
138  return false;
139  }
140 
156  public function getContent( $role, $audience = self::FOR_PUBLIC, Authority $performer = null ) {
157  // XXX: throwing an exception would be nicer, but would a further
158  // departure from the old signature of Revision::getContent() when it existed,
159  // and thus result in more complex and error prone refactoring.
160  if ( !$this->audienceCan( self::DELETED_TEXT, $audience, $performer ) ) {
161  return null;
162  }
163 
164  $content = $this->getSlot( $role, $audience, $performer )->getContent();
165  return $content->copy();
166  }
167 
180  public function getSlot( $role, $audience = self::FOR_PUBLIC, Authority $performer = null ) {
181  $slot = $this->mSlots->getSlot( $role );
182 
183  if ( !$this->audienceCan( self::DELETED_TEXT, $audience, $performer ) ) {
184  return SlotRecord::newWithSuppressedContent( $slot );
185  }
186 
187  return $slot;
188  }
189 
197  public function hasSlot( $role ) {
198  return $this->mSlots->hasSlot( $role );
199  }
200 
207  public function getSlotRoles() {
208  return $this->mSlots->getSlotRoles();
209  }
210 
222  public function getSlots() {
223  return $this->mSlots;
224  }
225 
240  public function getOriginalSlots() {
241  return new RevisionSlots( $this->mSlots->getOriginalSlots() );
242  }
243 
255  public function getInheritedSlots() {
256  return new RevisionSlots( $this->mSlots->getInheritedSlots() );
257  }
258 
265  public function getPrimarySlots(): RevisionSlots {
266  return new RevisionSlots( $this->mSlots->getPrimarySlots() );
267  }
268 
279  public function getId( $wikiId = self::LOCAL ) {
280  $this->deprecateInvalidCrossWiki( $wikiId, '1.36' );
281  return $this->mId;
282  }
283 
297  public function getParentId( $wikiId = self::LOCAL ) {
298  $this->deprecateInvalidCrossWiki( $wikiId, '1.36' );
299  return $this->mParentId;
300  }
301 
312  abstract public function getSize();
313 
325  abstract public function getSha1();
326 
335  public function getPageId( $wikiId = self::LOCAL ) {
336  $this->deprecateInvalidCrossWiki( $wikiId, '1.36' );
337  return $this->mPageId;
338  }
339 
345  public function getWikiId() {
346  return $this->wikiId;
347  }
348 
355  public function getPageAsLinkTarget() {
356  // TODO: Should be TitleValue::newFromPage( $this->mPage ),
357  // but Title is used too much still, so let's keep propagating it
358  return Title::castFromPageIdentity( $this->mPage );
359  }
360 
370  public function getPage() {
371  return $this->mPage;
372  }
373 
389  public function getUser( $audience = self::FOR_PUBLIC, Authority $performer = null ) {
390  if ( !$this->audienceCan( self::DELETED_USER, $audience, $performer ) ) {
391  return null;
392  } else {
393  return $this->mUser;
394  }
395  }
396 
413  public function getComment( $audience = self::FOR_PUBLIC, Authority $performer = null ) {
414  if ( !$this->audienceCan( self::DELETED_COMMENT, $audience, $performer ) ) {
415  return null;
416  } else {
417  return $this->mComment;
418  }
419  }
420 
426  public function isMinor() {
427  return (bool)$this->mMinorEdit;
428  }
429 
437  public function isDeleted( $field ) {
438  return ( $this->getVisibility() & $field ) == $field;
439  }
440 
448  public function getVisibility() {
449  return (int)$this->mDeleted;
450  }
451 
459  public function getTimestamp() {
460  return $this->mTimestamp;
461  }
462 
479  public function audienceCan( $field, $audience, Authority $performer = null ) {
480  if ( $audience == self::FOR_PUBLIC && $this->isDeleted( $field ) ) {
481  return false;
482  } elseif ( $audience == self::FOR_THIS_USER ) {
483  if ( !$performer ) {
484  throw new InvalidArgumentException(
485  'An Authority object must be given when checking FOR_THIS_USER audience.'
486  );
487  }
488 
489  if ( !$this->userCan( $field, $performer ) ) {
490  return false;
491  }
492  }
493 
494  return true;
495  }
496 
509  public function userCan( $field, Authority $performer ) {
510  return self::userCanBitfield( $this->getVisibility(), $field, $performer, $this->mPage );
511  }
512 
529  public static function userCanBitfield( $bitfield, $field, Authority $performer, PageIdentity $page = null ) {
530  if ( $bitfield & $field ) { // aspect is deleted
531  if ( $bitfield & self::DELETED_RESTRICTED ) {
532  $permissions = [ 'suppressrevision', 'viewsuppressed' ];
533  } elseif ( $field & self::DELETED_TEXT ) {
534  $permissions = [ 'deletedtext' ];
535  } else {
536  $permissions = [ 'deletedhistory' ];
537  }
538 
539  $permissionlist = implode( ', ', $permissions );
540  if ( $page === null ) {
541  wfDebug( "Checking for $permissionlist due to $field match on $bitfield" );
542  return $performer->isAllowedAny( ...$permissions );
543  } else {
544  wfDebug( "Checking for $permissionlist on $page due to $field match on $bitfield" );
545  foreach ( $permissions as $perm ) {
546  if ( $performer->authorizeRead( $perm, $page ) ) {
547  return true;
548  }
549  }
550  return false;
551  }
552  } else {
553  return true;
554  }
555  }
556 
568  public function isReadyForInsertion() {
569  // NOTE: don't check getSize() and getSha1(), since that may cause the full content to
570  // be loaded in order to calculate the values. Just assume these methods will not return
571  // null if mSlots is not empty.
572 
573  // NOTE: getId() and getPageId() may return null before a revision is saved, so don't
574  // check them.
575 
576  return $this->getTimestamp() !== null
577  && $this->getComment( self::RAW ) !== null
578  && $this->getUser( self::RAW ) !== null
579  && $this->mSlots->getSlotRoles() !== [];
580  }
581 
587  public function isCurrent() {
588  return false;
589  }
590 }
591 
596 class_alias( RevisionRecord::class, 'MediaWiki\Storage\RevisionRecord' );
MediaWiki\Revision\RevisionRecord\$mParentId
int null $mParentId
Definition: RevisionRecord.php:85
MediaWiki\Revision\RevisionRecord\RAW
const RAW
Definition: RevisionRecord.php:64
MediaWiki\Revision\RevisionRecord\SUPPRESSED_ALL
const SUPPRESSED_ALL
Definition: RevisionRecord.php:58
Page\PageIdentity
Interface for objects (potentially) representing an editable wiki page.
Definition: PageIdentity.php:64
MediaWiki\Revision\RevisionRecord\SUPPRESSED_USER
const SUPPRESSED_USER
Definition: RevisionRecord.php:57
MediaWiki\DAO\WikiAwareEntityTrait
trait WikiAwareEntityTrait
Definition: WikiAwareEntityTrait.php:32
MediaWiki\Revision\RevisionRecord\isReadyForInsertion
isReadyForInsertion()
Returns whether this RevisionRecord is ready for insertion, that is, whether it contains all informat...
Definition: RevisionRecord.php:568
MediaWiki\Revision\RevisionRecord\getContent
getContent( $role, $audience=self::FOR_PUBLIC, Authority $performer=null)
Returns the Content of the given slot of this revision.
Definition: RevisionRecord.php:156
MediaWiki\Revision\RevisionRecord\getUser
getUser( $audience=self::FOR_PUBLIC, Authority $performer=null)
Fetch revision's author's user identity, if it's available to the specified audience.
Definition: RevisionRecord.php:389
MediaWiki\Revision\RevisionRecord\$mComment
CommentStoreComment null $mComment
Definition: RevisionRecord.php:87
MediaWiki\Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:47
MediaWiki\Revision\RevisionRecord\$mTimestamp
string null $mTimestamp
Definition: RevisionRecord.php:77
MediaWiki\DAO\deprecateInvalidCrossWiki
deprecateInvalidCrossWiki( $wikiId, string $since)
Emits a deprecation warning $since version if $wikiId is not the same as this wiki.
Definition: WikiAwareEntityTrait.php:70
MediaWiki\Revision\RevisionRecord\DELETED_USER
const DELETED_USER
Definition: RevisionRecord.php:55
MediaWiki\Revision\RevisionRecord\isCurrent
isCurrent()
Checks whether the revision record is a stored current revision.
Definition: RevisionRecord.php:587
MediaWiki\Revision\RevisionRecord\getPrimarySlots
getPrimarySlots()
Returns primary slots (those that are not derived).
Definition: RevisionRecord.php:265
MediaWiki\Revision\RevisionRecord\$mSlots
RevisionSlots $mSlots
Definition: RevisionRecord.php:93
MediaWiki\Revision\SlotRecord\newWithSuppressedContent
static newWithSuppressedContent(SlotRecord $slot)
Returns a new SlotRecord just like the given $slot, except that calling getContent() will fail with a...
Definition: SlotRecord.php:70
MediaWiki\Revision\RevisionRecord\getPage
getPage()
Returns the page this revision belongs to.
Definition: RevisionRecord.php:370
MediaWiki\Revision\RevisionRecord\getPageId
getPageId( $wikiId=self::LOCAL)
Get the page ID.
Definition: RevisionRecord.php:335
MediaWiki\Revision\RevisionRecord\isMinor
isMinor()
MCR migration note: this replaced Revision::isMinor.
Definition: RevisionRecord.php:426
MediaWiki\Permissions\Authority\authorizeRead
authorizeRead(string $action, PageIdentity $target, PermissionStatus $status=null)
Authorize read access.
MediaWiki\Revision\RevisionRecord\getSha1
getSha1()
Returns the base36 sha1 of this revision.
MediaWiki\Revision\RevisionRecord\hasSlot
hasSlot( $role)
Returns whether the given slot is defined in this revision.
Definition: RevisionRecord.php:197
MediaWiki\DAO\WikiAwareEntity
Marker interface for entities aware of the wiki they belong to.
Definition: WikiAwareEntity.php:34
MediaWiki\Revision\RevisionRecord\$mMinorEdit
bool $mMinorEdit
Definition: RevisionRecord.php:75
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:39
MediaWiki\Permissions\Authority\isAllowedAny
isAllowedAny(... $permissions)
Checks whether this authority has any of the given permissions in general.
Title\castFromPageIdentity
static castFromPageIdentity(?PageIdentity $pageIdentity)
Return a Title for a given PageIdentity.
Definition: Title.php:364
MediaWiki\Revision
Definition: ContributionsLookup.php:3
MediaWiki\Page\LegacyArticleIdAccess
trait LegacyArticleIdAccess
Definition: LegacyArticleIdAccess.php:26
MediaWiki\Revision\RevisionRecord\DELETED_TEXT
const DELETED_TEXT
Definition: RevisionRecord.php:53
MediaWiki\Revision\RevisionRecord\$mPageId
int $mPageId
Definition: RevisionRecord.php:71
MediaWiki\Revision\RevisionRecord\DELETED_COMMENT
const DELETED_COMMENT
Definition: RevisionRecord.php:54
MediaWiki\Revision\RevisionRecord\$mPage
PageIdentity $mPage
Definition: RevisionRecord.php:90
MediaWiki\Revision\RevisionRecord\$wikiId
string false $wikiId
Wiki ID; false means the current wiki.
Definition: RevisionRecord.php:67
MediaWiki\Revision\RevisionRecord\$mSha1
string null $mSha1
Definition: RevisionRecord.php:83
MediaWiki\Revision\RevisionRecord\getComment
getComment( $audience=self::FOR_PUBLIC, Authority $performer=null)
Fetch revision comment, if it's available to the specified audience.
Definition: RevisionRecord.php:413
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:894
MediaWiki\Revision\RevisionRecord\audienceCan
audienceCan( $field, $audience, Authority $performer=null)
Check that the given audience has access to the given field.
Definition: RevisionRecord.php:479
MediaWiki\Revision\RevisionRecord\getSlots
getSlots()
Returns the slots defined for this revision.
Definition: RevisionRecord.php:222
MediaWiki\Permissions\Authority
This interface represents the authority associated the current execution context, such as a web reque...
Definition: Authority.php:37
MediaWiki\Revision\RevisionRecord\getParentId
getParentId( $wikiId=self::LOCAL)
Get parent revision ID (the original previous page revision).
Definition: RevisionRecord.php:297
$content
$content
Definition: router.php:76
MediaWiki\Revision\RevisionRecord\getInheritedSlots
getInheritedSlots()
Returns slots inherited from some previous revision.
Definition: RevisionRecord.php:255
MediaWiki\Revision\RevisionRecord\getPageAsLinkTarget
getPageAsLinkTarget()
Returns the title of the page this revision is associated with as a LinkTarget object.
Definition: RevisionRecord.php:355
MediaWiki\Revision\RevisionRecord\__construct
__construct(PageIdentity $page, RevisionSlots $slots, $wikiId=self::LOCAL)
Definition: RevisionRecord.php:103
MediaWiki\DAO\assertWikiIdParam
assertWikiIdParam( $wikiId)
Asserts correct $wikiId parameter was passed.
Definition: WikiAwareEntityTrait.php:88
Content
Base interface for content objects.
Definition: Content.php:35
MediaWiki\Revision\RevisionRecord\getWikiId
getWikiId()
Get the ID of the wiki this revision belongs to.
Definition: RevisionRecord.php:345
MediaWiki\Revision\RevisionRecord\getSlotRoles
getSlotRoles()
Returns the slot names (roles) of all slots present in this revision.
Definition: RevisionRecord.php:207
Title
Represents a title within MediaWiki.
Definition: Title.php:49
MediaWiki\Revision\RevisionRecord\getId
getId( $wikiId=self::LOCAL)
Get revision ID.
Definition: RevisionRecord.php:279
MediaWiki\Revision\RevisionRecord\isDeleted
isDeleted( $field)
MCR migration note: this replaced Revision::isDeleted.
Definition: RevisionRecord.php:437
MediaWiki\Revision\RevisionRecord\getOriginalSlots
getOriginalSlots()
Returns the slots that originate in this revision.
Definition: RevisionRecord.php:240
MediaWiki\Revision\RevisionRecord\userCan
userCan( $field, Authority $performer)
Determine if the give authority is allowed to view a particular field of this revision,...
Definition: RevisionRecord.php:509
MediaWiki\Revision\RevisionSlots
Value object representing the set of slots belonging to a revision.
Definition: RevisionSlots.php:41
MediaWiki\Revision\RevisionRecord\getTimestamp
getTimestamp()
MCR migration note: this replaced Revision::getTimestamp.
Definition: RevisionRecord.php:459
MediaWiki\Revision\RevisionRecord\getSize
getSize()
Returns the nominal size of this revision, in bogo-bytes.
MediaWiki\Revision\RevisionRecord\FOR_THIS_USER
const FOR_THIS_USER
Definition: RevisionRecord.php:63
MediaWiki\Revision\RevisionRecord\$mDeleted
int $mDeleted
using the DELETED_XXX and SUPPRESSED_XXX flags
Definition: RevisionRecord.php:79
MediaWiki\Revision\RevisionRecord\userCanBitfield
static userCanBitfield( $bitfield, $field, Authority $performer, PageIdentity $page=null)
Determine if the current user is allowed to view a particular field of this revision,...
Definition: RevisionRecord.php:529
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
MediaWiki\Revision\RevisionRecord\$mUser
UserIdentity null $mUser
Definition: RevisionRecord.php:73
MediaWiki\Revision\RevisionRecord\DELETED_RESTRICTED
const DELETED_RESTRICTED
Definition: RevisionRecord.php:56
MediaWiki\Revision\RevisionRecord\$mSize
int null $mSize
Definition: RevisionRecord.php:81
MediaWiki\Revision\RevisionRecord\hasSameContent
hasSameContent(RevisionRecord $rec)
Definition: RevisionRecord.php:118
MediaWiki\Revision\RevisionRecord\FOR_PUBLIC
const FOR_PUBLIC
Definition: RevisionRecord.php:62
CommentStoreComment
Value object for a comment stored by CommentStore.
Definition: CommentStoreComment.php:30
MediaWiki\Revision\RevisionRecord\getVisibility
getVisibility()
Get the deletion bitfield of the revision.
Definition: RevisionRecord.php:448
MediaWiki\Revision\RevisionRecord\getSlot
getSlot( $role, $audience=self::FOR_PUBLIC, Authority $performer=null)
Returns meta-data for the given slot.
Definition: RevisionRecord.php:180
MediaWiki\Revision\RevisionRecord\$mId
int null $mId
Definition: RevisionRecord.php:69