[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/ -> MovePage.php (source)

   1  <?php
   2  
   3  /**
   4   * This program is free software; you can redistribute it and/or modify
   5   * it under the terms of the GNU General Public License as published by
   6   * the Free Software Foundation; either version 2 of the License, or
   7   * (at your option) any later version.
   8   *
   9   * This program is distributed in the hope that it will be useful,
  10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12   * GNU General Public License for more details.
  13   *
  14   * You should have received a copy of the GNU General Public License along
  15   * with this program; if not, write to the Free Software Foundation, Inc.,
  16   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17   * http://www.gnu.org/copyleft/gpl.html
  18   *
  19   * @file
  20   */
  21  
  22  /**
  23   * Handles the backend logic of moving a page from one title
  24   * to another.
  25   *
  26   * @since 1.24
  27   */
  28  class MovePage {
  29  
  30      /**
  31       * @var Title
  32       */
  33      protected $oldTitle;
  34  
  35      /**
  36       * @var Title
  37       */
  38      protected $newTitle;
  39  
  40  	public function __construct( Title $oldTitle, Title $newTitle ) {
  41          $this->oldTitle = $oldTitle;
  42          $this->newTitle = $newTitle;
  43      }
  44  
  45      /**
  46       * @param User $user
  47       * @param string $reason
  48       * @param bool $createRedirect
  49       * @return Status
  50       */
  51  	public function move( User $user, $reason, $createRedirect ) {
  52          global $wgCategoryCollation;
  53  
  54          // If it is a file, move it first.
  55          // It is done before all other moving stuff is done because it's hard to revert.
  56          $dbw = wfGetDB( DB_MASTER );
  57          if ( $this->oldTitle->getNamespace() == NS_FILE ) {
  58              $file = wfLocalFile( $this->oldTitle );
  59              if ( $file->exists() ) {
  60                  $status = $file->move( $this->newTitle );
  61                  if ( !$status->isOk() ) {
  62                      return $status;
  63                  }
  64              }
  65              // Clear RepoGroup process cache
  66              RepoGroup::singleton()->clearCache( $this->oldTitle );
  67              RepoGroup::singleton()->clearCache( $this->newTitle ); # clear false negative cache
  68          }
  69  
  70          $dbw->begin( __METHOD__ ); # If $file was a LocalFile, its transaction would have closed our own.
  71          $pageid = $this->oldTitle->getArticleID( Title::GAID_FOR_UPDATE );
  72          $protected = $this->oldTitle->isProtected();
  73  
  74          // Do the actual move
  75          $this->moveToInternal( $user, $this->newTitle, $reason, $createRedirect );
  76  
  77          // Refresh the sortkey for this row.  Be careful to avoid resetting
  78          // cl_timestamp, which may disturb time-based lists on some sites.
  79          // @todo This block should be killed, it's duplicating code
  80          // from LinksUpdate::getCategoryInsertions() and friends.
  81          $prefixes = $dbw->select(
  82              'categorylinks',
  83              array( 'cl_sortkey_prefix', 'cl_to' ),
  84              array( 'cl_from' => $pageid ),
  85              __METHOD__
  86          );
  87          if ( $this->newTitle->getNamespace() == NS_CATEGORY ) {
  88              $type = 'subcat';
  89          } elseif ( $this->newTitle->getNamespace() == NS_FILE ) {
  90              $type = 'file';
  91          } else {
  92              $type = 'page';
  93          }
  94          foreach ( $prefixes as $prefixRow ) {
  95              $prefix = $prefixRow->cl_sortkey_prefix;
  96              $catTo = $prefixRow->cl_to;
  97              $dbw->update( 'categorylinks',
  98                  array(
  99                      'cl_sortkey' => Collation::singleton()->getSortKey(
 100                              $this->newTitle->getCategorySortkey( $prefix ) ),
 101                      'cl_collation' => $wgCategoryCollation,
 102                      'cl_type' => $type,
 103                      'cl_timestamp=cl_timestamp' ),
 104                  array(
 105                      'cl_from' => $pageid,
 106                      'cl_to' => $catTo ),
 107                  __METHOD__
 108              );
 109          }
 110  
 111          $redirid = $this->oldTitle->getArticleID();
 112  
 113          if ( $protected ) {
 114              # Protect the redirect title as the title used to be...
 115              $dbw->insertSelect( 'page_restrictions', 'page_restrictions',
 116                  array(
 117                      'pr_page' => $redirid,
 118                      'pr_type' => 'pr_type',
 119                      'pr_level' => 'pr_level',
 120                      'pr_cascade' => 'pr_cascade',
 121                      'pr_user' => 'pr_user',
 122                      'pr_expiry' => 'pr_expiry'
 123                  ),
 124                  array( 'pr_page' => $pageid ),
 125                  __METHOD__,
 126                  array( 'IGNORE' )
 127              );
 128              # Update the protection log
 129              $log = new LogPage( 'protect' );
 130              $comment = wfMessage(
 131                  'prot_1movedto2',
 132                  $this->oldTitle->getPrefixedText(),
 133                  $this->newTitle->getPrefixedText()
 134              )->inContentLanguage()->text();
 135              if ( $reason ) {
 136                  $comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason;
 137              }
 138              // @todo FIXME: $params?
 139              $logId = $log->addEntry(
 140                  'move_prot',
 141                  $this->newTitle,
 142                  $comment,
 143                  array( $this->oldTitle->getPrefixedText() ),
 144                  $user
 145              );
 146  
 147              // reread inserted pr_ids for log relation
 148              $insertedPrIds = $dbw->select(
 149                  'page_restrictions',
 150                  'pr_id',
 151                  array( 'pr_page' => $redirid ),
 152                  __METHOD__
 153              );
 154              $logRelationsValues = array();
 155              foreach ( $insertedPrIds as $prid ) {
 156                  $logRelationsValues[] = $prid->pr_id;
 157              }
 158              $log->addRelations( 'pr_id', $logRelationsValues, $logId );
 159          }
 160  
 161          // Update *_from_namespace fields as needed
 162          if ( $this->oldTitle->getNamespace() != $this->newTitle->getNamespace() ) {
 163              $dbw->update( 'pagelinks',
 164                  array( 'pl_from_namespace' => $this->newTitle->getNamespace() ),
 165                  array( 'pl_from' => $pageid ),
 166                  __METHOD__
 167              );
 168              $dbw->update( 'templatelinks',
 169                  array( 'tl_from_namespace' => $this->newTitle->getNamespace() ),
 170                  array( 'tl_from' => $pageid ),
 171                  __METHOD__
 172              );
 173              $dbw->update( 'imagelinks',
 174                  array( 'il_from_namespace' => $this->newTitle->getNamespace() ),
 175                  array( 'il_from' => $pageid ),
 176                  __METHOD__
 177              );
 178          }
 179  
 180          # Update watchlists
 181          $oldtitle = $this->oldTitle->getDBkey();
 182          $newtitle = $this->newTitle->getDBkey();
 183          $oldsnamespace = MWNamespace::getSubject( $this->oldTitle->getNamespace() );
 184          $newsnamespace = MWNamespace::getSubject( $this->newTitle->getNamespace() );
 185          if ( $oldsnamespace != $newsnamespace || $oldtitle != $newtitle ) {
 186              WatchedItem::duplicateEntries( $this->oldTitle, $this->newTitle );
 187          }
 188  
 189          $dbw->commit( __METHOD__ );
 190  
 191          wfRunHooks( 'TitleMoveComplete', array( &$this->oldTitle, &$this->newTitle, &$user, $pageid, $redirid, $reason ) );
 192          return Status::newGood();
 193  
 194      }
 195  
 196      /**
 197       * Move page to a title which is either a redirect to the
 198       * source page or nonexistent
 199       *
 200       * @fixme This was basically directly moved from Title, it should be split into smaller functions
 201       * @param User $user the User doing the move
 202       * @param Title $nt The page to move to, which should be a redirect or nonexistent
 203       * @param string $reason The reason for the move
 204       * @param bool $createRedirect Whether to leave a redirect at the old title. Does not check
 205       *   if the user has the suppressredirect right
 206       * @throws MWException
 207       */
 208  	private function moveToInternal( User $user, &$nt, $reason = '', $createRedirect = true ) {
 209          global $wgContLang;
 210  
 211          if ( $nt->exists() ) {
 212              $moveOverRedirect = true;
 213              $logType = 'move_redir';
 214          } else {
 215              $moveOverRedirect = false;
 216              $logType = 'move';
 217          }
 218  
 219          if ( $createRedirect ) {
 220              if ( $this->oldTitle->getNamespace() == NS_CATEGORY
 221                  && !wfMessage( 'category-move-redirect-override' )->inContentLanguage()->isDisabled()
 222              ) {
 223                  $redirectContent = new WikitextContent(
 224                      wfMessage( 'category-move-redirect-override' )
 225                          ->params( $nt->getPrefixedText() )->inContentLanguage()->plain() );
 226              } else {
 227                  $contentHandler = ContentHandler::getForTitle( $this->oldTitle );
 228                  $redirectContent = $contentHandler->makeRedirectContent( $nt,
 229                      wfMessage( 'move-redirect-text' )->inContentLanguage()->plain() );
 230              }
 231  
 232              // NOTE: If this page's content model does not support redirects, $redirectContent will be null.
 233          } else {
 234              $redirectContent = null;
 235          }
 236  
 237          // bug 57084: log_page should be the ID of the *moved* page
 238          $oldid = $this->oldTitle->getArticleID();
 239          $logTitle = clone $this->oldTitle;
 240  
 241          $logEntry = new ManualLogEntry( 'move', $logType );
 242          $logEntry->setPerformer( $user );
 243          $logEntry->setTarget( $logTitle );
 244          $logEntry->setComment( $reason );
 245          $logEntry->setParameters( array(
 246              '4::target' => $nt->getPrefixedText(),
 247              '5::noredir' => $redirectContent ? '0': '1',
 248          ) );
 249  
 250          $formatter = LogFormatter::newFromEntry( $logEntry );
 251          $formatter->setContext( RequestContext::newExtraneousContext( $this->oldTitle ) );
 252          $comment = $formatter->getPlainActionText();
 253          if ( $reason ) {
 254              $comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason;
 255          }
 256          # Truncate for whole multibyte characters.
 257          $comment = $wgContLang->truncate( $comment, 255 );
 258  
 259          $dbw = wfGetDB( DB_MASTER );
 260  
 261          $newpage = WikiPage::factory( $nt );
 262  
 263          if ( $moveOverRedirect ) {
 264              $newid = $nt->getArticleID();
 265              $newcontent = $newpage->getContent();
 266  
 267              # Delete the old redirect. We don't save it to history since
 268              # by definition if we've got here it's rather uninteresting.
 269              # We have to remove it so that the next step doesn't trigger
 270              # a conflict on the unique namespace+title index...
 271              $dbw->delete( 'page', array( 'page_id' => $newid ), __METHOD__ );
 272  
 273              $newpage->doDeleteUpdates( $newid, $newcontent );
 274          }
 275  
 276          # Save a null revision in the page's history notifying of the move
 277          $nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true, $user );
 278          if ( !is_object( $nullRevision ) ) {
 279              throw new MWException( 'No valid null revision produced in ' . __METHOD__ );
 280          }
 281  
 282          $nullRevision->insertOn( $dbw );
 283  
 284          # Change the name of the target page:
 285          $dbw->update( 'page',
 286              /* SET */ array(
 287                  'page_namespace' => $nt->getNamespace(),
 288                  'page_title' => $nt->getDBkey(),
 289              ),
 290              /* WHERE */ array( 'page_id' => $oldid ),
 291              __METHOD__
 292          );
 293  
 294          // clean up the old title before reset article id - bug 45348
 295          if ( !$redirectContent ) {
 296              WikiPage::onArticleDelete( $this->oldTitle );
 297          }
 298  
 299          $this->oldTitle->resetArticleID( 0 ); // 0 == non existing
 300          $nt->resetArticleID( $oldid );
 301          $newpage->loadPageData( WikiPage::READ_LOCKING ); // bug 46397
 302  
 303          $newpage->updateRevisionOn( $dbw, $nullRevision );
 304  
 305          wfRunHooks( 'NewRevisionFromEditComplete',
 306              array( $newpage, $nullRevision, $nullRevision->getParentId(), $user ) );
 307  
 308          $newpage->doEditUpdates( $nullRevision, $user, array( 'changed' => false ) );
 309  
 310          if ( !$moveOverRedirect ) {
 311              WikiPage::onArticleCreate( $nt );
 312          }
 313  
 314          # Recreate the redirect, this time in the other direction.
 315          if ( $redirectContent ) {
 316              $redirectArticle = WikiPage::factory( $this->oldTitle );
 317              $redirectArticle->loadFromRow( false, WikiPage::READ_LOCKING ); // bug 46397
 318              $newid = $redirectArticle->insertOn( $dbw );
 319              if ( $newid ) { // sanity
 320                  $this->oldTitle->resetArticleID( $newid );
 321                  $redirectRevision = new Revision( array(
 322                      'title' => $this->oldTitle, // for determining the default content model
 323                      'page' => $newid,
 324                      'user_text' => $user->getName(),
 325                      'user' => $user->getId(),
 326                      'comment' => $comment,
 327                      'content' => $redirectContent ) );
 328                  $redirectRevision->insertOn( $dbw );
 329                  $redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
 330  
 331                  wfRunHooks( 'NewRevisionFromEditComplete',
 332                      array( $redirectArticle, $redirectRevision, false, $user ) );
 333  
 334                  $redirectArticle->doEditUpdates( $redirectRevision, $user, array( 'created' => true ) );
 335              }
 336          }
 337  
 338          # Log the move
 339          $logid = $logEntry->insert();
 340          $logEntry->publish( $logid );
 341      }
 342  
 343  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1