Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
61.11% |
44 / 72 |
|
81.82% |
18 / 22 |
CRAP | |
0.00% |
0 / 1 |
MutableRevisionRecord | |
61.11% |
44 / 72 |
|
81.82% |
18 / 22 |
78.46 | |
0.00% |
0 / 1 |
newFromParentRevision | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
newUpdatedRevisionRecord | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
setParentId | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setSlot | |
37.50% |
3 / 8 |
|
0.00% |
0 / 1 |
5.20 | |||
inheritSlot | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setContent | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
removeSlot | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
applyUpdate | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setComment | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setSha1 | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setSize | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setVisibility | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setTimestamp | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setMinorEdit | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setId | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setUser | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setPageId | |
57.14% |
4 / 7 |
|
0.00% |
0 / 1 |
3.71 | |||
getSize | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getSha1 | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getSlots | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
resetAggregateValues | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * Mutable RevisionRecord implementation, for building new revision entries programmatically. |
4 | * |
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. |
9 | * |
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. |
14 | * |
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 |
19 | * |
20 | * @file |
21 | */ |
22 | |
23 | namespace MediaWiki\Revision; |
24 | |
25 | use InvalidArgumentException; |
26 | use MediaWiki\CommentStore\CommentStoreComment; |
27 | use MediaWiki\Content\Content; |
28 | use MediaWiki\Page\PageIdentity; |
29 | use MediaWiki\Storage\RevisionSlotsUpdate; |
30 | use MediaWiki\User\UserIdentity; |
31 | use MediaWiki\Utils\MWTimestamp; |
32 | |
33 | /** |
34 | * Mutable RevisionRecord implementation, for building new revision entries programmatically. |
35 | * Provides setters for all fields. |
36 | * |
37 | * @newable |
38 | * |
39 | * @since 1.31 |
40 | * @since 1.32 Renamed from MediaWiki\Storage\MutableRevisionRecord |
41 | * @property MutableRevisionSlots $mSlots |
42 | */ |
43 | class MutableRevisionRecord extends RevisionRecord { |
44 | |
45 | /** |
46 | * Returns an incomplete MutableRevisionRecord which uses $parent as its |
47 | * parent revision, and inherits all slots form it. If saved unchanged, |
48 | * the new revision will act as a null-revision. |
49 | * |
50 | * @param RevisionRecord $parent |
51 | * |
52 | * @return MutableRevisionRecord |
53 | */ |
54 | public static function newFromParentRevision( RevisionRecord $parent ) { |
55 | $rev = new MutableRevisionRecord( $parent->getPage(), $parent->getWikiId() ); |
56 | |
57 | foreach ( $parent->getSlotRoles() as $role ) { |
58 | $slot = $parent->getSlot( $role, self::RAW ); |
59 | $rev->inheritSlot( $slot ); |
60 | } |
61 | |
62 | $rev->setPageId( $parent->getPageId() ); |
63 | $rev->setParentId( $parent->getId() ); |
64 | |
65 | return $rev; |
66 | } |
67 | |
68 | /** |
69 | * Returns a MutableRevisionRecord which is an updated version of $revision with $slots |
70 | * added. |
71 | * @param RevisionRecord $revision |
72 | * @param SlotRecord[] $slots |
73 | * @return MutableRevisionRecord |
74 | * @since 1.36 |
75 | */ |
76 | public static function newUpdatedRevisionRecord( |
77 | RevisionRecord $revision, |
78 | array $slots |
79 | ): MutableRevisionRecord { |
80 | $newRevisionRecord = new MutableRevisionRecord( |
81 | $revision->getPage(), |
82 | $revision->getWikiId() |
83 | ); |
84 | |
85 | $newRevisionRecord->setId( $revision->getId( $revision->getWikiId() ) ); |
86 | $newRevisionRecord->setPageId( $revision->getPageId( $revision->getWikiId() ) ); |
87 | $newRevisionRecord->setParentId( $revision->getParentId( $revision->getWikiId() ) ); |
88 | $newRevisionRecord->setUser( $revision->getUser() ); |
89 | |
90 | foreach ( $revision->getSlots()->getSlots() as $slot ) { |
91 | $newRevisionRecord->setSlot( $slot ); |
92 | } |
93 | |
94 | foreach ( $slots as $slot ) { |
95 | $newRevisionRecord->setSlot( $slot ); |
96 | } |
97 | |
98 | return $newRevisionRecord; |
99 | } |
100 | |
101 | /** |
102 | * @stable to call. |
103 | * |
104 | * @param PageIdentity $page The page this RevisionRecord is associated with. |
105 | * @param false|string $wikiId Relevant wiki id or self::LOCAL for the current one. |
106 | */ |
107 | public function __construct( PageIdentity $page, $wikiId = self::LOCAL ) { |
108 | $slots = new MutableRevisionSlots( [], function () { |
109 | $this->resetAggregateValues(); |
110 | } ); |
111 | |
112 | parent::__construct( $page, $slots, $wikiId ); |
113 | } |
114 | |
115 | /** |
116 | * @param int $parentId |
117 | * @return self |
118 | */ |
119 | public function setParentId( int $parentId ) { |
120 | $this->mParentId = $parentId; |
121 | |
122 | return $this; |
123 | } |
124 | |
125 | /** |
126 | * Sets the given slot. If a slot with the same role is already present in the revision, |
127 | * it is replaced. |
128 | * |
129 | * @note This can only be used with a fresh "unattached" SlotRecord. Calling code that has a |
130 | * SlotRecord from another revision should use inheritSlot(). Calling code that has access to |
131 | * a Content object can use setContent(). |
132 | * |
133 | * @note This may cause the slot meta-data for the revision to be lazy-loaded. |
134 | * |
135 | * @note Calling this method will cause the revision size and hash to be re-calculated upon |
136 | * the next call to getSize() and getSha1(), respectively. |
137 | * |
138 | * @param SlotRecord $slot |
139 | * @return self |
140 | */ |
141 | public function setSlot( SlotRecord $slot ) { |
142 | if ( $slot->hasRevision() && $slot->getRevision() !== $this->getId() ) { |
143 | throw new InvalidArgumentException( |
144 | 'The given slot must be an unsaved, unattached one. ' |
145 | . 'This slot is already attached to revision ' . $slot->getRevision() . '. ' |
146 | . 'Use inheritSlot() instead to preserve a slot from a previous revision.' |
147 | ); |
148 | } |
149 | |
150 | $this->mSlots->setSlot( $slot ); |
151 | |
152 | return $this; |
153 | } |
154 | |
155 | /** |
156 | * "Inherits" the given slot's content. |
157 | * |
158 | * If a slot with the same role is already present in the revision, it is replaced. |
159 | * |
160 | * @note This may cause the slot meta-data for the revision to be lazy-loaded. |
161 | * |
162 | * @param SlotRecord $parentSlot |
163 | * @return self |
164 | */ |
165 | public function inheritSlot( SlotRecord $parentSlot ) { |
166 | $this->mSlots->inheritSlot( $parentSlot ); |
167 | |
168 | return $this; |
169 | } |
170 | |
171 | /** |
172 | * Sets the content for the slot with the given role. |
173 | * |
174 | * If a slot with the same role is already present in the revision, it is replaced. |
175 | * Calling code that has access to a SlotRecord can use inheritSlot() instead. |
176 | * |
177 | * @note This may cause the slot meta-data for the revision to be lazy-loaded. |
178 | * |
179 | * @note Calling this method will cause the revision size and hash to be re-calculated upon |
180 | * the next call to getSize() and getSha1(), respectively. |
181 | * |
182 | * @param string $role |
183 | * @param Content $content |
184 | * @return self |
185 | */ |
186 | public function setContent( $role, Content $content ) { |
187 | $this->mSlots->setContent( $role, $content ); |
188 | |
189 | return $this; |
190 | } |
191 | |
192 | /** |
193 | * Removes the slot with the given role from this revision. |
194 | * This effectively ends the "stream" with that role on the revision's page. |
195 | * Future revisions will no longer inherit this slot, unless it is added back explicitly. |
196 | * |
197 | * @note This may cause the slot meta-data for the revision to be lazy-loaded. |
198 | * |
199 | * @note Calling this method will cause the revision size and hash to be re-calculated upon |
200 | * the next call to getSize() and getSha1(), respectively. |
201 | * |
202 | * @param string $role |
203 | * @return self |
204 | */ |
205 | public function removeSlot( $role ) { |
206 | $this->mSlots->removeSlot( $role ); |
207 | |
208 | return $this; |
209 | } |
210 | |
211 | /** |
212 | * Applies the given update to the slots of this revision. |
213 | * |
214 | * @param RevisionSlotsUpdate $update |
215 | * @return self |
216 | */ |
217 | public function applyUpdate( RevisionSlotsUpdate $update ) { |
218 | $update->apply( $this->mSlots ); |
219 | |
220 | return $this; |
221 | } |
222 | |
223 | /** |
224 | * @param CommentStoreComment $comment |
225 | * @return self |
226 | */ |
227 | public function setComment( CommentStoreComment $comment ) { |
228 | $this->mComment = $comment; |
229 | |
230 | return $this; |
231 | } |
232 | |
233 | /** |
234 | * Set revision hash, for optimization. Prevents getSha1() from re-calculating the hash. |
235 | * |
236 | * @note This should only be used if the calling code is sure that the given hash is correct |
237 | * for the revision's content, and there is no chance of the content being manipulated |
238 | * later. When in doubt, this method should not be called. |
239 | * |
240 | * @param string $sha1 SHA1 hash as a base36 string. |
241 | * @return self |
242 | */ |
243 | public function setSha1( string $sha1 ) { |
244 | $this->mSha1 = $sha1; |
245 | |
246 | return $this; |
247 | } |
248 | |
249 | /** |
250 | * Set nominal revision size, for optimization. Prevents getSize() from re-calculating the size. |
251 | * |
252 | * @note This should only be used if the calling code is sure that the given size is correct |
253 | * for the revision's content, and there is no chance of the content being manipulated |
254 | * later. When in doubt, this method should not be called. |
255 | * |
256 | * @param int $size nominal size in bogo-bytes |
257 | * @return self |
258 | */ |
259 | public function setSize( int $size ) { |
260 | $this->mSize = $size; |
261 | |
262 | return $this; |
263 | } |
264 | |
265 | /** |
266 | * @param int $visibility |
267 | * @return self |
268 | */ |
269 | public function setVisibility( int $visibility ) { |
270 | $this->mDeleted = $visibility; |
271 | |
272 | return $this; |
273 | } |
274 | |
275 | /** |
276 | * @param string $timestamp A timestamp understood by MWTimestamp |
277 | * @return self |
278 | */ |
279 | public function setTimestamp( string $timestamp ) { |
280 | $this->mTimestamp = MWTimestamp::convert( TS_MW, $timestamp ); |
281 | |
282 | return $this; |
283 | } |
284 | |
285 | /** |
286 | * @param bool $minorEdit |
287 | * @return self |
288 | */ |
289 | public function setMinorEdit( bool $minorEdit ) { |
290 | $this->mMinorEdit = $minorEdit; |
291 | |
292 | return $this; |
293 | } |
294 | |
295 | /** |
296 | * Set the revision ID. |
297 | * |
298 | * MCR migration note: this replaced Revision::setId |
299 | * |
300 | * @warning Use this with care, especially when preparing a revision for insertion |
301 | * into the database! The revision ID should only be fixed in special cases |
302 | * like preserving the original ID when restoring a revision. |
303 | * |
304 | * @param int $id |
305 | * @return self |
306 | */ |
307 | public function setId( int $id ) { |
308 | $this->mId = $id; |
309 | |
310 | return $this; |
311 | } |
312 | |
313 | /** |
314 | * Sets the user identity associated with the revision |
315 | * |
316 | * @param UserIdentity $user |
317 | * @return self |
318 | */ |
319 | public function setUser( UserIdentity $user ) { |
320 | $this->mUser = $user; |
321 | |
322 | return $this; |
323 | } |
324 | |
325 | /** |
326 | * @param int $pageId |
327 | * @return self |
328 | */ |
329 | public function setPageId( int $pageId ) { |
330 | $pageIdBasedOnPage = $this->getArticleId( $this->mPage ); |
331 | if ( $pageIdBasedOnPage && $pageIdBasedOnPage !== $this->getArticleId( $this->mPage ) ) { |
332 | throw new InvalidArgumentException( |
333 | 'The given page does not belong to page ID ' . $this->mPageId |
334 | ); |
335 | } |
336 | |
337 | $this->mPageId = $pageId; |
338 | |
339 | return $this; |
340 | } |
341 | |
342 | /** |
343 | * Returns the nominal size of this revision. |
344 | * |
345 | * MCR migration note: this replaced Revision::getSize |
346 | * |
347 | * @return int The nominal size, may be computed on the fly if not yet known. |
348 | */ |
349 | public function getSize() { |
350 | // If not known, re-calculate and remember. Will be reset when slots change. |
351 | $this->mSize ??= $this->mSlots->computeSize(); |
352 | |
353 | return $this->mSize; |
354 | } |
355 | |
356 | /** |
357 | * Returns the base36 sha1 of this revision. |
358 | * |
359 | * MCR migration note: this replaced Revision::getSha1 |
360 | * |
361 | * @return string The revision hash, may be computed on the fly if not yet known. |
362 | */ |
363 | public function getSha1() { |
364 | // If not known, re-calculate and remember. Will be reset when slots change. |
365 | $this->mSha1 ??= $this->mSlots->computeSha1(); |
366 | |
367 | return $this->mSha1; |
368 | } |
369 | |
370 | /** |
371 | * Returns the slots defined for this revision as a MutableRevisionSlots instance, |
372 | * which can be modified to defined the slots for this revision. |
373 | * |
374 | * @return MutableRevisionSlots |
375 | */ |
376 | public function getSlots(): MutableRevisionSlots { |
377 | // Overwritten just to guarantee the more narrow return type. |
378 | // @phan-suppress-next-line PhanTypeMismatchReturnSuperType |
379 | return parent::getSlots(); |
380 | } |
381 | |
382 | /** |
383 | * Invalidate cached aggregate values such as hash and size. |
384 | * Used as a callback by MutableRevisionSlots. |
385 | */ |
386 | private function resetAggregateValues() { |
387 | $this->mSize = null; |
388 | $this->mSha1 = null; |
389 | } |
390 | |
391 | } |