MediaWiki REL1_31
RevisionRecord.php
Go to the documentation of this file.
1<?php
23namespace MediaWiki\Storage;
24
26use Content;
27use InvalidArgumentException;
28use LogicException;
31use MWException;
32use Title;
33use User;
34use Wikimedia\Assert\Assert;
35
44abstract class RevisionRecord {
45
46 // RevisionRecord deletion constants
47 const DELETED_TEXT = 1;
48 const DELETED_COMMENT = 2;
49 const DELETED_USER = 4;
51 const SUPPRESSED_USER = 12; // convenience
52 const SUPPRESSED_ALL = 15; // convenience
53
54 // Audience options for accessors
55 const FOR_PUBLIC = 1;
56 const FOR_THIS_USER = 2;
57 const RAW = 3;
58
60 protected $mWiki = false;
62 protected $mId;
64 protected $mPageId;
66 protected $mUser;
68 protected $mMinorEdit = false;
70 protected $mTimestamp;
72 protected $mDeleted = 0;
74 protected $mSize;
76 protected $mSha1;
78 protected $mParentId;
80 protected $mComment;
81
83 protected $mTitle; // TODO: we only need the title for permission checks!
84
86 protected $mSlots;
87
99 function __construct( Title $title, RevisionSlots $slots, $wikiId = false ) {
100 Assert::parameterType( 'string|boolean', $wikiId, '$wikiId' );
101
102 $this->mTitle = $title;
103 $this->mSlots = $slots;
104 $this->mWiki = $wikiId;
105
106 // XXX: this is a sensible default, but we may not have a Title object here in the future.
107 $this->mPageId = $title->getArticleID();
108 }
109
115 public function __sleep() {
116 throw new LogicException( __CLASS__ . ' is not serializable.' );
117 }
118
125 public function hasSameContent( RevisionRecord $rec ) {
126 if ( $rec === $this ) {
127 return true;
128 }
129
130 if ( $this->getId() !== null && $this->getId() === $rec->getId() ) {
131 return true;
132 }
133
134 // check size before hash, since size is quicker to compute
135 if ( $this->getSize() !== $rec->getSize() ) {
136 return false;
137 }
138
139 // instead of checking the hash, we could also check the content addresses of all slots.
140
141 if ( $this->getSha1() === $rec->getSha1() ) {
142 return true;
143 }
144
145 return false;
146 }
147
165 public function getContent( $role, $audience = self::FOR_PUBLIC, User $user = null ) {
166 // XXX: throwing an exception would be nicer, but would a further
167 // departure from the signature of Revision::getContent(), and thus
168 // more complex and error prone refactoring.
169 if ( !$this->audienceCan( self::DELETED_TEXT, $audience, $user ) ) {
170 return null;
171 }
172
173 $content = $this->getSlot( $role, $audience, $user )->getContent();
174 return $content->copy();
175 }
176
189 public function getSlot( $role, $audience = self::FOR_PUBLIC, User $user = null ) {
190 $slot = $this->mSlots->getSlot( $role );
191
192 if ( !$this->audienceCan( self::DELETED_TEXT, $audience, $user ) ) {
194 }
195
196 return $slot;
197 }
198
206 public function hasSlot( $role ) {
207 return $this->mSlots->hasSlot( $role );
208 }
209
216 public function getSlotRoles() {
217 return $this->mSlots->getSlotRoles();
218 }
219
229 public function getId() {
230 return $this->mId;
231 }
232
245 public function getParentId() {
246 return $this->mParentId;
247 }
248
259 abstract public function getSize();
260
272 abstract public function getSha1();
273
281 public function getPageId() {
282 return $this->mPageId;
283 }
284
290 public function getWikiId() {
291 return $this->mWiki;
292 }
293
301 public function getPageAsLinkTarget() {
302 return $this->mTitle;
303 }
304
321 public function getUser( $audience = self::FOR_PUBLIC, User $user = null ) {
322 if ( !$this->audienceCan( self::DELETED_USER, $audience, $user ) ) {
323 return null;
324 } else {
325 return $this->mUser;
326 }
327 }
328
346 public function getComment( $audience = self::FOR_PUBLIC, User $user = null ) {
347 if ( !$this->audienceCan( self::DELETED_COMMENT, $audience, $user ) ) {
348 return null;
349 } else {
350 return $this->mComment;
351 }
352 }
353
359 public function isMinor() {
360 return (bool)$this->mMinorEdit;
361 }
362
370 public function isDeleted( $field ) {
371 return ( $this->getVisibility() & $field ) == $field;
372 }
373
381 public function getVisibility() {
382 return (int)$this->mDeleted;
383 }
384
392 public function getTimestamp() {
393 return $this->mTimestamp;
394 }
395
413 protected function audienceCan( $field, $audience, User $user = null ) {
414 if ( $audience == self::FOR_PUBLIC && $this->isDeleted( $field ) ) {
415 return false;
416 } elseif ( $audience == self::FOR_THIS_USER ) {
417 if ( !$user ) {
418 throw new InvalidArgumentException(
419 'A User object must be given when checking FOR_THIS_USER audience.'
420 );
421 }
422
423 if ( !$this->userCan( $field, $user ) ) {
424 return false;
425 }
426 }
427
428 return true;
429 }
430
443 protected function userCan( $field, User $user ) {
444 // TODO: use callback for permission checks, so we don't need to know a Title object!
445 return self::userCanBitfield( $this->getVisibility(), $field, $user, $this->mTitle );
446 }
447
464 public static function userCanBitfield( $bitfield, $field, User $user, Title $title = null ) {
465 if ( $bitfield & $field ) { // aspect is deleted
466 if ( $bitfield & self::DELETED_RESTRICTED ) {
467 $permissions = [ 'suppressrevision', 'viewsuppressed' ];
468 } elseif ( $field & self::DELETED_TEXT ) {
469 $permissions = [ 'deletedtext' ];
470 } else {
471 $permissions = [ 'deletedhistory' ];
472 }
473 $permissionlist = implode( ', ', $permissions );
474 if ( $title === null ) {
475 wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" );
476 return call_user_func_array( [ $user, 'isAllowedAny' ], $permissions );
477 } else {
478 $text = $title->getPrefixedText();
479 wfDebug( "Checking for $permissionlist on $text due to $field match on $bitfield\n" );
480 foreach ( $permissions as $perm ) {
481 if ( $title->userCan( $perm, $user ) ) {
482 return true;
483 }
484 }
485 return false;
486 }
487 } else {
488 return true;
489 }
490 }
491
492}
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
CommentStoreComment represents a comment stored by CommentStore.
MediaWiki exception.
Page revision base class.
getComment( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision comment, if it's available to the specified audience.
isMinor()
MCR migration note: this replaces Revision::isMinor.
userCan( $field, User $user)
Determine if the current user is allowed to view a particular field of this revision,...
getSize()
Returns the nominal size of this revision, in bogo-bytes.
audienceCan( $field, $audience, User $user=null)
Check that the given audience has access to the given field.
int $mDeleted
using the DELETED_XXX and SUPPRESSED_XXX flags
getTimestamp()
MCR migration note: this replaces Revision::getTimestamp.
getContent( $role, $audience=self::FOR_PUBLIC, User $user=null)
Returns the Content of the given slot of this revision.
hasSlot( $role)
Returns whether the given slot is defined in this revision.
isDeleted( $field)
MCR migration note: this replaces Revision::isDeleted.
getSlot( $role, $audience=self::FOR_PUBLIC, User $user=null)
Returns meta-data for the given slot.
getSlotRoles()
Returns the slot names (roles) of all slots present in this revision.
getParentId()
Get parent revision ID (the original previous page revision).
getWikiId()
Get the ID of the wiki this revision belongs to.
CommentStoreComment null $mComment
hasSameContent(RevisionRecord $rec)
string $mWiki
Wiki ID; false means the current wiki.
getSha1()
Returns the base36 sha1 of this revision.
getUser( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision's author's user identity, if it's available to the specified audience.
__construct(Title $title, RevisionSlots $slots, $wikiId=false)
getVisibility()
Get the deletion bitfield of the revision.
getPageAsLinkTarget()
Returns the title of the page this revision is associated with as a LinkTarget object.
__sleep()
Implemented to defy serialization.
static userCanBitfield( $bitfield, $field, User $user, Title $title=null)
Determine if the current user is allowed to view a particular field of this revision,...
Value object representing the set of slots belonging to a revision.
static newWithSuppressedContent(SlotRecord $slot)
Returns a new SlotRecord just like the given $slot, except that calling getContent() will fail with a...
Represents a title within MediaWiki.
Definition Title.php:39
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:53
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:964
Base interface for content objects.
Definition Content.php:34
Interface for objects representing user identity.