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 | |