Index: trunk/phase3/includes/DoubleRedirectJob.php |
— | — | @@ -0,0 +1,155 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class DoubleRedirectJob extends Job { |
| 5 | + var $reason, $redirTitle, $destTitleText; |
| 6 | + static $user; |
| 7 | + |
| 8 | + /** |
| 9 | + * Insert jobs into the job queue to fix redirects to the given title |
| 10 | + * @param string $type The reason for the fix, see message double-redirect-fixed-<reason> |
| 11 | + * @param Title $redirTitle The title which has changed, redirects pointing to this title are fixed |
| 12 | + */ |
| 13 | + public static function fixRedirects( $reason, $redirTitle, $destTitle = false ) { |
| 14 | + # Need to use the master to get the redirect table updated in the same transaction |
| 15 | + $dbw = wfGetDB( DB_MASTER ); |
| 16 | + $res = $dbw->select( |
| 17 | + array( 'redirect', 'page' ), |
| 18 | + array( 'page_namespace', 'page_title' ), |
| 19 | + array( |
| 20 | + 'page_id = rd_from', |
| 21 | + 'rd_namespace' => $redirTitle->getNamespace(), |
| 22 | + 'rd_title' => $redirTitle->getDBkey() |
| 23 | + ), __METHOD__ ); |
| 24 | + if ( !$res->numRows() ) { |
| 25 | + return; |
| 26 | + } |
| 27 | + $jobs = array(); |
| 28 | + foreach ( $res as $row ) { |
| 29 | + $title = Title::makeTitle( $row->page_namespace, $row->page_title ); |
| 30 | + if ( !$title ) { |
| 31 | + continue; |
| 32 | + } |
| 33 | + |
| 34 | + $jobs[] = new self( $title, array( |
| 35 | + 'reason' => $reason, |
| 36 | + 'redirTitle' => $redirTitle->getPrefixedDBkey() ) ); |
| 37 | + # Avoid excessive memory usage |
| 38 | + if ( count( $jobs ) > 10000 ) { |
| 39 | + Job::batchInsert( $jobs ); |
| 40 | + $jobs = array(); |
| 41 | + } |
| 42 | + } |
| 43 | + Job::batchInsert( $jobs ); |
| 44 | + } |
| 45 | + function __construct( $title, $params = false, $id = 0 ) { |
| 46 | + parent::__construct( 'fixDoubleRedirect', $title, $params, $id ); |
| 47 | + $this->reason = $params['reason']; |
| 48 | + $this->redirTitle = Title::newFromText( $params['redirTitle'] ); |
| 49 | + $this->destTitleText = !empty( $params['destTitle'] ) ? $params['destTitle'] : ''; |
| 50 | + } |
| 51 | + |
| 52 | + function run() { |
| 53 | + if ( !$this->redirTitle ) { |
| 54 | + $this->setLastError( 'Invalid title' ); |
| 55 | + return false; |
| 56 | + } |
| 57 | + |
| 58 | + $targetRev = Revision::newFromTitle( $this->title ); |
| 59 | + if ( !$targetRev ) { |
| 60 | + wfDebug( __METHOD__.": target redirect already deleted, ignoring\n" ); |
| 61 | + return true; |
| 62 | + } |
| 63 | + $text = $targetRev->getText(); |
| 64 | + $currentDest = Title::newFromRedirect( $text ); |
| 65 | + if ( !$currentDest || !$currentDest->equals( $this->redirTitle ) ) { |
| 66 | + wfDebug( __METHOD__.": Redirect has changed since the job was queued\n" ); |
| 67 | + return true; |
| 68 | + } |
| 69 | + |
| 70 | + # Find the current final destination |
| 71 | + $newTitle = self::getFinalDestination( $this->redirTitle ); |
| 72 | + if ( !$newTitle ) { |
| 73 | + wfDebug( __METHOD__.": skipping: single redirect, circular redirect or invalid redirect destination\n" ); |
| 74 | + return true; |
| 75 | + } |
| 76 | + if ( $newTitle->equals( $this->redirTitle ) ) { |
| 77 | + # The redirect is already right, no need to change it |
| 78 | + # This can happen if the page was moved back (say after vandalism) |
| 79 | + wfDebug( __METHOD__.": skipping, already good\n" ); |
| 80 | + } |
| 81 | + |
| 82 | + # Fix the text |
| 83 | + # Remember that redirect pages can have categories, templates, etc., |
| 84 | + # so the regex has to be fairly general |
| 85 | + $newText = preg_replace( '/ \[ \[ [^\]]* \] \] /x', |
| 86 | + '[[' . $newTitle->getPrefixedText() . ']]', |
| 87 | + $text, 1 ); |
| 88 | + |
| 89 | + if ( $newText === $text ) { |
| 90 | + $this->setLastError( 'Text unchanged???' ); |
| 91 | + return false; |
| 92 | + } |
| 93 | + |
| 94 | + # Save it |
| 95 | + global $wgUser; |
| 96 | + $oldUser = $wgUser; |
| 97 | + $wgUser = $this->getUser(); |
| 98 | + $article = new Article( $this->title ); |
| 99 | + $reason = wfMsgForContent( 'double-redirect-fixed-' . $this->reason, |
| 100 | + $this->redirTitle->getPrefixedText(), $newTitle->getPrefixedText() ); |
| 101 | + $article->doEdit( $newText, $reason, EDIT_UPDATE | EDIT_SUPPRESS_RC ); |
| 102 | + $wgUser = $oldUser; |
| 103 | + |
| 104 | + return true; |
| 105 | + } |
| 106 | + |
| 107 | + /** |
| 108 | + * Get the final destination of a redirect |
| 109 | + * Returns false if the specified title is not a redirect, or if it is a circular redirect |
| 110 | + */ |
| 111 | + public static function getFinalDestination( $title ) { |
| 112 | + $dbw = wfGetDB( DB_MASTER ); |
| 113 | + |
| 114 | + $seenTitles = array(); # Circular redirect check |
| 115 | + $dest = false; |
| 116 | + |
| 117 | + while ( true ) { |
| 118 | + $titleText = $title->getPrefixedDBkey(); |
| 119 | + if ( isset( $seenTitles[$titleText] ) ) { |
| 120 | + wfDebug( __METHOD__, "Circular redirect detected, aborting\n" ); |
| 121 | + return false; |
| 122 | + } |
| 123 | + $seenTitles[$titleText] = true; |
| 124 | + |
| 125 | + $row = $dbw->selectRow( |
| 126 | + array( 'redirect', 'page' ), |
| 127 | + array( 'rd_namespace', 'rd_title' ), |
| 128 | + array( |
| 129 | + 'rd_from=page_id', |
| 130 | + 'page_namespace' => $title->getNamespace(), |
| 131 | + 'page_title' => $title->getDBkey() |
| 132 | + ), __METHOD__ ); |
| 133 | + if ( !$row ) { |
| 134 | + # No redirect from here, chain terminates |
| 135 | + break; |
| 136 | + } else { |
| 137 | + $dest = $title = Title::makeTitle( $row->rd_namespace, $row->rd_title ); |
| 138 | + } |
| 139 | + } |
| 140 | + return $dest; |
| 141 | + } |
| 142 | + |
| 143 | + /** |
| 144 | + * Get a user object for doing edits, from a request-lifetime cache |
| 145 | + */ |
| 146 | + function getUser() { |
| 147 | + if ( !self::$user ) { |
| 148 | + self::$user = User::newFromName( wfMsgForContent( 'double-redirect-fixer' ), false ); |
| 149 | + if ( !self::$user->isLoggedIn() ) { |
| 150 | + self::$user->addToDatabase(); |
| 151 | + } |
| 152 | + } |
| 153 | + return self::$user; |
| 154 | + } |
| 155 | +} |
| 156 | + |
Property changes on: trunk/phase3/includes/DoubleRedirectJob.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 157 | + native |