MediaWiki  1.33.0
RevisionRecord.php
Go to the documentation of this file.
1 <?php
23 namespace MediaWiki\Revision;
24 
26 use Content;
27 use InvalidArgumentException;
28 use LogicException;
32 use Title;
33 use User;
34 use Wikimedia\Assert\Assert;
35 
45 abstract class RevisionRecord {
46 
47  // RevisionRecord deletion constants
48  const DELETED_TEXT = 1;
49  const DELETED_COMMENT = 2;
50  const DELETED_USER = 4;
51  const DELETED_RESTRICTED = 8;
52  const SUPPRESSED_USER = self::DELETED_USER | self::DELETED_RESTRICTED; // convenience
53  const SUPPRESSED_ALL = self::DELETED_TEXT | self::DELETED_COMMENT | self::DELETED_USER |
54  self::DELETED_RESTRICTED; // convenience
55 
56  // Audience options for accessors
57  const FOR_PUBLIC = 1;
58  const FOR_THIS_USER = 2;
59  const RAW = 3;
60 
62  protected $mWiki = false;
64  protected $mId;
66  protected $mPageId;
68  protected $mUser;
70  protected $mMinorEdit = false;
72  protected $mTimestamp;
74  protected $mDeleted = 0;
76  protected $mSize;
78  protected $mSha1;
80  protected $mParentId;
82  protected $mComment;
83 
85  protected $mTitle; // TODO: we only need the title for permission checks!
86 
88  protected $mSlots;
89 
101  function __construct( Title $title, RevisionSlots $slots, $wikiId = false ) {
102  Assert::parameterType( 'string|boolean', $wikiId, '$wikiId' );
103 
104  $this->mTitle = $title;
105  $this->mSlots = $slots;
106  $this->mWiki = $wikiId;
107 
108  // XXX: this is a sensible default, but we may not have a Title object here in the future.
109  $this->mPageId = $title->getArticleID();
110  }
111 
117  public function __sleep() {
118  throw new LogicException( __CLASS__ . ' is not serializable.' );
119  }
120 
127  public function hasSameContent( RevisionRecord $rec ) {
128  if ( $rec === $this ) {
129  return true;
130  }
131 
132  if ( $this->getId() !== null && $this->getId() === $rec->getId() ) {
133  return true;
134  }
135 
136  // check size before hash, since size is quicker to compute
137  if ( $this->getSize() !== $rec->getSize() ) {
138  return false;
139  }
140 
141  // instead of checking the hash, we could also check the content addresses of all slots.
142 
143  if ( $this->getSha1() === $rec->getSha1() ) {
144  return true;
145  }
146 
147  return false;
148  }
149 
167  public function getContent( $role, $audience = self::FOR_PUBLIC, User $user = null ) {
168  // XXX: throwing an exception would be nicer, but would a further
169  // departure from the signature of Revision::getContent(), and thus
170  // more complex and error prone refactoring.
171  if ( !$this->audienceCan( self::DELETED_TEXT, $audience, $user ) ) {
172  return null;
173  }
174 
175  $content = $this->getSlot( $role, $audience, $user )->getContent();
176  return $content->copy();
177  }
178 
191  public function getSlot( $role, $audience = self::FOR_PUBLIC, User $user = null ) {
192  $slot = $this->mSlots->getSlot( $role );
193 
194  if ( !$this->audienceCan( self::DELETED_TEXT, $audience, $user ) ) {
195  return SlotRecord::newWithSuppressedContent( $slot );
196  }
197 
198  return $slot;
199  }
200 
208  public function hasSlot( $role ) {
209  return $this->mSlots->hasSlot( $role );
210  }
211 
218  public function getSlotRoles() {
219  return $this->mSlots->getSlotRoles();
220  }
221 
227  public function getSlots() {
228  return $this->mSlots;
229  }
230 
245  public function getOriginalSlots() {
246  return new RevisionSlots( $this->mSlots->getOriginalSlots() );
247  }
248 
260  public function getInheritedSlots() {
261  return new RevisionSlots( $this->mSlots->getInheritedSlots() );
262  }
263 
273  public function getId() {
274  return $this->mId;
275  }
276 
289  public function getParentId() {
290  return $this->mParentId;
291  }
292 
303  abstract public function getSize();
304 
316  abstract public function getSha1();
317 
325  public function getPageId() {
326  return $this->mPageId;
327  }
328 
334  public function getWikiId() {
335  return $this->mWiki;
336  }
337 
345  public function getPageAsLinkTarget() {
346  return $this->mTitle;
347  }
348 
365  public function getUser( $audience = self::FOR_PUBLIC, User $user = null ) {
366  if ( !$this->audienceCan( self::DELETED_USER, $audience, $user ) ) {
367  return null;
368  } else {
369  return $this->mUser;
370  }
371  }
372 
390  public function getComment( $audience = self::FOR_PUBLIC, User $user = null ) {
391  if ( !$this->audienceCan( self::DELETED_COMMENT, $audience, $user ) ) {
392  return null;
393  } else {
394  return $this->mComment;
395  }
396  }
397 
403  public function isMinor() {
404  return (bool)$this->mMinorEdit;
405  }
406 
414  public function isDeleted( $field ) {
415  return ( $this->getVisibility() & $field ) == $field;
416  }
417 
425  public function getVisibility() {
426  return (int)$this->mDeleted;
427  }
428 
436  public function getTimestamp() {
437  return $this->mTimestamp;
438  }
439 
457  public function audienceCan( $field, $audience, User $user = null ) {
458  if ( $audience == self::FOR_PUBLIC && $this->isDeleted( $field ) ) {
459  return false;
460  } elseif ( $audience == self::FOR_THIS_USER ) {
461  if ( !$user ) {
462  throw new InvalidArgumentException(
463  'A User object must be given when checking FOR_THIS_USER audience.'
464  );
465  }
466 
467  if ( !$this->userCan( $field, $user ) ) {
468  return false;
469  }
470  }
471 
472  return true;
473  }
474 
487  protected function userCan( $field, User $user ) {
488  // TODO: use callback for permission checks, so we don't need to know a Title object!
489  return self::userCanBitfield( $this->getVisibility(), $field, $user, $this->mTitle );
490  }
491 
508  public static function userCanBitfield( $bitfield, $field, User $user, Title $title = null ) {
509  if ( $bitfield & $field ) { // aspect is deleted
510  if ( $bitfield & self::DELETED_RESTRICTED ) {
511  $permissions = [ 'suppressrevision', 'viewsuppressed' ];
512  } elseif ( $field & self::DELETED_TEXT ) {
513  $permissions = [ 'deletedtext' ];
514  } else {
515  $permissions = [ 'deletedhistory' ];
516  }
517  $permissionlist = implode( ', ', $permissions );
518  if ( $title === null ) {
519  wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" );
520  return $user->isAllowedAny( ...$permissions );
521  } else {
522  $text = $title->getPrefixedText();
523  wfDebug( "Checking for $permissionlist on $text due to $field match on $bitfield\n" );
524  foreach ( $permissions as $perm ) {
525  if ( $title->userCan( $perm, $user ) ) {
526  return true;
527  }
528  }
529  return false;
530  }
531  } else {
532  return true;
533  }
534  }
535 
547  public function isReadyForInsertion() {
548  // NOTE: don't check getSize() and getSha1(), since that may cause the full content to
549  // be loaded in order to calculate the values. Just assume these methods will not return
550  // null if mSlots is not empty.
551 
552  // NOTE: getId() and getPageId() may return null before a revision is saved, so don't
553  //check them.
554 
555  return $this->getTimestamp() !== null
556  && $this->getComment( self::RAW ) !== null
557  && $this->getUser( self::RAW ) !== null
558  && $this->mSlots->getSlotRoles() !== [];
559  }
560 
561 }
562 
567 class_alias( RevisionRecord::class, 'MediaWiki\Storage\RevisionRecord' );
Revision\RevisionRecord\$mWiki
string $mWiki
Wiki ID; false means the current wiki.
Definition: RevisionRecord.php:62
Revision\RevisionRecord\__construct
__construct(Title $title, RevisionSlots $slots, $wikiId=false)
Definition: RevisionRecord.php:101
$user
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1476
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:45
Revision\RevisionRecord\$mTitle
Title $mTitle
Definition: RevisionRecord.php:85
Revision\RevisionRecord\getOriginalSlots
getOriginalSlots()
Returns the slots that originate in this revision.
Definition: RevisionRecord.php:245
Revision\RevisionRecord\isDeleted
isDeleted( $field)
MCR migration note: this replaces Revision::isDeleted.
Definition: RevisionRecord.php:414
Revision\RevisionRecord\$mSlots
RevisionSlots $mSlots
Definition: RevisionRecord.php:88
Revision\RevisionRecord\$mComment
CommentStoreComment null $mComment
Definition: RevisionRecord.php:82
Revision\RevisionRecord\getTimestamp
getTimestamp()
MCR migration note: this replaces Revision::getTimestamp.
Definition: RevisionRecord.php:436
Revision\RevisionRecord\$mMinorEdit
bool $mMinorEdit
Definition: RevisionRecord.php:70
Revision\RevisionRecord\audienceCan
audienceCan( $field, $audience, User $user=null)
Check that the given audience has access to the given field.
Definition: RevisionRecord.php:457
Revision\RevisionRecord\getSlot
getSlot( $role, $audience=self::FOR_PUBLIC, User $user=null)
Returns meta-data for the given slot.
Definition: RevisionRecord.php:191
Revision\RevisionRecord\hasSlot
hasSlot( $role)
Returns whether the given slot is defined in this revision.
Definition: RevisionRecord.php:208
User
User
Definition: All_system_messages.txt:425
Revision\RevisionRecord\userCan
userCan( $field, User $user)
Determine if the current user is allowed to view a particular field of this revision,...
Definition: RevisionRecord.php:487
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:32
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Revision\RevisionRecord\$mUser
UserIdentity null $mUser
Definition: RevisionRecord.php:68
MediaWiki\Revision
Created by PhpStorm.
Definition: FallbackSlotRoleHandler.php:23
Revision\RevisionRecord\getInheritedSlots
getInheritedSlots()
Returns slots inherited from some previous revision.
Definition: RevisionRecord.php:260
Revision\RevisionRecord\$mTimestamp
string null $mTimestamp
Definition: RevisionRecord.php:72
MWException
MediaWiki exception.
Definition: MWException.php:26
Revision\RevisionRecord\getSize
getSize()
Returns the nominal size of this revision, in bogo-bytes.
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
Revision\RevisionRecord\getSha1
getSha1()
Returns the base36 sha1 of this revision.
Revision\RevisionRecord\getUser
getUser( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision's author's user identity, if it's available to the specified audience.
Definition: RevisionRecord.php:365
Revision\RevisionRecord\isMinor
isMinor()
MCR migration note: this replaces Revision::isMinor.
Definition: RevisionRecord.php:403
Revision\RevisionRecord\isReadyForInsertion
isReadyForInsertion()
Returns whether this RevisionRecord is ready for insertion, that is, whether it contains all informat...
Definition: RevisionRecord.php:547
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
Revision\RevisionRecord\userCanBitfield
static userCanBitfield( $bitfield, $field, User $user, Title $title=null)
Determine if the current user is allowed to view a particular field of this revision,...
Definition: RevisionRecord.php:508
Revision\RevisionRecord\RAW
const RAW
Definition: RevisionRecord.php:59
Revision\RevisionRecord\getSlotRoles
getSlotRoles()
Returns the slot names (roles) of all slots present in this revision.
Definition: RevisionRecord.php:218
Revision\RevisionRecord\$mParentId
int null $mParentId
Definition: RevisionRecord.php:80
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:949
Revision\RevisionRecord\getPageId
getPageId()
Get the page ID.
Definition: RevisionRecord.php:325
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:63
Revision\RevisionRecord\getId
getId()
Get revision ID.
Definition: RevisionRecord.php:273
Revision\RevisionRecord\getParentId
getParentId()
Get parent revision ID (the original previous page revision).
Definition: RevisionRecord.php:289
Revision\RevisionRecord\SUPPRESSED_USER
const SUPPRESSED_USER
Definition: RevisionRecord.php:52
Revision\RevisionRecord\__sleep
__sleep()
Implemented to defy serialization.
Definition: RevisionRecord.php:117
Revision\RevisionRecord\DELETED_USER
const DELETED_USER
Definition: RevisionRecord.php:50
Revision\RevisionRecord\getComment
getComment( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision comment, if it's available to the specified audience.
Definition: RevisionRecord.php:390
Revision\RevisionRecord\$mSize
int null $mSize
Definition: RevisionRecord.php:76
Revision\RevisionRecord\getSlots
getSlots()
Returns the slots defined for this revision.
Definition: RevisionRecord.php:227
Content
Base interface for content objects.
Definition: Content.php:34
Revision\RevisionRecord\FOR_PUBLIC
const FOR_PUBLIC
Definition: RevisionRecord.php:57
Revision\RevisionRecord\$mPageId
int $mPageId
Definition: RevisionRecord.php:66
Revision\RevisionRecord\getVisibility
getVisibility()
Get the deletion bitfield of the revision.
Definition: RevisionRecord.php:425
Revision\RevisionRecord\getPageAsLinkTarget
getPageAsLinkTarget()
Returns the title of the page this revision is associated with as a LinkTarget object.
Definition: RevisionRecord.php:345
Title
Represents a title within MediaWiki.
Definition: Title.php:40
Revision\RevisionRecord\DELETED_COMMENT
const DELETED_COMMENT
Definition: RevisionRecord.php:49
Revision\RevisionRecord\DELETED_TEXT
const DELETED_TEXT
Definition: RevisionRecord.php:48
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Revision\RevisionSlots
Value object representing the set of slots belonging to a revision.
Definition: RevisionSlots.php:35
Revision\RevisionRecord\getContent
getContent( $role, $audience=self::FOR_PUBLIC, User $user=null)
Returns the Content of the given slot of this revision.
Definition: RevisionRecord.php:167
$content
$content
Definition: pageupdater.txt:72
Revision\RevisionRecord\hasSameContent
hasSameContent(RevisionRecord $rec)
Definition: RevisionRecord.php:127
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
Revision\RevisionRecord\SUPPRESSED_ALL
const SUPPRESSED_ALL
Definition: RevisionRecord.php:53
Revision\RevisionRecord\DELETED_RESTRICTED
const DELETED_RESTRICTED
Definition: RevisionRecord.php:51
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:48
Revision\RevisionRecord\FOR_THIS_USER
const FOR_THIS_USER
Definition: RevisionRecord.php:58
Revision\RevisionRecord\$mSha1
string null $mSha1
Definition: RevisionRecord.php:78
Revision\RevisionRecord\getWikiId
getWikiId()
Get the ID of the wiki this revision belongs to.
Definition: RevisionRecord.php:334
Revision\RevisionRecord\$mDeleted
int $mDeleted
using the DELETED_XXX and SUPPRESSED_XXX flags
Definition: RevisionRecord.php:74
Revision\RevisionRecord\$mId
int null $mId
Definition: RevisionRecord.php:64
CommentStoreComment
CommentStoreComment represents a comment stored by CommentStore.
Definition: CommentStoreComment.php:29