MutableRevisionRecord.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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. namespace MediaWiki\Revision;
  23. use CommentStoreComment;
  24. use Content;
  25. use InvalidArgumentException;
  26. use MediaWiki\Storage\RevisionSlotsUpdate;
  27. use MediaWiki\User\UserIdentity;
  28. use MWException;
  29. use Title;
  30. use Wikimedia\Assert\Assert;
  31. /**
  32. * Mutable RevisionRecord implementation, for building new revision entries programmatically.
  33. * Provides setters for all fields.
  34. *
  35. * @since 1.31
  36. * @since 1.32 Renamed from MediaWiki\Storage\MutableRevisionRecord
  37. * @property MutableRevisionSlots $mSlots
  38. */
  39. class MutableRevisionRecord extends RevisionRecord {
  40. /**
  41. * Returns an incomplete MutableRevisionRecord which uses $parent as its
  42. * parent revision, and inherits all slots form it. If saved unchanged,
  43. * the new revision will act as a null-revision.
  44. *
  45. * @param RevisionRecord $parent
  46. *
  47. * @return MutableRevisionRecord
  48. */
  49. public static function newFromParentRevision( RevisionRecord $parent ) {
  50. // TODO: ideally, we wouldn't need a Title here
  51. $title = Title::newFromLinkTarget( $parent->getPageAsLinkTarget() );
  52. $rev = new MutableRevisionRecord( $title, $parent->getWikiId() );
  53. foreach ( $parent->getSlotRoles() as $role ) {
  54. $slot = $parent->getSlot( $role, self::RAW );
  55. $rev->inheritSlot( $slot );
  56. }
  57. $rev->setPageId( $parent->getPageId() );
  58. $rev->setParentId( $parent->getId() );
  59. return $rev;
  60. }
  61. /**
  62. * @note Avoid calling this constructor directly. Use the appropriate methods
  63. * in RevisionStore instead.
  64. *
  65. * @param Title $title The title of the page this Revision is associated with.
  66. * @param bool|string $dbDomain DB domain of the relevant wiki or false for the current one.
  67. *
  68. * @throws MWException
  69. */
  70. function __construct( Title $title, $dbDomain = false ) {
  71. $slots = new MutableRevisionSlots();
  72. parent::__construct( $title, $slots, $dbDomain );
  73. }
  74. /**
  75. * @param int $parentId
  76. */
  77. public function setParentId( $parentId ) {
  78. Assert::parameterType( 'integer', $parentId, '$parentId' );
  79. $this->mParentId = $parentId;
  80. }
  81. /**
  82. * Sets the given slot. If a slot with the same role is already present in the revision,
  83. * it is replaced.
  84. *
  85. * @note This can only be used with a fresh "unattached" SlotRecord. Calling code that has a
  86. * SlotRecord from another revision should use inheritSlot(). Calling code that has access to
  87. * a Content object can use setContent().
  88. *
  89. * @note This may cause the slot meta-data for the revision to be lazy-loaded.
  90. *
  91. * @note Calling this method will cause the revision size and hash to be re-calculated upon
  92. * the next call to getSize() and getSha1(), respectively.
  93. *
  94. * @param SlotRecord $slot
  95. */
  96. public function setSlot( SlotRecord $slot ) {
  97. if ( $slot->hasRevision() && $slot->getRevision() !== $this->getId() ) {
  98. throw new InvalidArgumentException(
  99. 'The given slot must be an unsaved, unattached one. '
  100. . 'This slot is already attached to revision ' . $slot->getRevision() . '. '
  101. . 'Use inheritSlot() instead to preserve a slot from a previous revision.'
  102. );
  103. }
  104. $this->mSlots->setSlot( $slot );
  105. $this->resetAggregateValues();
  106. }
  107. /**
  108. * "Inherits" the given slot's content.
  109. *
  110. * If a slot with the same role is already present in the revision, it is replaced.
  111. *
  112. * @note This may cause the slot meta-data for the revision to be lazy-loaded.
  113. *
  114. * @param SlotRecord $parentSlot
  115. */
  116. public function inheritSlot( SlotRecord $parentSlot ) {
  117. $this->mSlots->inheritSlot( $parentSlot );
  118. $this->resetAggregateValues();
  119. }
  120. /**
  121. * Sets the content for the slot with the given role.
  122. *
  123. * If a slot with the same role is already present in the revision, it is replaced.
  124. * Calling code that has access to a SlotRecord can use inheritSlot() instead.
  125. *
  126. * @note This may cause the slot meta-data for the revision to be lazy-loaded.
  127. *
  128. * @note Calling this method will cause the revision size and hash to be re-calculated upon
  129. * the next call to getSize() and getSha1(), respectively.
  130. *
  131. * @param string $role
  132. * @param Content $content
  133. */
  134. public function setContent( $role, Content $content ) {
  135. $this->mSlots->setContent( $role, $content );
  136. $this->resetAggregateValues();
  137. }
  138. /**
  139. * Removes the slot with the given role from this revision.
  140. * This effectively ends the "stream" with that role on the revision's page.
  141. * Future revisions will no longer inherit this slot, unless it is added back explicitly.
  142. *
  143. * @note This may cause the slot meta-data for the revision to be lazy-loaded.
  144. *
  145. * @note Calling this method will cause the revision size and hash to be re-calculated upon
  146. * the next call to getSize() and getSha1(), respectively.
  147. *
  148. * @param string $role
  149. */
  150. public function removeSlot( $role ) {
  151. $this->mSlots->removeSlot( $role );
  152. $this->resetAggregateValues();
  153. }
  154. /**
  155. * Applies the given update to the slots of this revision.
  156. *
  157. * @param RevisionSlotsUpdate $update
  158. */
  159. public function applyUpdate( RevisionSlotsUpdate $update ) {
  160. $update->apply( $this->mSlots );
  161. }
  162. /**
  163. * @param CommentStoreComment $comment
  164. */
  165. public function setComment( CommentStoreComment $comment ) {
  166. $this->mComment = $comment;
  167. }
  168. /**
  169. * Set revision hash, for optimization. Prevents getSha1() from re-calculating the hash.
  170. *
  171. * @note This should only be used if the calling code is sure that the given hash is correct
  172. * for the revision's content, and there is no chance of the content being manipulated
  173. * later. When in doubt, this method should not be called.
  174. *
  175. * @param string $sha1 SHA1 hash as a base36 string.
  176. */
  177. public function setSha1( $sha1 ) {
  178. Assert::parameterType( 'string', $sha1, '$sha1' );
  179. $this->mSha1 = $sha1;
  180. }
  181. /**
  182. * Set nominal revision size, for optimization. Prevents getSize() from re-calculating the size.
  183. *
  184. * @note This should only be used if the calling code is sure that the given size is correct
  185. * for the revision's content, and there is no chance of the content being manipulated
  186. * later. When in doubt, this method should not be called.
  187. *
  188. * @param int $size nominal size in bogo-bytes
  189. */
  190. public function setSize( $size ) {
  191. Assert::parameterType( 'integer', $size, '$size' );
  192. $this->mSize = $size;
  193. }
  194. /**
  195. * @param int $visibility
  196. */
  197. public function setVisibility( $visibility ) {
  198. Assert::parameterType( 'integer', $visibility, '$visibility' );
  199. $this->mDeleted = $visibility;
  200. }
  201. /**
  202. * @param string $timestamp A timestamp understood by wfTimestamp
  203. */
  204. public function setTimestamp( $timestamp ) {
  205. Assert::parameterType( 'string', $timestamp, '$timestamp' );
  206. $this->mTimestamp = wfTimestamp( TS_MW, $timestamp );
  207. }
  208. /**
  209. * @param bool $minorEdit
  210. */
  211. public function setMinorEdit( $minorEdit ) {
  212. Assert::parameterType( 'boolean', $minorEdit, '$minorEdit' );
  213. $this->mMinorEdit = $minorEdit;
  214. }
  215. /**
  216. * Set the revision ID.
  217. *
  218. * MCR migration note: this replaces Revision::setId()
  219. *
  220. * @warning Use this with care, especially when preparing a revision for insertion
  221. * into the database! The revision ID should only be fixed in special cases
  222. * like preserving the original ID when restoring a revision.
  223. *
  224. * @param int $id
  225. */
  226. public function setId( $id ) {
  227. Assert::parameterType( 'integer', $id, '$id' );
  228. $this->mId = $id;
  229. }
  230. /**
  231. * Sets the user identity associated with the revision
  232. *
  233. * @param UserIdentity $user
  234. */
  235. public function setUser( UserIdentity $user ) {
  236. $this->mUser = $user;
  237. }
  238. /**
  239. * @param int $pageId
  240. */
  241. public function setPageId( $pageId ) {
  242. Assert::parameterType( 'integer', $pageId, '$pageId' );
  243. if ( $this->mTitle->exists() && $pageId !== $this->mTitle->getArticleID() ) {
  244. throw new InvalidArgumentException(
  245. 'The given Title does not belong to page ID ' . $this->mPageId
  246. );
  247. }
  248. $this->mPageId = $pageId;
  249. }
  250. /**
  251. * Returns the nominal size of this revision.
  252. *
  253. * MCR migration note: this replaces Revision::getSize
  254. *
  255. * @return int The nominal size, may be computed on the fly if not yet known.
  256. */
  257. public function getSize() {
  258. // If not known, re-calculate and remember. Will be reset when slots change.
  259. if ( $this->mSize === null ) {
  260. $this->mSize = $this->mSlots->computeSize();
  261. }
  262. return $this->mSize;
  263. }
  264. /**
  265. * Returns the base36 sha1 of this revision.
  266. *
  267. * MCR migration note: this replaces Revision::getSha1
  268. *
  269. * @return string The revision hash, may be computed on the fly if not yet known.
  270. */
  271. public function getSha1() {
  272. // If not known, re-calculate and remember. Will be reset when slots change.
  273. if ( $this->mSha1 === null ) {
  274. $this->mSha1 = $this->mSlots->computeSha1();
  275. }
  276. return $this->mSha1;
  277. }
  278. /**
  279. * Returns the slots defined for this revision as a MutableRevisionSlots instance,
  280. * which can be modified to defined the slots for this revision.
  281. *
  282. * @return MutableRevisionSlots
  283. */
  284. public function getSlots() {
  285. // Overwritten just guarantee the more narrow return type.
  286. return parent::getSlots();
  287. }
  288. /**
  289. * Invalidate cached aggregate values such as hash and size.
  290. */
  291. private function resetAggregateValues() {
  292. $this->mSize = null;
  293. $this->mSha1 = null;
  294. }
  295. }
  296. /**
  297. * Retain the old class name for backwards compatibility.
  298. * @deprecated since 1.32
  299. */
  300. class_alias( MutableRevisionRecord::class, 'MediaWiki\Storage\MutableRevisionRecord' );