| Index: trunk/phase3/includes/Article.php |
| — | — | @@ -34,6 +34,7 @@ |
| 35 | 35 | var $mTouched; //!< |
| 36 | 36 | var $mUser; //!< |
| 37 | 37 | var $mUserText; //!< |
| | 38 | + var $mRedirectTarget; //!< |
| 38 | 39 | /**@}}*/ |
| 39 | 40 | |
| 40 | 41 | /** |
| — | — | @@ -57,11 +58,57 @@ |
| 58 | 59 | } |
| 59 | 60 | |
| 60 | 61 | /** |
| | 62 | + * If this page is a redirect, get its target |
| | 63 | + * |
| | 64 | + * The target will be fetched from the redirect table if possible. |
| | 65 | + * If this page doesn't have an entry there, call insertRedirect() |
| | 66 | + * @return mixed Title object, or null if this page is not a redirect |
| | 67 | + */ |
| | 68 | + public function getRedirectTarget() { |
| | 69 | + if(!$this->mTitle || !$this->mTitle->isRedirect()) |
| | 70 | + return null; |
| | 71 | + if(!is_null($this->mRedirectTarget)) |
| | 72 | + return $this->mRedirectTarget; |
| | 73 | + |
| | 74 | + # Query the redirect table |
| | 75 | + $dbr = wfGetDb(DB_SLAVE); |
| | 76 | + $res = $dbr->select('redirect', |
| | 77 | + array('rd_namespace', 'rd_title'), |
| | 78 | + array('rd_from' => $this->getID()), |
| | 79 | + __METHOD__ |
| | 80 | + ); |
| | 81 | + $row = $dbr->fetchObject($res); |
| | 82 | + if($row) |
| | 83 | + return $this->mRedirectTarget = Title::makeTitle($row->rd_namespace, $row->rd_title); |
| | 84 | + |
| | 85 | + # This page doesn't have an entry in the redirect table |
| | 86 | + return $this->mRedirectTarget = $this->insertRedirect(); |
| | 87 | + } |
| | 88 | + |
| | 89 | + /** |
| | 90 | + * Insert an entry for this page into the redirect table. |
| | 91 | + * |
| | 92 | + * Don't call this function directly unless you know what you're doing. |
| | 93 | + * @return Title object |
| | 94 | + */ |
| | 95 | + public function insertRedirect() { |
| | 96 | + $retval = Title::newFromRedirect($this->getContent()); |
| | 97 | + if(!$retval) |
| | 98 | + return null; |
| | 99 | + $dbw = wfGetDb(DB_MASTER); |
| | 100 | + $dbw->insert('redirect', array( |
| | 101 | + 'rd_from' => $this->getID(), |
| | 102 | + 'rd_namespace' => $retval->getNamespace(), |
| | 103 | + 'rd_title' => $retval->getDBKey() |
| | 104 | + )); |
| | 105 | + return $retval; |
| | 106 | + } |
| | 107 | + |
| | 108 | + /** |
| 61 | 109 | * @return mixed false, Title of in-wiki target, or string with URL |
| 62 | 110 | */ |
| 63 | 111 | function followRedirect() { |
| 64 | | - $text = $this->getContent(); |
| 65 | | - $rt = Title::newFromRedirect( $text ); |
| | 112 | + $rt = $this->getRedirectTarget(); |
| 66 | 113 | |
| 67 | 114 | # process if title object is valid and not special:userlogout |
| 68 | 115 | if( $rt ) { |
| — | — | @@ -114,6 +161,7 @@ |
| 115 | 162 | |
| 116 | 163 | $this->mCurID = $this->mUser = $this->mCounter = -1; # Not loaded |
| 117 | 164 | $this->mRedirectedFrom = null; # Title object if set |
| | 165 | + $this->mRedirectTarget = null; # Title object if set |
| 118 | 166 | $this->mUserText = |
| 119 | 167 | $this->mTimestamp = $this->mComment = ''; |
| 120 | 168 | $this->mGoodAdjustment = $this->mTotalAdjustment = 0; |
| — | — | @@ -801,7 +849,7 @@ |
| 802 | 850 | |
| 803 | 851 | } |
| 804 | 852 | |
| 805 | | - elseif ( $rt = Title::newFromRedirect( $text ) ) { |
| | 853 | + elseif ( $rt = $this->getRedirectTarget() ) { |
| 806 | 854 | # Display redirect |
| 807 | 855 | $imageDir = $wgContLang->isRTL() ? 'rtl' : 'ltr'; |
| 808 | 856 | $imageUrl = $wgStylePath.'/common/images/redirect' . $imageDir . '.png'; |
| Index: trunk/phase3/includes/api/ApiMove.php |
| — | — | @@ -79,8 +79,6 @@ |
| 80 | 80 | // We don't care about multiple errors, just report one of them |
| 81 | 81 | $this->dieUsageMsg(current($errors)); |
| 82 | 82 | |
| 83 | | - $dbw = wfGetDB(DB_MASTER); |
| 84 | | - $dbw->begin(); |
| 85 | 83 | $retval = $fromTitle->moveTo($toTitle, true, $params['reason'], !$params['noredirect']); |
| 86 | 84 | if($retval !== true) |
| 87 | 85 | $this->dieUsageMsg(array($retval)); |
| — | — | @@ -118,7 +116,7 @@ |
| 119 | 117 | $wgUser->removeWatch($fromTitle); |
| 120 | 118 | $wgUser->removeWatch($toTitle); |
| 121 | 119 | } |
| 122 | | - $dbw->commit(); // Make sure all changes are really written to the DB |
| | 120 | + $this->getMain()->scheduleCommit(); |
| 123 | 121 | $this->getResult()->addValue(null, $this->getModuleName(), $r); |
| 124 | 122 | } |
| 125 | 123 | |
| Index: trunk/phase3/includes/api/ApiProtect.php |
| — | — | @@ -85,8 +85,6 @@ |
| 86 | 86 | $this->dieUsageMsg(array('missingtitles-createonly')); |
| 87 | 87 | } |
| 88 | 88 | |
| 89 | | - $dbw = wfGetDb(DB_MASTER); |
| 90 | | - $dbw->begin(); |
| 91 | 89 | if($titleObj->exists()) { |
| 92 | 90 | $articleObj = new Article($titleObj); |
| 93 | 91 | $ok = $articleObj->updateRestrictions($protections, $params['reason'], $params['cascade'], $expiry); |
| — | — | @@ -96,7 +94,7 @@ |
| 97 | 95 | // This is very weird. Maybe the article was deleted or the user was blocked/desysopped in the meantime? |
| 98 | 96 | // Just throw an unknown error in this case, as it's very likely to be a race condition |
| 99 | 97 | $this->dieUsageMsg(array()); |
| 100 | | - $dbw->commit(); |
| | 98 | + $this->getMain()->scheduleCommit(); |
| 101 | 99 | $res = array('title' => $titleObj->getPrefixedText(), 'reason' => $params['reason']); |
| 102 | 100 | if($expiry == Block::infinity()) |
| 103 | 101 | $res['expiry'] = 'infinity'; |
| Index: trunk/phase3/includes/api/ApiMain.php |
| — | — | @@ -95,7 +95,7 @@ |
| 96 | 96 | 'dbgfm' => 'ApiFormatDbg' |
| 97 | 97 | ); |
| 98 | 98 | |
| 99 | | - private $mPrinter, $mModules, $mModuleNames, $mFormats, $mFormatNames; |
| | 99 | + private $mPrinter, $mModules, $mModuleNames, $mFormats, $mFormatNames, $mCommit; |
| 100 | 100 | private $mResult, $mAction, $mShowVersions, $mEnableWrite, $mRequest, $mInternalMode, $mSquidMaxage; |
| 101 | 101 | |
| 102 | 102 | /** |
| — | — | @@ -150,6 +150,7 @@ |
| 151 | 151 | $this->mRequest = & $request; |
| 152 | 152 | |
| 153 | 153 | $this->mSquidMaxage = 0; |
| | 154 | + $this->mCommit = false; |
| 154 | 155 | } |
| 155 | 156 | |
| 156 | 157 | /** |
| — | — | @@ -195,6 +196,13 @@ |
| 196 | 197 | public function createPrinterByName($format) { |
| 197 | 198 | return new $this->mFormats[$format] ($this, $format); |
| 198 | 199 | } |
| | 200 | + |
| | 201 | + /** |
| | 202 | + * Schedule a database commit |
| | 203 | + */ |
| | 204 | + public function scheduleCommit() { |
| | 205 | + $this->mCommit = true; |
| | 206 | + } |
| 199 | 207 | |
| 200 | 208 | /** |
| 201 | 209 | * Execute api request. Any errors will be handled if the API was called by the remote client. |
| — | — | @@ -205,6 +213,11 @@ |
| 206 | 214 | $this->executeAction(); |
| 207 | 215 | else |
| 208 | 216 | $this->executeActionWithErrorHandling(); |
| | 217 | + if($this->mCommit) |
| | 218 | + { |
| | 219 | + $dbw = wfGetDb(DB_MASTER); |
| | 220 | + $dbw->immediateCommit(); |
| | 221 | + } |
| 209 | 222 | $this->profileOut(); |
| 210 | 223 | } |
| 211 | 224 | |
| — | — | @@ -617,3 +630,4 @@ |
| 618 | 631 | } |
| 619 | 632 | |
| 620 | 633 | |
| | 634 | + |
| Index: trunk/phase3/includes/api/ApiPageSet.php |
| — | — | @@ -528,7 +528,7 @@ |
| 529 | 529 | while($row = $db->fetchObject($res)) |
| 530 | 530 | { |
| 531 | 531 | $rdfrom = intval($row->rd_from); |
| 532 | | - $from = Title::newFromId($row->rd_from)->getPrefixedText(); |
| | 532 | + $from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText(); |
| 533 | 533 | $to = Title::makeTitle($row->rd_namespace, $row->rd_title)->getPrefixedText(); |
| 534 | 534 | unset($this->mPendingRedirectIDs[$rdfrom]); |
| 535 | 535 | if(!isset($this->mAllPages[$row->rd_namespace][$row->rd_title])) |
| — | — | @@ -537,7 +537,22 @@ |
| 538 | 538 | } |
| 539 | 539 | $db->freeResult($res); |
| 540 | 540 | if(!empty($this->mPendingRedirectIDs)) |
| 541 | | - ApiBase :: dieDebug(__METHOD__, 'Invalid redirect IDs were found'); |
| | 541 | + { |
| | 542 | + # We found pages that aren't in the redirect table |
| | 543 | + # Add them |
| | 544 | + foreach($this->mPendingRedirectIDs as $id => $title) |
| | 545 | + { |
| | 546 | + $article = new Article($title); |
| | 547 | + $rt = $article->insertRedirect(); |
| | 548 | + if(!$rt) |
| | 549 | + # What the hell. Let's just ignore this |
| | 550 | + continue; |
| | 551 | + $lb->addObj($rt); |
| | 552 | + $this->mRedirectTitles[$title->getPrefixedText()] = $rt->getPrefixedText(); |
| | 553 | + unset($this->mPendingRedirectIDs[$id]); |
| | 554 | + } |
| | 555 | + $this->getMain()->scheduleCommit(); |
| | 556 | + } |
| 542 | 557 | return $lb; |
| 543 | 558 | } |
| 544 | 559 | |
| — | — | @@ -617,3 +632,4 @@ |
| 618 | 633 | } |
| 619 | 634 | } |
| 620 | 635 | |
| | 636 | + |
| Index: trunk/phase3/includes/api/ApiRollback.php |
| — | — | @@ -62,15 +62,13 @@ |
| 63 | 63 | $articleObj = new Article($titleObj); |
| 64 | 64 | $summary = (isset($params['summary']) ? $params['summary'] : ""); |
| 65 | 65 | $details = null; |
| 66 | | - $dbw = wfGetDb(DB_MASTER); |
| 67 | | - $dbw->begin(); |
| 68 | 66 | $retval = $articleObj->doRollback($username, $summary, $params['token'], $params['markbot'], $details); |
| 69 | 67 | |
| 70 | 68 | if(!empty($retval)) |
| 71 | 69 | // We don't care about multiple errors, just report one of them |
| 72 | 70 | $this->dieUsageMsg(current($retval)); |
| 73 | 71 | |
| 74 | | - $dbw->commit(); |
| | 72 | + $this->getMain()->scheduleCommit(); |
| 75 | 73 | $current = $target = $summary = NULL; |
| 76 | 74 | extract($details); |
| 77 | 75 | |
| Index: trunk/phase3/includes/api/ApiBlock.php |
| — | — | @@ -87,14 +87,12 @@ |
| 88 | 88 | $form->BlockEmail = $params['noemail']; |
| 89 | 89 | $form->BlockHideName = $params['hidename']; |
| 90 | 90 | |
| 91 | | - $dbw = wfGetDb(DB_MASTER); |
| 92 | | - $dbw->begin(); |
| 93 | 91 | $retval = $form->doBlock($userID, $expiry); |
| 94 | 92 | if(!empty($retval)) |
| 95 | 93 | // We don't care about multiple errors, just report one of them |
| 96 | 94 | $this->dieUsageMsg($retval); |
| | 95 | + $this->getMain()->scheduleCommit(); |
| 97 | 96 | |
| 98 | | - $dbw->commit(); |
| 99 | 97 | $res['user'] = $params['user']; |
| 100 | 98 | $res['userID'] = $userID; |
| 101 | 99 | $res['expiry'] = ($expiry == Block::infinity() ? 'infinite' : $expiry); |
| Index: trunk/phase3/includes/api/ApiDelete.php |
| — | — | @@ -66,8 +66,6 @@ |
| 67 | 67 | |
| 68 | 68 | $articleObj = new Article($titleObj); |
| 69 | 69 | $reason = (isset($params['reason']) ? $params['reason'] : NULL); |
| 70 | | - $dbw = wfGetDb(DB_MASTER); |
| 71 | | - $dbw->begin(); |
| 72 | 70 | $retval = self::delete($articleObj, $params['token'], $reason); |
| 73 | 71 | |
| 74 | 72 | if(!empty($retval)) |
| — | — | @@ -78,7 +76,7 @@ |
| 79 | 77 | $articleObj->doWatch(); |
| 80 | 78 | else if($params['unwatch']) |
| 81 | 79 | $articleObj->doUnwatch(); |
| 82 | | - $dbw->commit(); |
| | 80 | + $this->getMain()->scheduleCommit(); |
| 83 | 81 | $r = array('title' => $titleObj->getPrefixedText(), 'reason' => $reason); |
| 84 | 82 | $this->getResult()->addValue(null, $this->getModuleName(), $r); |
| 85 | 83 | } |
| Index: trunk/phase3/includes/api/ApiUndelete.php |
| — | — | @@ -73,7 +73,7 @@ |
| 74 | 74 | if(!is_array($retval)) |
| 75 | 75 | $this->dieUsageMsg(array('cannotundelete')); |
| 76 | 76 | |
| 77 | | - $dbw->commit(); |
| | 77 | + $this->getMain()->scheduleCommit(); |
| 78 | 78 | $info['title'] = $titleObj->getPrefixedText(); |
| 79 | 79 | $info['revisions'] = $retval[0]; |
| 80 | 80 | $info['fileversions'] = $retval[1]; |
| Index: trunk/phase3/includes/api/ApiEditPage.php |
| — | — | @@ -146,10 +146,8 @@ |
| 147 | 147 | # but that breaks API mode detection through is_null($wgTitle) |
| 148 | 148 | global $wgTitle; |
| 149 | 149 | $wgTitle = null; |
| 150 | | - $dbw = wfGetDb(DB_MASTER); |
| 151 | | - $dbw->begin(); |
| 152 | 150 | $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']); |
| 153 | | - $dbw->commit(); |
| | 151 | + $this->getMain()->scheduleCommit(); |
| 154 | 152 | switch($retval) |
| 155 | 153 | { |
| 156 | 154 | case EditPage::AS_HOOK_ERROR: |
| Index: trunk/phase3/includes/api/ApiUnblock.php |
| — | — | @@ -70,13 +70,11 @@ |
| 71 | 71 | $id = $params['id']; |
| 72 | 72 | $user = $params['user']; |
| 73 | 73 | $reason = (is_null($params['reason']) ? '' : $params['reason']); |
| 74 | | - $dbw = wfGetDb(DB_MASTER); |
| 75 | | - $dbw->begin(); |
| 76 | 74 | $retval = IPUnblockForm::doUnblock($id, $user, $reason, $range); |
| 77 | 75 | if(!empty($retval)) |
| 78 | 76 | $this->dieUsageMsg($retval); |
| 79 | 77 | |
| 80 | | - $dbw->commit(); |
| | 78 | + $this->getMain()->scheduleCommit(); |
| 81 | 79 | $res['id'] = $id; |
| 82 | 80 | $res['user'] = $user; |
| 83 | 81 | $res['reason'] = $reason; |
| Index: trunk/phase3/RELEASE-NOTES |
| — | — | @@ -69,6 +69,7 @@ |
| 70 | 70 | to message 'sidebar' |
| 71 | 71 | ** (bug 6332) Lacking entry Mainpage-url |
| 72 | 72 | ** (bug 8617) Separate main page url and name |
| | 73 | +* Automatically add old redirects to the redirect table when needed |
| 73 | 74 | |
| 74 | 75 | === Bug fixes in 1.13 === |
| 75 | 76 | |