RevDelRevisionList.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. /**
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program; if not, write to the Free Software Foundation, Inc.,
  15. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. * http://www.gnu.org/copyleft/gpl.html
  17. *
  18. * @file
  19. * @ingroup RevisionDelete
  20. */
  21. use MediaWiki\Revision\RevisionRecord;
  22. use Wikimedia\Rdbms\FakeResultWrapper;
  23. use Wikimedia\Rdbms\IDatabase;
  24. /**
  25. * List for revision table items
  26. *
  27. * This will check both the 'revision' table for live revisions and the
  28. * 'archive' table for traditionally-deleted revisions that have an
  29. * ar_rev_id saved.
  30. *
  31. * See RevDelRevisionItem and RevDelArchivedRevisionItem for items.
  32. */
  33. class RevDelRevisionList extends RevDelList {
  34. /** @var int */
  35. public $currentRevId;
  36. public function getType() {
  37. return 'revision';
  38. }
  39. public static function getRelationType() {
  40. return 'rev_id';
  41. }
  42. public static function getRestriction() {
  43. return 'deleterevision';
  44. }
  45. public static function getRevdelConstant() {
  46. return RevisionRecord::DELETED_TEXT;
  47. }
  48. public static function suggestTarget( $target, array $ids ) {
  49. $rev = Revision::newFromId( $ids[0] );
  50. return $rev ? $rev->getTitle() : $target;
  51. }
  52. /**
  53. * @param IDatabase $db
  54. * @return mixed
  55. */
  56. public function doQuery( $db ) {
  57. $ids = array_map( 'intval', $this->ids );
  58. $revQuery = Revision::getQueryInfo( [ 'page', 'user' ] );
  59. $queryInfo = [
  60. 'tables' => $revQuery['tables'],
  61. 'fields' => $revQuery['fields'],
  62. 'conds' => [
  63. 'rev_page' => $this->title->getArticleID(),
  64. 'rev_id' => $ids,
  65. ],
  66. 'options' => [
  67. 'ORDER BY' => 'rev_id DESC',
  68. 'USE INDEX' => [ 'revision' => 'PRIMARY' ] // workaround for MySQL bug (T104313)
  69. ],
  70. 'join_conds' => $revQuery['joins'],
  71. ];
  72. ChangeTags::modifyDisplayQuery(
  73. $queryInfo['tables'],
  74. $queryInfo['fields'],
  75. $queryInfo['conds'],
  76. $queryInfo['join_conds'],
  77. $queryInfo['options'],
  78. ''
  79. );
  80. $live = $db->select(
  81. $queryInfo['tables'],
  82. $queryInfo['fields'],
  83. $queryInfo['conds'],
  84. __METHOD__,
  85. $queryInfo['options'],
  86. $queryInfo['join_conds']
  87. );
  88. if ( $live->numRows() >= count( $ids ) ) {
  89. // All requested revisions are live, keeps things simple!
  90. return $live;
  91. }
  92. $arQuery = Revision::getArchiveQueryInfo();
  93. $archiveQueryInfo = [
  94. 'tables' => $arQuery['tables'],
  95. 'fields' => $arQuery['fields'],
  96. 'conds' => [
  97. 'ar_rev_id' => $ids,
  98. ],
  99. 'options' => [ 'ORDER BY' => 'ar_rev_id DESC' ],
  100. 'join_conds' => $arQuery['joins'],
  101. ];
  102. ChangeTags::modifyDisplayQuery(
  103. $archiveQueryInfo['tables'],
  104. $archiveQueryInfo['fields'],
  105. $archiveQueryInfo['conds'],
  106. $archiveQueryInfo['join_conds'],
  107. $archiveQueryInfo['options'],
  108. ''
  109. );
  110. // Check if any requested revisions are available fully deleted.
  111. $archived = $db->select(
  112. $archiveQueryInfo['tables'],
  113. $archiveQueryInfo['fields'],
  114. $archiveQueryInfo['conds'],
  115. __METHOD__,
  116. $archiveQueryInfo['options'],
  117. $archiveQueryInfo['join_conds']
  118. );
  119. if ( $archived->numRows() == 0 ) {
  120. return $live;
  121. } elseif ( $live->numRows() == 0 ) {
  122. return $archived;
  123. } else {
  124. // Combine the two! Whee
  125. $rows = [];
  126. foreach ( $live as $row ) {
  127. $rows[$row->rev_id] = $row;
  128. }
  129. foreach ( $archived as $row ) {
  130. $rows[$row->ar_rev_id] = $row;
  131. }
  132. krsort( $rows );
  133. return new FakeResultWrapper( array_values( $rows ) );
  134. }
  135. }
  136. public function newItem( $row ) {
  137. if ( isset( $row->rev_id ) ) {
  138. return new RevDelRevisionItem( $this, $row );
  139. } elseif ( isset( $row->ar_rev_id ) ) {
  140. return new RevDelArchivedRevisionItem( $this, $row );
  141. } else {
  142. // This shouldn't happen. :)
  143. throw new MWException( 'Invalid row type in RevDelRevisionList' );
  144. }
  145. }
  146. public function getCurrent() {
  147. if ( is_null( $this->currentRevId ) ) {
  148. $dbw = wfGetDB( DB_MASTER );
  149. $this->currentRevId = $dbw->selectField(
  150. 'page', 'page_latest', $this->title->pageCond(), __METHOD__ );
  151. }
  152. return $this->currentRevId;
  153. }
  154. public function getSuppressBit() {
  155. return RevisionRecord::DELETED_RESTRICTED;
  156. }
  157. public function doPreCommitUpdates() {
  158. $this->title->invalidateCache();
  159. return Status::newGood();
  160. }
  161. public function doPostCommitUpdates( array $visibilityChangeMap ) {
  162. $this->title->purgeSquid();
  163. // Extensions that require referencing previous revisions may need this
  164. Hooks::run( 'ArticleRevisionVisibilitySet', [ $this->title, $this->ids, $visibilityChangeMap ] );
  165. return Status::newGood();
  166. }
  167. }