3 * Mutable RevisionRecord implementation, for building new revision entries programmatically.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 namespace MediaWiki\Revision
;
25 use CommentStoreComment
;
27 use InvalidArgumentException
;
28 use MediaWiki\Storage\RevisionSlotsUpdate
;
29 use MediaWiki\User\UserIdentity
;
32 use Wikimedia\Assert\Assert
;
35 * Mutable RevisionRecord implementation, for building new revision entries programmatically.
36 * Provides setters for all fields.
39 * @since 1.32 Renamed from MediaWiki\Storage\MutableRevisionRecord
41 class MutableRevisionRecord
extends RevisionRecord
{
44 * Returns an incomplete MutableRevisionRecord which uses $parent as its
45 * parent revision, and inherits all slots form it. If saved unchanged,
46 * the new revision will act as a null-revision.
48 * @param RevisionRecord $parent
50 * @return MutableRevisionRecord
52 public static function newFromParentRevision( RevisionRecord
$parent ) {
53 // TODO: ideally, we wouldn't need a Title here
54 $title = Title
::newFromLinkTarget( $parent->getPageAsLinkTarget() );
55 $rev = new MutableRevisionRecord( $title, $parent->getWikiId() );
57 foreach ( $parent->getSlotRoles() as $role ) {
58 $slot = $parent->getSlot( $role, self
::RAW
);
59 $rev->inheritSlot( $slot );
62 $rev->setPageId( $parent->getPageId() );
63 $rev->setParentId( $parent->getId() );
69 * @note Avoid calling this constructor directly. Use the appropriate methods
70 * in RevisionStore instead.
72 * @param Title $title The title of the page this Revision is associated with.
73 * @param bool|string $dbDomain DB domain of the relevant wiki or false for the current one.
77 function __construct( Title
$title, $dbDomain = false ) {
78 $slots = new MutableRevisionSlots();
80 parent
::__construct( $title, $slots, $dbDomain );
82 $this->mSlots
= $slots; // redundant, but nice for static analysis
86 * @param int $parentId
88 public function setParentId( $parentId ) {
89 Assert
::parameterType( 'integer', $parentId, '$parentId' );
91 $this->mParentId
= $parentId;
95 * Sets the given slot. If a slot with the same role is already present in the revision,
98 * @note This can only be used with a fresh "unattached" SlotRecord. Calling code that has a
99 * SlotRecord from another revision should use inheritSlot(). Calling code that has access to
100 * a Content object can use setContent().
102 * @note This may cause the slot meta-data for the revision to be lazy-loaded.
104 * @note Calling this method will cause the revision size and hash to be re-calculated upon
105 * the next call to getSize() and getSha1(), respectively.
107 * @param SlotRecord $slot
109 public function setSlot( SlotRecord
$slot ) {
110 if ( $slot->hasRevision() && $slot->getRevision() !== $this->getId() ) {
111 throw new InvalidArgumentException(
112 'The given slot must be an unsaved, unattached one. '
113 . 'This slot is already attached to revision ' . $slot->getRevision() . '. '
114 . 'Use inheritSlot() instead to preserve a slot from a previous revision.'
118 $this->mSlots
->setSlot( $slot );
119 $this->resetAggregateValues();
123 * "Inherits" the given slot's content.
125 * If a slot with the same role is already present in the revision, it is replaced.
127 * @note This may cause the slot meta-data for the revision to be lazy-loaded.
129 * @param SlotRecord $parentSlot
131 public function inheritSlot( SlotRecord
$parentSlot ) {
132 $this->mSlots
->inheritSlot( $parentSlot );
133 $this->resetAggregateValues();
137 * Sets the content for the slot with the given role.
139 * If a slot with the same role is already present in the revision, it is replaced.
140 * Calling code that has access to a SlotRecord can use inheritSlot() instead.
142 * @note This may cause the slot meta-data for the revision to be lazy-loaded.
144 * @note Calling this method will cause the revision size and hash to be re-calculated upon
145 * the next call to getSize() and getSha1(), respectively.
147 * @param string $role
148 * @param Content $content
150 public function setContent( $role, Content
$content ) {
151 $this->mSlots
->setContent( $role, $content );
152 $this->resetAggregateValues();
156 * Removes the slot with the given role from this revision.
157 * This effectively ends the "stream" with that role on the revision's page.
158 * Future revisions will no longer inherit this slot, unless it is added back explicitly.
160 * @note This may cause the slot meta-data for the revision to be lazy-loaded.
162 * @note Calling this method will cause the revision size and hash to be re-calculated upon
163 * the next call to getSize() and getSha1(), respectively.
165 * @param string $role
167 public function removeSlot( $role ) {
168 $this->mSlots
->removeSlot( $role );
169 $this->resetAggregateValues();
173 * Applies the given update to the slots of this revision.
175 * @param RevisionSlotsUpdate $update
177 public function applyUpdate( RevisionSlotsUpdate
$update ) {
178 $update->apply( $this->mSlots
);
182 * @param CommentStoreComment $comment
184 public function setComment( CommentStoreComment
$comment ) {
185 $this->mComment
= $comment;
189 * Set revision hash, for optimization. Prevents getSha1() from re-calculating the hash.
191 * @note This should only be used if the calling code is sure that the given hash is correct
192 * for the revision's content, and there is no chance of the content being manipulated
193 * later. When in doubt, this method should not be called.
195 * @param string $sha1 SHA1 hash as a base36 string.
197 public function setSha1( $sha1 ) {
198 Assert
::parameterType( 'string', $sha1, '$sha1' );
200 $this->mSha1
= $sha1;
204 * Set nominal revision size, for optimization. Prevents getSize() from re-calculating the size.
206 * @note This should only be used if the calling code is sure that the given size is correct
207 * for the revision's content, and there is no chance of the content being manipulated
208 * later. When in doubt, this method should not be called.
210 * @param int $size nominal size in bogo-bytes
212 public function setSize( $size ) {
213 Assert
::parameterType( 'integer', $size, '$size' );
215 $this->mSize
= $size;
219 * @param int $visibility
221 public function setVisibility( $visibility ) {
222 Assert
::parameterType( 'integer', $visibility, '$visibility' );
224 $this->mDeleted
= $visibility;
228 * @param string $timestamp A timestamp understood by wfTimestamp
230 public function setTimestamp( $timestamp ) {
231 Assert
::parameterType( 'string', $timestamp, '$timestamp' );
233 $this->mTimestamp
= wfTimestamp( TS_MW
, $timestamp );
237 * @param bool $minorEdit
239 public function setMinorEdit( $minorEdit ) {
240 Assert
::parameterType( 'boolean', $minorEdit, '$minorEdit' );
242 $this->mMinorEdit
= $minorEdit;
246 * Set the revision ID.
248 * MCR migration note: this replaces Revision::setId()
250 * @warning Use this with care, especially when preparing a revision for insertion
251 * into the database! The revision ID should only be fixed in special cases
252 * like preserving the original ID when restoring a revision.
256 public function setId( $id ) {
257 Assert
::parameterType( 'integer', $id, '$id' );
263 * Sets the user identity associated with the revision
265 * @param UserIdentity $user
267 public function setUser( UserIdentity
$user ) {
268 $this->mUser
= $user;
274 public function setPageId( $pageId ) {
275 Assert
::parameterType( 'integer', $pageId, '$pageId' );
277 if ( $this->mTitle
->exists() && $pageId !== $this->mTitle
->getArticleID() ) {
278 throw new InvalidArgumentException(
279 'The given Title does not belong to page ID ' . $this->mPageId
283 $this->mPageId
= $pageId;
287 * Returns the nominal size of this revision.
289 * MCR migration note: this replaces Revision::getSize
291 * @return int The nominal size, may be computed on the fly if not yet known.
293 public function getSize() {
294 // If not known, re-calculate and remember. Will be reset when slots change.
295 if ( $this->mSize
=== null ) {
296 $this->mSize
= $this->mSlots
->computeSize();
303 * Returns the base36 sha1 of this revision.
305 * MCR migration note: this replaces Revision::getSha1
307 * @return string The revision hash, may be computed on the fly if not yet known.
309 public function getSha1() {
310 // If not known, re-calculate and remember. Will be reset when slots change.
311 if ( $this->mSha1
=== null ) {
312 $this->mSha1
= $this->mSlots
->computeSha1();
319 * Returns the slots defined for this revision as a MutableRevisionSlots instance,
320 * which can be modified to defined the slots for this revision.
322 * @return MutableRevisionSlots
324 public function getSlots() {
325 // Overwritten just guarantee the more narrow return type.
326 return parent
::getSlots();
330 * Invalidate cached aggregate values such as hash and size.
332 private function resetAggregateValues() {
340 * Retain the old class name for backwards compatibility.
341 * @deprecated since 1.32
343 class_alias( MutableRevisionRecord
::class, 'MediaWiki\Storage\MutableRevisionRecord' );