MediaWiki  REL1_24
SpecialMovepage.php
Go to the documentation of this file.
00001 <?php
00029 class MovePageForm extends UnlistedSpecialPage {
00031     protected $oldTitle;
00032 
00034     protected $newTitle;
00035 
00036 
00038     protected $reason;
00039 
00040     // Checks
00041 
00043     protected $moveTalk;
00044 
00046     protected $deleteAndMove;
00047 
00049     protected $moveSubpages;
00050 
00052     protected $fixRedirects;
00053 
00055     protected $leaveRedirect;
00056 
00058     protected $moveOverShared;
00059 
00060     private $watch = false;
00061 
00062     public function __construct() {
00063         parent::__construct( 'Movepage' );
00064     }
00065 
00066     public function execute( $par ) {
00067         $this->checkReadOnly();
00068 
00069         $this->setHeaders();
00070         $this->outputHeader();
00071 
00072         $request = $this->getRequest();
00073         $target = !is_null( $par ) ? $par : $request->getVal( 'target' );
00074 
00075         // Yes, the use of getVal() and getText() is wanted, see bug 20365
00076 
00077         $oldTitleText = $request->getVal( 'wpOldTitle', $target );
00078         $this->oldTitle = Title::newFromText( $oldTitleText );
00079 
00080         if ( is_null( $this->oldTitle ) ) {
00081             throw new ErrorPageError( 'notargettitle', 'notargettext' );
00082         }
00083         if ( !$this->oldTitle->exists() ) {
00084             throw new ErrorPageError( 'nopagetitle', 'nopagetext' );
00085         }
00086 
00087         $newTitleTextMain = $request->getText( 'wpNewTitleMain' );
00088         $newTitleTextNs = $request->getInt( 'wpNewTitleNs', $this->oldTitle->getNamespace() );
00089         // Backwards compatibility for forms submitting here from other sources
00090         // which is more common than it should be..
00091         $newTitleText_bc = $request->getText( 'wpNewTitle' );
00092         $this->newTitle = strlen( $newTitleText_bc ) > 0
00093             ? Title::newFromText( $newTitleText_bc )
00094             : Title::makeTitleSafe( $newTitleTextNs, $newTitleTextMain );
00095 
00096         $user = $this->getUser();
00097 
00098         # Check rights
00099         $permErrors = $this->oldTitle->getUserPermissionsErrors( 'move', $user );
00100         if ( count( $permErrors ) ) {
00101             // Auto-block user's IP if the account was "hard" blocked
00102             $user->spreadAnyEditBlock();
00103             throw new PermissionsError( 'move', $permErrors );
00104         }
00105 
00106         $def = !$request->wasPosted();
00107 
00108         $this->reason = $request->getText( 'wpReason' );
00109         $this->moveTalk = $request->getBool( 'wpMovetalk', $def );
00110         $this->fixRedirects = $request->getBool( 'wpFixRedirects', $def );
00111         $this->leaveRedirect = $request->getBool( 'wpLeaveRedirect', $def );
00112         $this->moveSubpages = $request->getBool( 'wpMovesubpages', false );
00113         $this->deleteAndMove = $request->getBool( 'wpDeleteAndMove' ) && $request->getBool( 'wpConfirm' );
00114         $this->moveOverShared = $request->getBool( 'wpMoveOverSharedFile', false );
00115         $this->watch = $request->getCheck( 'wpWatch' ) && $user->isLoggedIn();
00116 
00117         if ( 'submit' == $request->getVal( 'action' ) && $request->wasPosted()
00118             && $user->matchEditToken( $request->getVal( 'wpEditToken' ) )
00119         ) {
00120             $this->doSubmit();
00121         } else {
00122             $this->showForm( array() );
00123         }
00124     }
00125 
00133     function showForm( $err ) {
00134         global $wgContLang;
00135 
00136         $this->getSkin()->setRelevantTitle( $this->oldTitle );
00137 
00138         $oldTitleLink = Linker::link( $this->oldTitle );
00139 
00140         $out = $this->getOutput();
00141         $out->setPageTitle( $this->msg( 'move-page', $this->oldTitle->getPrefixedText() ) );
00142         $out->addModules( 'mediawiki.special.movePage' );
00143 
00144         $newTitle = $this->newTitle;
00145 
00146         if ( !$newTitle ) {
00147             # Show the current title as a default
00148             # when the form is first opened.
00149             $newTitle = $this->oldTitle;
00150         } elseif ( !count( $err ) ) {
00151             # If a title was supplied, probably from the move log revert
00152             # link, check for validity. We can then show some diagnostic
00153             # information and save a click.
00154             $newerr = $this->oldTitle->isValidMoveOperation( $newTitle );
00155             if ( is_array( $newerr ) ) {
00156                 $err = $newerr;
00157             }
00158         }
00159 
00160         $user = $this->getUser();
00161 
00162         if ( count( $err ) == 1 && isset( $err[0][0] ) && $err[0][0] == 'articleexists'
00163             && $newTitle->quickUserCan( 'delete', $user )
00164         ) {
00165             $out->addWikiMsg( 'delete_and_move_text', $newTitle->getPrefixedText() );
00166             $movepagebtn = $this->msg( 'delete_and_move' )->text();
00167             $submitVar = 'wpDeleteAndMove';
00168             $confirm = "
00169                 <tr>
00170                     <td></td>
00171                     <td class='mw-input'>" .
00172                 Xml::checkLabel(
00173                     $this->msg( 'delete_and_move_confirm' )->text(),
00174                     'wpConfirm',
00175                     'wpConfirm'
00176                 ) .
00177                 "</td>
00178                 </tr>";
00179             $err = array();
00180         } else {
00181             if ( $this->oldTitle->getNamespace() == NS_USER && !$this->oldTitle->isSubpage() ) {
00182                 $out->wrapWikiMsg(
00183                     "<div class=\"error mw-moveuserpage-warning\">\n$1\n</div>",
00184                     'moveuserpage-warning'
00185                 );
00186             } elseif ( $this->oldTitle->getNamespace() == NS_CATEGORY ) {
00187                 $out->wrapWikiMsg(
00188                     "<div class=\"error mw-movecategorypage-warning\">\n$1\n</div>",
00189                     'movecategorypage-warning'
00190                 );
00191             }
00192 
00193             $out->addWikiMsg( $this->getConfig()->get( 'FixDoubleRedirects' ) ?
00194                 'movepagetext' :
00195                 'movepagetext-noredirectfixer'
00196             );
00197             $movepagebtn = $this->msg( 'movepagebtn' )->text();
00198             $submitVar = 'wpMove';
00199             $confirm = false;
00200         }
00201 
00202         if ( count( $err ) == 1 && isset( $err[0][0] ) && $err[0][0] == 'file-exists-sharedrepo'
00203             && $user->isAllowed( 'reupload-shared' )
00204         ) {
00205             $out->addWikiMsg( 'move-over-sharedrepo', $newTitle->getPrefixedText() );
00206             $submitVar = 'wpMoveOverSharedFile';
00207             $err = array();
00208         }
00209 
00210         $oldTalk = $this->oldTitle->getTalkPage();
00211         $oldTitleSubpages = $this->oldTitle->hasSubpages();
00212         $oldTitleTalkSubpages = $this->oldTitle->getTalkPage()->hasSubpages();
00213 
00214         $canMoveSubpage = ( $oldTitleSubpages || $oldTitleTalkSubpages ) &&
00215             !count( $this->oldTitle->getUserPermissionsErrors( 'move-subpages', $user ) );
00216 
00217         # We also want to be able to move assoc. subpage talk-pages even if base page
00218         # has no associated talk page, so || with $oldTitleTalkSubpages.
00219         $considerTalk = !$this->oldTitle->isTalkPage() &&
00220             ( $oldTalk->exists()
00221                 || ( $oldTitleTalkSubpages && $canMoveSubpage ) );
00222 
00223         $dbr = wfGetDB( DB_SLAVE );
00224         if ( $this->getConfig()->get( 'FixDoubleRedirects' ) ) {
00225             $hasRedirects = $dbr->selectField( 'redirect', '1',
00226                 array(
00227                     'rd_namespace' => $this->oldTitle->getNamespace(),
00228                     'rd_title' => $this->oldTitle->getDBkey(),
00229                 ), __METHOD__ );
00230         } else {
00231             $hasRedirects = false;
00232         }
00233 
00234         if ( $considerTalk ) {
00235             $out->addWikiMsg( 'movepagetalktext' );
00236         }
00237 
00238         if ( count( $err ) ) {
00239             $out->addHTML( "<div class='error'>\n" );
00240             $action_desc = $this->msg( 'action-move' )->plain();
00241             $out->addWikiMsg( 'permissionserrorstext-withaction', count( $err ), $action_desc );
00242 
00243             if ( count( $err ) == 1 ) {
00244                 $errMsg = $err[0];
00245                 $errMsgName = array_shift( $errMsg );
00246 
00247                 if ( $errMsgName == 'hookaborted' ) {
00248                     $out->addHTML( "<p>{$errMsg[0]}</p>\n" );
00249                 } else {
00250                     $out->addWikiMsgArray( $errMsgName, $errMsg );
00251                 }
00252             } else {
00253                 $errStr = array();
00254 
00255                 foreach ( $err as $errMsg ) {
00256                     if ( $errMsg[0] == 'hookaborted' ) {
00257                         $errStr[] = $errMsg[1];
00258                     } else {
00259                         $errMsgName = array_shift( $errMsg );
00260                         $errStr[] = $this->msg( $errMsgName, $errMsg )->parse();
00261                     }
00262                 }
00263 
00264                 $out->addHTML( '<ul><li>' . implode( "</li>\n<li>", $errStr ) . "</li></ul>\n" );
00265             }
00266             $out->addHTML( "</div>\n" );
00267         }
00268 
00269         if ( $this->oldTitle->isProtected( 'move' ) ) {
00270             # Is the title semi-protected?
00271             if ( $this->oldTitle->isSemiProtected( 'move' ) ) {
00272                 $noticeMsg = 'semiprotectedpagemovewarning';
00273                 $classes[] = 'mw-textarea-sprotected';
00274             } else {
00275                 # Then it must be protected based on static groups (regular)
00276                 $noticeMsg = 'protectedpagemovewarning';
00277                 $classes[] = 'mw-textarea-protected';
00278             }
00279             $out->addHTML( "<div class='mw-warning-with-logexcerpt'>\n" );
00280             $out->addWikiMsg( $noticeMsg );
00281             LogEventsList::showLogExtract(
00282                 $out,
00283                 'protect',
00284                 $this->oldTitle,
00285                 '',
00286                 array( 'lim' => 1 )
00287             );
00288             $out->addHTML( "</div>\n" );
00289         }
00290 
00291         // Byte limit (not string length limit) for wpReason and wpNewTitleMain
00292         // is enforced in the mediawiki.special.movePage module
00293 
00294         $immovableNamespaces = array();
00295 
00296         foreach ( array_keys( $this->getLanguage()->getNamespaces() ) as $nsId ) {
00297             if ( !MWNamespace::isMovable( $nsId ) ) {
00298                 $immovableNamespaces[] = $nsId;
00299             }
00300         }
00301 
00302         $handler = ContentHandler::getForTitle( $this->oldTitle );
00303 
00304         $out->addHTML(
00305             Xml::openElement(
00306                 'form',
00307                 array(
00308                     'method' => 'post',
00309                     'action' => $this->getPageTitle()->getLocalURL( 'action=submit' ),
00310                     'id' => 'movepage'
00311                 )
00312             ) .
00313                 Xml::openElement( 'fieldset' ) .
00314                 Xml::element( 'legend', null, $this->msg( 'move-page-legend' )->text() ) .
00315                 Xml::openElement( 'table', array( 'id' => 'mw-movepage-table' ) ) .
00316                 "<tr>
00317                 <td class='mw-label'>" .
00318                 $this->msg( 'movearticle' )->escaped() .
00319                 "</td>
00320                 <td class='mw-input'>
00321                     <strong>{$oldTitleLink}</strong>
00322                 </td>
00323             </tr>
00324             <tr>
00325                 <td class='mw-label'>" .
00326                 Xml::label( $this->msg( 'newtitle' )->text(), 'wpNewTitleMain' ) .
00327                 "</td>
00328                 <td class='mw-input'>" .
00329                 Html::namespaceSelector(
00330                     array(
00331                         'selected' => $newTitle->getNamespace(),
00332                         'exclude' => $immovableNamespaces
00333                     ),
00334                     array( 'name' => 'wpNewTitleNs', 'id' => 'wpNewTitleNs' )
00335                 ) .
00336                 Xml::input(
00337                     'wpNewTitleMain',
00338                     60,
00339                     $wgContLang->recodeForEdit( $newTitle->getText() ),
00340                     array(
00341                         'type' => 'text',
00342                         'id' => 'wpNewTitleMain',
00343                         'maxlength' => 255
00344                     )
00345                 ) .
00346                 Html::hidden( 'wpOldTitle', $this->oldTitle->getPrefixedText() ) .
00347                 "</td>
00348             </tr>
00349             <tr>
00350                 <td class='mw-label'>" .
00351                 Xml::label( $this->msg( 'movereason' )->text(), 'wpReason' ) .
00352                 "</td>
00353                 <td class='mw-input'>" .
00354                     Xml::input( 'wpReason', 60, $this->reason, array(
00355                         'type' => 'text',
00356                         'id' => 'wpReason',
00357                         'maxlength' => 200,
00358                     ) ) .
00359                 "</td>
00360             </tr>"
00361         );
00362 
00363         if ( $considerTalk ) {
00364             $out->addHTML( "
00365                 <tr>
00366                     <td></td>
00367                     <td class='mw-input'>" .
00368                     Xml::checkLabel(
00369                         $this->msg( 'movetalk' )->text(),
00370                         'wpMovetalk',
00371                         'wpMovetalk',
00372                         $this->moveTalk
00373                     ) .
00374                     "</td>
00375                 </tr>"
00376             );
00377         }
00378 
00379         if ( $user->isAllowed( 'suppressredirect' ) ) {
00380             if ( $handler->supportsRedirects() ) {
00381                 $isChecked = $this->leaveRedirect;
00382                 $options = array();
00383             } else {
00384                 $isChecked = false;
00385                 $options = array(
00386                     'disabled' => 'disabled'
00387                 );
00388             }
00389             $out->addHTML( "
00390                 <tr>
00391                     <td></td>
00392                     <td class='mw-input' >" .
00393                     Xml::checkLabel(
00394                         $this->msg( 'move-leave-redirect' )->text(),
00395                         'wpLeaveRedirect',
00396                         'wpLeaveRedirect',
00397                         $isChecked,
00398                         $options
00399                     ) .
00400                     "</td>
00401                 </tr>"
00402             );
00403         }
00404 
00405         if ( $hasRedirects ) {
00406             $out->addHTML( "
00407                 <tr>
00408                     <td></td>
00409                     <td class='mw-input' >" .
00410                     Xml::checkLabel(
00411                         $this->msg( 'fix-double-redirects' )->text(),
00412                         'wpFixRedirects',
00413                         'wpFixRedirects',
00414                         $this->fixRedirects
00415                     ) .
00416                     "</td>
00417                 </tr>"
00418             );
00419         }
00420 
00421         if ( $canMoveSubpage ) {
00422             $maximumMovedPages = $this->getConfig()->get( 'MaximumMovedPages' );
00423             $out->addHTML( "
00424                 <tr>
00425                     <td></td>
00426                     <td class=\"mw-input\">" .
00427                     Xml::check(
00428                         'wpMovesubpages',
00429                         # Don't check the box if we only have talk subpages to
00430                         # move and we aren't moving the talk page.
00431                         $this->moveSubpages && ( $this->oldTitle->hasSubpages() || $this->moveTalk ),
00432                         array( 'id' => 'wpMovesubpages' )
00433                     ) . '&#160;' .
00434                     Xml::tags( 'label', array( 'for' => 'wpMovesubpages' ),
00435                         $this->msg(
00436                             ( $this->oldTitle->hasSubpages()
00437                                 ? 'move-subpages'
00438                                 : 'move-talk-subpages' )
00439                         )->numParams( $maximumMovedPages )->params( $maximumMovedPages )->parse()
00440                     ) .
00441                     "</td>
00442                 </tr>"
00443             );
00444         }
00445 
00446         $watchChecked = $user->isLoggedIn() && ( $this->watch || $user->getBoolOption( 'watchmoves' )
00447             || $user->isWatched( $this->oldTitle ) );
00448         # Don't allow watching if user is not logged in
00449         if ( $user->isLoggedIn() ) {
00450             $out->addHTML( "
00451             <tr>
00452                 <td></td>
00453                 <td class='mw-input'>" .
00454                 Xml::checkLabel(
00455                     $this->msg( 'move-watch' )->text(),
00456                     'wpWatch',
00457                     'watch',
00458                     $watchChecked
00459                 ) .
00460                 "</td>
00461             </tr>" );
00462         }
00463 
00464         $out->addHTML( "
00465                 {$confirm}
00466             <tr>
00467                 <td>&#160;</td>
00468                 <td class='mw-submit'>" .
00469                 Xml::submitButton( $movepagebtn, array( 'name' => $submitVar ) ) .
00470                 "</td>
00471             </tr>" .
00472                 Xml::closeElement( 'table' ) .
00473                 Html::hidden( 'wpEditToken', $user->getEditToken() ) .
00474                 Xml::closeElement( 'fieldset' ) .
00475                 Xml::closeElement( 'form' ) .
00476                 "\n"
00477         );
00478 
00479         $this->showLogFragment( $this->oldTitle );
00480         $this->showSubpages( $this->oldTitle );
00481     }
00482 
00483     function doSubmit() {
00484         $user = $this->getUser();
00485 
00486         if ( $user->pingLimiter( 'move' ) ) {
00487             throw new ThrottledError;
00488         }
00489 
00490         $ot = $this->oldTitle;
00491         $nt = $this->newTitle;
00492 
00493         # don't allow moving to pages with # in
00494         if ( !$nt || $nt->hasFragment() ) {
00495             $this->showForm( array( array( 'badtitletext' ) ) );
00496 
00497             return;
00498         }
00499 
00500         # Show a warning if the target file exists on a shared repo
00501         if ( $nt->getNamespace() == NS_FILE
00502             && !( $this->moveOverShared && $user->isAllowed( 'reupload-shared' ) )
00503             && !RepoGroup::singleton()->getLocalRepo()->findFile( $nt )
00504             && wfFindFile( $nt )
00505         ) {
00506             $this->showForm( array( array( 'file-exists-sharedrepo' ) ) );
00507 
00508             return;
00509         }
00510 
00511         # Delete to make way if requested
00512         if ( $this->deleteAndMove ) {
00513             $permErrors = $nt->getUserPermissionsErrors( 'delete', $user );
00514             if ( count( $permErrors ) ) {
00515                 # Only show the first error
00516                 $this->showForm( $permErrors );
00517 
00518                 return;
00519             }
00520 
00521             $reason = $this->msg( 'delete_and_move_reason', $ot )->inContentLanguage()->text();
00522 
00523             // Delete an associated image if there is
00524             if ( $nt->getNamespace() == NS_FILE ) {
00525                 $file = wfLocalFile( $nt );
00526                 if ( $file->exists() ) {
00527                     $file->delete( $reason, false );
00528                 }
00529             }
00530 
00531             $error = ''; // passed by ref
00532             $page = WikiPage::factory( $nt );
00533             $deleteStatus = $page->doDeleteArticleReal( $reason, false, 0, true, $error, $user );
00534             if ( !$deleteStatus->isGood() ) {
00535                 $this->showForm( $deleteStatus->getErrorsArray() );
00536 
00537                 return;
00538             }
00539         }
00540 
00541         $handler = ContentHandler::getForTitle( $ot );
00542 
00543         if ( !$handler->supportsRedirects() ) {
00544             $createRedirect = false;
00545         } elseif ( $user->isAllowed( 'suppressredirect' ) ) {
00546             $createRedirect = $this->leaveRedirect;
00547         } else {
00548             $createRedirect = true;
00549         }
00550 
00551         # Do the actual move.
00552         $error = $ot->moveTo( $nt, true, $this->reason, $createRedirect );
00553         if ( $error !== true ) {
00554             $this->showForm( $error );
00555 
00556             return;
00557         }
00558 
00559         if ( $this->getConfig()->get( 'FixDoubleRedirects' ) && $this->fixRedirects ) {
00560             DoubleRedirectJob::fixRedirects( 'move', $ot, $nt );
00561         }
00562 
00563         $out = $this->getOutput();
00564         $out->setPageTitle( $this->msg( 'pagemovedsub' ) );
00565 
00566         $oldLink = Linker::link(
00567             $ot,
00568             null,
00569             array( 'id' => 'movepage-oldlink' ),
00570             array( 'redirect' => 'no' )
00571         );
00572         $newLink = Linker::linkKnown(
00573             $nt,
00574             null,
00575             array( 'id' => 'movepage-newlink' )
00576         );
00577         $oldText = $ot->getPrefixedText();
00578         $newText = $nt->getPrefixedText();
00579 
00580         if ( $ot->exists() ) {
00581             //NOTE: we assume that if the old title exists, it's because it was re-created as
00582             // a redirect to the new title. This is not safe, but what we did before was
00583             // even worse: we just determined whether a redirect should have been created,
00584             // and reported that it was created if it should have, without any checks.
00585             // Also note that isRedirect() is unreliable because of bug 37209.
00586             $msgName = 'movepage-moved-redirect';
00587         } else {
00588             $msgName = 'movepage-moved-noredirect';
00589         }
00590 
00591         $out->addHTML( $this->msg( 'movepage-moved' )->rawParams( $oldLink,
00592             $newLink )->params( $oldText, $newText )->parseAsBlock() );
00593         $out->addWikiMsg( $msgName );
00594 
00595         wfRunHooks( 'SpecialMovepageAfterMove', array( &$this, &$ot, &$nt ) );
00596 
00597         # Now we move extra pages we've been asked to move: subpages and talk
00598         # pages.  First, if the old page or the new page is a talk page, we
00599         # can't move any talk pages: cancel that.
00600         if ( $ot->isTalkPage() || $nt->isTalkPage() ) {
00601             $this->moveTalk = false;
00602         }
00603 
00604         if ( count( $ot->getUserPermissionsErrors( 'move-subpages', $user ) ) ) {
00605             $this->moveSubpages = false;
00606         }
00607 
00608         # Next make a list of id's.  This might be marginally less efficient
00609         # than a more direct method, but this is not a highly performance-cri-
00610         # tical code path and readable code is more important here.
00611         #
00612         # Note: this query works nicely on MySQL 5, but the optimizer in MySQL
00613         # 4 might get confused.  If so, consider rewriting as a UNION.
00614         #
00615         # If the target namespace doesn't allow subpages, moving with subpages
00616         # would mean that you couldn't move them back in one operation, which
00617         # is bad.
00618         # @todo FIXME: A specific error message should be given in this case.
00619 
00620         // @todo FIXME: Use Title::moveSubpages() here
00621         $dbr = wfGetDB( DB_MASTER );
00622         if ( $this->moveSubpages && (
00623             MWNamespace::hasSubpages( $nt->getNamespace() ) || (
00624                 $this->moveTalk
00625                     && MWNamespace::hasSubpages( $nt->getTalkPage()->getNamespace() )
00626             )
00627         ) ) {
00628             $conds = array(
00629                 'page_title' . $dbr->buildLike( $ot->getDBkey() . '/', $dbr->anyString() )
00630                     . ' OR page_title = ' . $dbr->addQuotes( $ot->getDBkey() )
00631             );
00632             $conds['page_namespace'] = array();
00633             if ( MWNamespace::hasSubpages( $nt->getNamespace() ) ) {
00634                 $conds['page_namespace'][] = $ot->getNamespace();
00635             }
00636             if ( $this->moveTalk &&
00637                 MWNamespace::hasSubpages( $nt->getTalkPage()->getNamespace() )
00638             ) {
00639                 $conds['page_namespace'][] = $ot->getTalkPage()->getNamespace();
00640             }
00641         } elseif ( $this->moveTalk ) {
00642             $conds = array(
00643                 'page_namespace' => $ot->getTalkPage()->getNamespace(),
00644                 'page_title' => $ot->getDBkey()
00645             );
00646         } else {
00647             # Skip the query
00648             $conds = null;
00649         }
00650 
00651         $extraPages = array();
00652         if ( !is_null( $conds ) ) {
00653             $extraPages = TitleArray::newFromResult(
00654                 $dbr->select( 'page',
00655                     array( 'page_id', 'page_namespace', 'page_title' ),
00656                     $conds,
00657                     __METHOD__
00658                 )
00659             );
00660         }
00661 
00662         $extraOutput = array();
00663         $count = 1;
00664         foreach ( $extraPages as $oldSubpage ) {
00665             if ( $ot->equals( $oldSubpage ) || $nt->equals( $oldSubpage ) ) {
00666                 # Already did this one.
00667                 continue;
00668             }
00669 
00670             $newPageName = preg_replace(
00671                 '#^' . preg_quote( $ot->getDBkey(), '#' ) . '#',
00672                 StringUtils::escapeRegexReplacement( $nt->getDBkey() ), # bug 21234
00673                 $oldSubpage->getDBkey()
00674             );
00675 
00676             if ( $oldSubpage->isTalkPage() ) {
00677                 $newNs = $nt->getTalkPage()->getNamespace();
00678             } else {
00679                 $newNs = $nt->getSubjectPage()->getNamespace();
00680             }
00681 
00682             # Bug 14385: we need makeTitleSafe because the new page names may
00683             # be longer than 255 characters.
00684             $newSubpage = Title::makeTitleSafe( $newNs, $newPageName );
00685             if ( !$newSubpage ) {
00686                 $oldLink = Linker::linkKnown( $oldSubpage );
00687                 $extraOutput[] = $this->msg( 'movepage-page-unmoved' )->rawParams( $oldLink )
00688                     ->params( Title::makeName( $newNs, $newPageName ) )->escaped();
00689                 continue;
00690             }
00691 
00692             # This was copy-pasted from Renameuser, bleh.
00693             if ( $newSubpage->exists() && !$oldSubpage->isValidMoveTarget( $newSubpage ) ) {
00694                 $link = Linker::linkKnown( $newSubpage );
00695                 $extraOutput[] = $this->msg( 'movepage-page-exists' )->rawParams( $link )->escaped();
00696             } else {
00697                 $success = $oldSubpage->moveTo( $newSubpage, true, $this->reason, $createRedirect );
00698 
00699                 if ( $success === true ) {
00700                     if ( $this->fixRedirects ) {
00701                         DoubleRedirectJob::fixRedirects( 'move', $oldSubpage, $newSubpage );
00702                     }
00703                     $oldLink = Linker::link(
00704                         $oldSubpage,
00705                         null,
00706                         array(),
00707                         array( 'redirect' => 'no' )
00708                     );
00709 
00710                     $newLink = Linker::linkKnown( $newSubpage );
00711                     $extraOutput[] = $this->msg( 'movepage-page-moved' )
00712                         ->rawParams( $oldLink, $newLink )->escaped();
00713                     ++$count;
00714 
00715                     $maximumMovedPages = $this->getConfig()->get( 'MaximumMovedPages' );
00716                     if ( $count >= $maximumMovedPages ) {
00717                         $extraOutput[] = $this->msg( 'movepage-max-pages' )
00718                             ->numParams( $maximumMovedPages )->escaped();
00719                         break;
00720                     }
00721                 } else {
00722                     $oldLink = Linker::linkKnown( $oldSubpage );
00723                     $newLink = Linker::link( $newSubpage );
00724                     $extraOutput[] = $this->msg( 'movepage-page-unmoved' )
00725                         ->rawParams( $oldLink, $newLink )->escaped();
00726                 }
00727             }
00728         }
00729 
00730         if ( $extraOutput !== array() ) {
00731             $out->addHTML( "<ul>\n<li>" . implode( "</li>\n<li>", $extraOutput ) . "</li>\n</ul>" );
00732         }
00733 
00734         # Deal with watches (we don't watch subpages)
00735         WatchAction::doWatchOrUnwatch( $this->watch, $ot, $user );
00736         WatchAction::doWatchOrUnwatch( $this->watch, $nt, $user );
00737     }
00738 
00739     function showLogFragment( $title ) {
00740         $moveLogPage = new LogPage( 'move' );
00741         $out = $this->getOutput();
00742         $out->addHTML( Xml::element( 'h2', null, $moveLogPage->getName()->text() ) );
00743         LogEventsList::showLogExtract( $out, 'move', $title );
00744     }
00745 
00746     function showSubpages( $title ) {
00747         if ( !MWNamespace::hasSubpages( $title->getNamespace() ) ) {
00748             return;
00749         }
00750 
00751         $subpages = $title->getSubpages();
00752         $count = $subpages instanceof TitleArray ? $subpages->count() : 0;
00753 
00754         $out = $this->getOutput();
00755         $out->wrapWikiMsg( '== $1 ==', array( 'movesubpage', $count ) );
00756 
00757         # No subpages.
00758         if ( $count == 0 ) {
00759             $out->addWikiMsg( 'movenosubpage' );
00760 
00761             return;
00762         }
00763 
00764         $out->addWikiMsg( 'movesubpagetext', $this->getLanguage()->formatNum( $count ) );
00765         $out->addHTML( "<ul>\n" );
00766 
00767         foreach ( $subpages as $subpage ) {
00768             $link = Linker::link( $subpage );
00769             $out->addHTML( "<li>$link</li>\n" );
00770         }
00771         $out->addHTML( "</ul>\n" );
00772     }
00773 
00774     protected function getGroupName() {
00775         return 'pagetools';
00776     }
00777 }