r97134 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r97133‎ | r97134 | r97135 >
Date:01:24, 15 September 2011
Author:dantman
Status:deferred
Tags:
Comment:
Checkpoint; PageView is finally back to outputting page content for normal views and oldid views.
Modified paths:
  • /branches/pageoutput/includes/Article.php (modified) (history)
  • /branches/pageoutput/includes/AutoLoader.php (modified) (history)
  • /branches/pageoutput/includes/OutputPage.php (modified) (history)
  • /branches/pageoutput/includes/WikiPage.php (modified) (history)
  • /branches/pageoutput/includes/view/ArticlePageView.php (modified) (history)

Diff [purge]

Index: branches/pageoutput/includes/Article.php
@@ -187,11 +187,13 @@
188188 }
189189
190190 public function getOldID() {
191 - throw MWException(__METHOD__ . " moved to PageView." );
 191+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 192+ throw new MWException(__METHOD__ . " moved to PageView." );
192193 }
193194
194195 public function getOldIDFromRequest() {
195 - throw MWException(__METHOD__ . " moved to PageView." );
 196+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 197+ throw new MWException(__METHOD__ . " moved to PageView." );
196198 }
197199
198200 /**
@@ -308,7 +310,8 @@
309311 * page of the given title.
310312 */
311313 public function view() {
312 - throw MWException(__METHOD__ . " moved to PageView." );
 314+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 315+ throw new MWException(__METHOD__ . " moved to PageView." );
313316 }
314317
315318 /**
@@ -364,95 +367,57 @@
365368 }
366369
367370 public function getRobotPolicy( $action ) {
368 - throw MWException(__METHOD__ . " moved to PageView." );
 371+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 372+ throw new MWException(__METHOD__ . " moved to PageView." );
369373 }
370374
 375+ /**
 376+ * @see OutputPage::formatRobotPolicy
 377+ * @deprecated
 378+ */
371379 public static function formatRobotPolicy( $policy ) {
372 - throw MWException(__METHOD__ . " moved to PageView." );
 380+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 381+ return OutputPage::formatRobotPolicy( $policy );
373382 }
374383
375384 public function showRedirectedFromHeader() {
376 - throw MWException(__METHOD__ . " moved to PageView." );
 385+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 386+ throw new MWException(__METHOD__ . " moved to PageView." );
377387 }
378388
379389 public function showNamespaceHeader() {
380 - throw MWException(__METHOD__ . " moved to PageView." );
 390+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 391+ throw new MWException(__METHOD__ . " moved to PageView." );
381392 }
382393
383394 public function showViewFooter() {
384 - throw MWException(__METHOD__ . " moved to PageView." );
 395+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 396+ throw new MWException(__METHOD__ . " moved to PageView." );
385397 }
386398
387399 public function showPatrolFooter() {
388 - throw MWException(__METHOD__ . " moved to PageView." );
 400+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 401+ throw new MWException(__METHOD__ . " moved to PageView." );
389402 }
390403
391404 public function showMissingArticle() {
392 - throw MWException(__METHOD__ . " moved to PageView." );
 405+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 406+ throw new MWException(__METHOD__ . " moved to PageView." );
393407 }
394408
395409 public function showDeletedRevisionHeader() {
396 - throw MWException(__METHOD__ . " moved to PageView." );
 410+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 411+ throw new MWException(__METHOD__ . " moved to PageView." );
397412 }
398413
399 - /**
400 - * Execute the uncached parse for action=view
401 - */
402414 public function doViewParse() {
403 - global $wgOut;
404 -
405 - $oldid = $this->getOldID();
406 - $parserOptions = $this->mPage->getParserOptions();
407 -
408 - # Render printable version, use printable version cache
409 - $parserOptions->setIsPrintable( $wgOut->isPrintable() );
410 -
411 - # Don't show section-edit links on old revisions... this way lies madness.
412 - if ( !$this->isCurrent() || $wgOut->isPrintable() || !$this->getTitle()->quickUserCan( 'edit' ) ) {
413 - $parserOptions->setEditSection( false );
414 - }
415 -
416 - $useParserCache = $this->useParserCache( $oldid );
417 - $this->outputWikiText( $this->getContent(), $useParserCache, $parserOptions );
418 -
419 - return true;
 415+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 416+ return OutputPage::formatRobotPolicy( $policy );
420417 }
421418
422 - /**
423 - * Try to fetch an expired entry from the parser cache. If it is present,
424 - * output it and return true. If it is not present, output nothing and
425 - * return false. This is used as a callback function for
426 - * PoolCounter::executeProtected().
427 - *
428 - * @return boolean
429 - */
430419 public function tryDirtyCache() {
431 - global $wgOut;
432 - $parserCache = ParserCache::singleton();
433 - $options = $this->mPage->getParserOptions();
434 -
435 - if ( $wgOut->isPrintable() ) {
436 - $options->setIsPrintable( true );
437 - $options->setEditSection( false );
438 - }
439 -
440 - $output = $parserCache->getDirty( $this, $options );
441 -
442 - if ( $output ) {
443 - wfDebug( __METHOD__ . ": sending dirty output\n" );
444 - wfDebugLog( 'dirty', "dirty output " . $parserCache->getKey( $this, $options ) . "\n" );
445 - $wgOut->setSquidMaxage( 0 );
446 - $this->mParserOutput = $output;
447 - $wgOut->addParserOutput( $output );
448 - $wgOut->addHTML( "<!-- parser cache is expired, sending anyway due to pool overload-->\n" );
449 -
450 - return true;
451 - } else {
452 - wfDebugLog( 'dirty', "dirty missing\n" );
453 - wfDebug( __METHOD__ . ": no dirty cache\n" );
454 -
455 - return false;
456 - }
 420+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 421+ return OutputPage::formatRobotPolicy( $policy );
457422 }
458423
459424 /**
@@ -948,149 +913,9 @@
949914 }
950915 }
951916
952 - /**
953 - * Generate the navigation links when browsing through an article revisions
954 - * It shows the information as:
955 - * Revision as of \<date\>; view current revision
956 - * \<- Previous version | Next Version -\>
957 - *
958 - * @param $oldid String: revision ID of this article revision
959 - */
960917 public function setOldSubtitle( $oldid = 0 ) {
961 - global $wgLang, $wgOut, $wgUser, $wgRequest;
962 -
963 - if ( !wfRunHooks( 'DisplayOldSubtitle', array( &$this, &$oldid ) ) ) {
964 - return;
965 - }
966 -
967 - $unhide = $wgRequest->getInt( 'unhide' ) == 1;
968 -
969 - # Cascade unhide param in links for easy deletion browsing
970 - $extraParams = array();
971 - if ( $wgRequest->getVal( 'unhide' ) ) {
972 - $extraParams['unhide'] = 1;
973 - }
974 -
975 - $revision = Revision::newFromId( $oldid );
976 - $timestamp = $revision->getTimestamp();
977 -
978 - $current = ( $oldid == $this->mPage->getLatest() );
979 - $td = $wgLang->timeanddate( $timestamp, true );
980 - $tddate = $wgLang->date( $timestamp, true );
981 - $tdtime = $wgLang->time( $timestamp, true );
982 -
983 - $lnk = $current
984 - ? wfMsgHtml( 'currentrevisionlink' )
985 - : Linker::link(
986 - $this->getTitle(),
987 - wfMsgHtml( 'currentrevisionlink' ),
988 - array(),
989 - $extraParams,
990 - array( 'known', 'noclasses' )
991 - );
992 - $curdiff = $current
993 - ? wfMsgHtml( 'diff' )
994 - : Linker::link(
995 - $this->getTitle(),
996 - wfMsgHtml( 'diff' ),
997 - array(),
998 - array(
999 - 'diff' => 'cur',
1000 - 'oldid' => $oldid
1001 - ) + $extraParams,
1002 - array( 'known', 'noclasses' )
1003 - );
1004 - $prev = $this->getTitle()->getPreviousRevisionID( $oldid ) ;
1005 - $prevlink = $prev
1006 - ? Linker::link(
1007 - $this->getTitle(),
1008 - wfMsgHtml( 'previousrevision' ),
1009 - array(),
1010 - array(
1011 - 'direction' => 'prev',
1012 - 'oldid' => $oldid
1013 - ) + $extraParams,
1014 - array( 'known', 'noclasses' )
1015 - )
1016 - : wfMsgHtml( 'previousrevision' );
1017 - $prevdiff = $prev
1018 - ? Linker::link(
1019 - $this->getTitle(),
1020 - wfMsgHtml( 'diff' ),
1021 - array(),
1022 - array(
1023 - 'diff' => 'prev',
1024 - 'oldid' => $oldid
1025 - ) + $extraParams,
1026 - array( 'known', 'noclasses' )
1027 - )
1028 - : wfMsgHtml( 'diff' );
1029 - $nextlink = $current
1030 - ? wfMsgHtml( 'nextrevision' )
1031 - : Linker::link(
1032 - $this->getTitle(),
1033 - wfMsgHtml( 'nextrevision' ),
1034 - array(),
1035 - array(
1036 - 'direction' => 'next',
1037 - 'oldid' => $oldid
1038 - ) + $extraParams,
1039 - array( 'known', 'noclasses' )
1040 - );
1041 - $nextdiff = $current
1042 - ? wfMsgHtml( 'diff' )
1043 - : Linker::link(
1044 - $this->getTitle(),
1045 - wfMsgHtml( 'diff' ),
1046 - array(),
1047 - array(
1048 - 'diff' => 'next',
1049 - 'oldid' => $oldid
1050 - ) + $extraParams,
1051 - array( 'known', 'noclasses' )
1052 - );
1053 -
1054 - $cdel = '';
1055 -
1056 - // User can delete revisions or view deleted revisions...
1057 - $canHide = $wgUser->isAllowed( 'deleterevision' );
1058 - if ( $canHide || ( $revision->getVisibility() && $wgUser->isAllowed( 'deletedhistory' ) ) ) {
1059 - if ( !$revision->userCan( Revision::DELETED_RESTRICTED ) ) {
1060 - $cdel = Linker::revDeleteLinkDisabled( $canHide ); // rev was hidden from Sysops
1061 - } else {
1062 - $query = array(
1063 - 'type' => 'revision',
1064 - 'target' => $this->getTitle()->getPrefixedDbkey(),
1065 - 'ids' => $oldid
1066 - );
1067 - $cdel = Linker::revDeleteLink( $query, $revision->isDeleted( File::DELETED_RESTRICTED ), $canHide );
1068 - }
1069 - $cdel .= ' ';
1070 - }
1071 -
1072 - # Show user links if allowed to see them. If hidden, then show them only if requested...
1073 - $userlinks = Linker::revUserTools( $revision, !$unhide );
1074 -
1075 - $infomsg = $current && !wfMessage( 'revision-info-current' )->isDisabled()
1076 - ? 'revision-info-current'
1077 - : 'revision-info';
1078 -
1079 - $r = "\n\t\t\t\t<div id=\"mw-{$infomsg}\">" .
1080 - wfMsgExt(
1081 - $infomsg,
1082 - array( 'parseinline', 'replaceafter' ),
1083 - $td,
1084 - $userlinks,
1085 - $revision->getID(),
1086 - $tddate,
1087 - $tdtime,
1088 - $revision->getUser()
1089 - ) .
1090 - "</div>\n" .
1091 - "\n\t\t\t\t<div id=\"mw-revision-nav\">" . $cdel . wfMsgExt( 'revision-nav', array( 'escapenoentities', 'parsemag', 'replaceafter' ),
1092 - $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff ) . "</div>\n\t\t\t";
1093 -
1094 - $wgOut->setSubtitle( $r );
 918+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 919+ return OutputPage::formatRobotPolicy( $policy );
1095920 }
1096921
1097922 /* Caching functions */
@@ -1148,23 +973,9 @@
1149974
1150975 /**#@-*/
1151976
1152 - /**
1153 - * Add the primary page-view wikitext to the output buffer
1154 - * Saves the text into the parser cache if possible.
1155 - * Updates templatelinks if it is out of date.
1156 - *
1157 - * @param $text String
1158 - * @param $cache Boolean
1159 - * @param $parserOptions mixed ParserOptions object, or boolean false
1160 - */
1161977 public function outputWikiText( $text, $cache = true, $parserOptions = false ) {
1162 - global $wgOut;
1163 -
1164 - $this->mParserOutput = $this->getOutputFromWikitext( $text, $cache, $parserOptions );
1165 -
1166 - $this->doCascadeProtectionUpdates( $this->mParserOutput );
1167 -
1168 - $wgOut->addParserOutput( $this->mParserOutput );
 978+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 979+ return OutputPage::formatRobotPolicy( $policy );
1169980 }
1170981
1171982 /**
@@ -1220,51 +1031,9 @@
12211032 return $output;
12221033 }
12231034
1224 - /**
1225 - * This does all the heavy lifting for outputWikitext, except it returns the parser
1226 - * output instead of sending it straight to $wgOut. Makes things nice and simple for,
1227 - * say, embedding thread pages within a discussion system (LiquidThreads)
1228 - *
1229 - * @param $text string
1230 - * @param $cache boolean
1231 - * @param $parserOptions parsing options, defaults to false
1232 - * @return ParserOutput
1233 - */
12341035 public function getOutputFromWikitext( $text, $cache = true, $parserOptions = false ) {
1235 - global $wgParser, $wgEnableParserCache, $wgUseFileCache;
1236 -
1237 - if ( !$parserOptions ) {
1238 - $parserOptions = $this->mPage->getParserOptions();
1239 - }
1240 -
1241 - $time = - wfTime();
1242 - $this->mParserOutput = $wgParser->parse( $text, $this->getTitle(),
1243 - $parserOptions, true, true, $this->getRevIdFetched() );
1244 - $time += wfTime();
1245 -
1246 - # Timing hack
1247 - if ( $time > 3 ) {
1248 - wfDebugLog( 'slow-parse', sprintf( "%-5.2f %s", $time,
1249 - $this->getTitle()->getPrefixedDBkey() ) );
1250 - }
1251 -
1252 - if ( $wgEnableParserCache && $cache && $this->mParserOutput->isCacheable() ) {
1253 - $parserCache = ParserCache::singleton();
1254 - $parserCache->save( $this->mParserOutput, $this, $parserOptions );
1255 - }
1256 -
1257 - // Make sure file cache is not used on uncacheable content.
1258 - // Output that has magic words in it can still use the parser cache
1259 - // (if enabled), though it will generally expire sooner.
1260 - if ( !$this->mParserOutput->isCacheable() || $this->mParserOutput->containsOldMagic() ) {
1261 - $wgUseFileCache = false;
1262 - }
1263 -
1264 - if ( $this->isCurrent() ) {
1265 - $this->mPage->doCascadeProtectionUpdates( $this->mParserOutput );
1266 - }
1267 -
1268 - return $this->mParserOutput;
 1036+ wfDeprecated( __METHOD__, '1.19-pageoutput' );
 1037+ return OutputPage::formatRobotPolicy( $policy );
12691038 }
12701039
12711040 /**
@@ -1388,58 +1157,3 @@
13891158 // ******
13901159 }
13911160
1392 -class PoolWorkArticleView extends PoolCounterWork {
1393 -
1394 - /**
1395 - * @var Article
1396 - */
1397 - private $mArticle;
1398 -
1399 - function __construct( $article, $key, $useParserCache, $parserOptions ) {
1400 - parent::__construct( 'ArticleView', $key );
1401 - $this->mArticle = $article;
1402 - $this->cacheable = $useParserCache;
1403 - $this->parserOptions = $parserOptions;
1404 - }
1405 -
1406 - function doWork() {
1407 - return $this->mArticle->doViewParse();
1408 - }
1409 -
1410 - function getCachedWork() {
1411 - global $wgOut;
1412 -
1413 - $parserCache = ParserCache::singleton();
1414 - $this->mArticle->mParserOutput = $parserCache->get( $this->mArticle, $this->parserOptions );
1415 -
1416 - if ( $this->mArticle->mParserOutput !== false ) {
1417 - wfDebug( __METHOD__ . ": showing contents parsed by someone else\n" );
1418 - $wgOut->addParserOutput( $this->mArticle->mParserOutput );
1419 - # Ensure that UI elements requiring revision ID have
1420 - # the correct version information.
1421 - $wgOut->setRevisionId( $this->mArticle->getLatest() );
1422 - return true;
1423 - }
1424 - return false;
1425 - }
1426 -
1427 - function fallback() {
1428 - return $this->mArticle->tryDirtyCache();
1429 - }
1430 -
1431 - /**
1432 - * @param $status Status
1433 - */
1434 - function error( $status ) {
1435 - global $wgOut;
1436 -
1437 - $wgOut->clearHTML(); // for release() errors
1438 - $wgOut->enableClientCache( false );
1439 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
1440 -
1441 - $errortext = $status->getWikiText( false, 'view-pool-error' );
1442 - $wgOut->addWikiText( '<div class="errorbox">' . $errortext . '</div>' );
1443 -
1444 - return false;
1445 - }
1446 -}
Index: branches/pageoutput/includes/OutputPage.php
@@ -682,6 +682,35 @@
683683 }
684684
685685 /**
 686+ * Converts a String robot policy into an associative array, to allow
 687+ * merging of several policies using array_merge().
 688+ * @param $policy Mixed, returns empty array on null/false/'', transparent
 689+ * to already-converted arrays, converts String.
 690+ * @return Array: 'index' => <indexpolicy>, 'follow' => <followpolicy>
 691+ */
 692+ public static function formatRobotPolicy( $policy ) {
 693+ if ( is_array( $policy ) ) {
 694+ return $policy;
 695+ } elseif ( !$policy ) {
 696+ return array();
 697+ }
 698+
 699+ $policy = explode( ',', $policy );
 700+ $policy = array_map( 'trim', $policy );
 701+
 702+ $arr = array();
 703+ foreach ( $policy as $var ) {
 704+ if ( in_array( $var, array( 'index', 'noindex' ) ) ) {
 705+ $arr['index'] = $var;
 706+ } elseif ( in_array( $var, array( 'follow', 'nofollow' ) ) ) {
 707+ $arr['follow'] = $var;
 708+ }
 709+ }
 710+
 711+ return $arr;
 712+ }
 713+
 714+ /**
686715 * Set the robot policy for the page: <http://www.robotstxt.org/meta.html>
687716 *
688717 * @param $policy String: the literal string to output as the contents of
@@ -690,7 +719,7 @@
691720 * @return null
692721 */
693722 public function setRobotPolicy( $policy ) {
694 - $policy = Article::formatRobotPolicy( $policy );
 723+ $policy = self::formatRobotPolicy( $policy );
695724
696725 if( isset( $policy['index'] ) ) {
697726 $this->setIndexPolicy( $policy['index'] );
Index: branches/pageoutput/includes/AutoLoader.php
@@ -274,6 +274,7 @@
275275 # includes/view
276276 'PageView' => 'includes/view/PageView.php',
277277 'ArticlePageView' => 'includes/view/ArticlePageView.php',
 278+ 'PoolWorkArticleView' => 'includes/view/ArticlePageView.php',
278279
279280 # includes/api
280281 'ApiBase' => 'includes/api/ApiBase.php',
Index: branches/pageoutput/includes/WikiPage.php
@@ -710,7 +710,7 @@
711711 * @param $user User The relevant user
712712 * @return boolean
713713 */
714 - public function isParserCacheUsed( User $user, $oldid ) {
 714+ public function isParserCacheUsed( User $user, $oldid=false ) {
715715 global $wgEnableParserCache;
716716
717717 return $wgEnableParserCache
Index: branches/pageoutput/includes/view/ArticlePageView.php
@@ -2,39 +2,24 @@
33
44 class ArticlePageView extends PageView {
55
6 - private $mOldId, $mRedirectedFrom, $mRedirectUrl, $mPage, $mParserOutput;
 6+ protected $mRedirectedFrom, $mRedirectUrl, $mParserOutput;
 7+ private $mOldId, $mRevision, $mPage;
78
89 function getTabs() {
910 }
1011
1112 /** **/
1213
13 - public function getPage() {
14 - if ( is_null( $this->mPage ) ) {
15 - $this->mPage = WikiPage::factory( $this->getTitle() );
16 - }
17 - return $this->mPage;
18 - }
19 -
2014 /**
21 - * @return int The oldid of the article that is to be shown, 0 for the
22 - * current revision
 15+ * Prepare the oldid, make any possible title changes based on it, and set the
 16+ * redirect url if needed.
2317 */
24 - public function getOldID() {
25 - // @fixme Merge getOldID and getOldIDFromRequest together for PageView
26 - if ( is_null( $this->mOldId ) ) {
27 - $this->mOldId = $this->getOldIDFromRequest();
 18+ protected function prepareTitleAndRevision() {
 19+ if ( !is_null($this->mOldId) && !is_null($this->mRedirectUrl) ) {
 20+ // If oldid, redirecturl, and page are ready exit
 21+ return;
2822 }
29 -
30 - return $this->mOldId;
31 - }
32 -
33 - /**
34 - * Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect
35 - *
36 - * @return int The old id for the request
37 - */
38 - public function getOldIDFromRequest() {
 23+
3924 $this->mRedirectUrl = false;
4025
4126 $request = $this->getRequest();
@@ -43,7 +28,7 @@
4429
4530 if ( isset( $oldid ) ) {
4631 $oldid = intval( $oldid );
47 - if ( $rRequest->getVal( 'direction' ) == 'next' ) {
 32+ if ( $request->getVal( 'direction' ) == 'next' ) {
4833 $nextid = $this->getTitle()->getNextRevisionID( $oldid );
4934 if ( $nextid ) {
5035 $oldid = $nextid;
@@ -62,10 +47,102 @@
6348 $oldid = 0;
6449 }
6550
66 - return $oldid;
 51+ $this->mOldId = $oldid;
 52+
 53+ if ( $this->mOldId ) {
 54+ // Preload the revision on an &oldid= to see if we need to use a different title
 55+ // We may not need the Revision instance for parser cached current pages so
 56+ // We don't load the revision yet for those
 57+ # Fixme WikiPage actually holds latest rev information perhaps we shouldn't preload the revision instance
 58+ $rev = Revision::newFromId( $this->mOldId );
 59+ if ( $rev ) {
 60+ $this->mRevision = $rev;
 61+ if ( $this->getTitle()->getArticleID() != $rev->getPage() ) {
 62+ $this->setTitle( $rev->getTitle() );
 63+ }
 64+ } else {
 65+ // Make note that there was no revision found so we don't double-query for a nonexistant rev
 66+ $this->mRevision = false;
 67+ }
 68+ }
 69+
6770 }
6871
6972 /**
 73+ * Returns a WikiPage instance that can be used for this PageView
 74+ * @return WikiPage
 75+ */
 76+ public function getPage() {
 77+ if ( is_null( $this->mPage ) ) {
 78+ $this->prepareTitleAndRevision();
 79+ $this->mPage = WikiPage::factory( $this->getTitle() );
 80+ }
 81+ return $this->mPage;
 82+ }
 83+
 84+ /**
 85+ * Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect
 86+ * @return int The oldid of the article that is to be shown, 0 for the
 87+ * current revision
 88+ */
 89+ public function getOldID() {
 90+ if ( is_null( $this->mOldId ) ) {
 91+ $this->prepareTitleAndRevision();
 92+ }
 93+ return $this->mOldId;
 94+ }
 95+
 96+ /**
 97+ * Returns true if we are looking at the latest revision for a page
 98+ * Returns true if $oldid is 0 or oldid refers to the latest revision
 99+ * Note that this returns true for nonexistant pages unlike Article::isCurrent did
 100+ * @return bool
 101+ */
 102+ public function isLatest() {
 103+ $oldid = $this->getOldID();
 104+ return !$oldid || !$this->mRevision || $this->mRevision->isCurrent();
 105+ }
 106+
 107+ /**
 108+ * Returns true if the currently-referenced revision is the current edit
 109+ * to this page (and it exists).
 110+ * @return bool
 111+ */
 112+ public function isCurrent() {
 113+ # If no oldid, this is the current version.
 114+ if ( $this->getOldID() == 0 ) {
 115+ return true;
 116+ }
 117+
 118+ return $this->getPage()->exists() && $this->getPage()->getLatest() == $this->getOldID();
 119+ }
 120+
 121+ /**
 122+ * Returns a revision instance for the oldid or current page we are displaying
 123+ * @return Revision
 124+ * @fixme Article::fetchContent had a lot of wfDebug calls we should replicate
 125+ */
 126+ public function getRevision() {
 127+ # getOldID calls prepareTitleAndRevision which may preload mRevision so
 128+ # we call this here instead of when we try to create a rev
 129+ $oldid = $this->getOldID();
 130+ if ( is_null($this->mRevision) ) {
 131+ if ( !$oldid || $oldid == $this->getPage()->getLatest() ) {
 132+ # WikiPage caches a revision on it's own, query from there for
 133+ # the latest revision to avoid double loading from the database
 134+ $this->mRevision = $this->getPage()->getRevision();
 135+ } else {
 136+ $this->mRevision = Revision::newFromID( $oldid );
 137+ }
 138+ if ( is_null($this->mRevision) ) {
 139+ # If revision was not loaded set mRevision to false to avoid double-querying the database
 140+ $this->mRevision = false;
 141+ }
 142+ }
 143+ return $this->mRevision;
 144+ }
 145+
 146+ /**
70147 * Get the robot policy to be used for the current view
71148 * @return Array the policy that should be set
72149 */
@@ -108,13 +185,13 @@
109186 }
110187
111188 # Otherwise, construct the policy based on the various config variables.
112 - $policy = self::formatRobotPolicy( $wgDefaultRobotPolicy );
 189+ $policy = OutputPage::formatRobotPolicy( $wgDefaultRobotPolicy );
113190
114191 if ( isset( $wgNamespaceRobotPolicies[$ns] ) ) {
115192 # Honour customised robot policies for this namespace
116193 $policy = array_merge(
117194 $policy,
118 - self::formatRobotPolicy( $wgNamespaceRobotPolicies[$ns] )
 195+ OutputPage::formatRobotPolicy( $wgNamespaceRobotPolicies[$ns] )
119196 );
120197 }
121198 if ( $this->getTitle()->canUseNoindex() && is_object( $this->mParserOutput ) && $this->mParserOutput->getIndexPolicy() ) {
@@ -130,42 +207,13 @@
131208 # (bug 14900) site config can override user-defined __INDEX__ or __NOINDEX__
132209 $policy = array_merge(
133210 $policy,
134 - self::formatRobotPolicy( $wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()] )
 211+ OutputPage::formatRobotPolicy( $wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()] )
135212 );
136213 }
137214
138215 return $policy;
139216 }
140217
141 - /**
142 - * Converts a String robot policy into an associative array, to allow
143 - * merging of several policies using array_merge().
144 - * @param $policy Mixed, returns empty array on null/false/'', transparent
145 - * to already-converted arrays, converts String.
146 - * @return Array: 'index' => <indexpolicy>, 'follow' => <followpolicy>
147 - */
148 - public static function formatRobotPolicy( $policy ) {
149 - if ( is_array( $policy ) ) {
150 - return $policy;
151 - } elseif ( !$policy ) {
152 - return array();
153 - }
154 -
155 - $policy = explode( ',', $policy );
156 - $policy = array_map( 'trim', $policy );
157 -
158 - $arr = array();
159 - foreach ( $policy as $var ) {
160 - if ( in_array( $var, array( 'index', 'noindex' ) ) ) {
161 - $arr['index'] = $var;
162 - } elseif ( in_array( $var, array( 'follow', 'nofollow' ) ) ) {
163 - $arr['follow'] = $var;
164 - }
165 - }
166 -
167 - return $arr;
168 - }
169 -
170218 /** PageView render and sub-areas of the rendering process **/
171219
172220 function render() {
@@ -178,8 +226,8 @@
179227 $out = $this->getOutput();
180228 $user = $this->getUser();
181229
182 - # Get variables from query string
183 - $oldid = $this->getOldID();
 230+ // Prepare some info we might need, this will set mRedirectUrl if needed
 231+ $this->prepareTitleAndRevision();
184232
185233 # getOldID may want us to redirect somewhere else
186234 if ( $this->mRedirectUrl ) {
@@ -190,12 +238,22 @@
191239 return;
192240 }
193241
 242+ # Ensure that the user has the rights to read this page
 243+ if ( !$this->getTitle()->userCanRead() ) {
 244+ $out->loginToUse();
 245+ $out->output();
 246+ $out->disable();
 247+ wfProfileOut( __METHOD__ );
 248+ return;
 249+ }
 250+
194251 # Set page title (may be overridden by DISPLAYTITLE)
195252 $out->setPageTitle( $this->getTitle()->getPrefixedText() );
196253
197254 # If we got diff in the query, we want to see a diff page instead of the article.
198255 if ( $request->getCheck( 'diff' ) ) {
199256 wfDebug( __METHOD__ . ": showing diff page\n" );
 257+ // @fixme DifferenceEngine shouldn't be rendering anything other than the diff, we should handle diffonly ourselves
200258 $this->showDiffPage();
201259 wfProfileOut( __METHOD__ );
202260
@@ -218,7 +276,12 @@
219277 $parserOptions->setEditSection( false );
220278 }
221279
 280+ # Get variables from query string
 281+ $oldid = $this->getOldID();
 282+
222283 # Try client and file cache
 284+ # @fixme: We can't return file cached content for a permalink to the current
 285+ # revision, however we CAN return a 304 for the current revision's permalink
223286 if ( $oldid === 0 && $this->getPage()->checkTouched() ) {
224287 if ( $wgUseETag ) {
225288 $out->setETag( $parserCache->getETag( $this->getPage(), $parserOptions ) );
@@ -247,7 +310,7 @@
248311 }
249312
250313 # Should the parser cache be used?
251 - $useParserCache = $this->getPage()->isParserCacheUsed( $user, $oldid );
 314+ $useParserCache = $this->getPage()->isParserCacheUsed( $user ) && $this->isCurrent();
252315 wfDebug( __METHOD__ . ' using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
253316 if ( $user->getStubThreshold() ) {
254317 wfIncrStats( 'pcache_miss_stub' );
@@ -256,125 +319,112 @@
257320 $wasRedirected = $this->showRedirectedFromHeader();
258321 $this->showNamespaceHeader();
259322
260 - # Iterate through the possible ways of constructing the output text.
261 - # Keep going until $outputDone is set, or we run out of things to do.
262 - $pass = 0;
263323 $outputDone = false;
264324 $this->mParserOutput = false;
265325
266 - while ( !$outputDone && ++$pass ) {
267 - switch( $pass ) {
268 - case 1:
269 - wfRunHooks( 'ArticleViewHeader', array( &$this, &$outputDone, &$useParserCache ) ); // @fixme
270 - break;
271 - case 2:
272 - # Try the parser cache
273 - if ( $useParserCache ) {
274 - $this->mParserOutput = $parserCache->get( $this->getPage(), $parserOptions );
 326+ wfRunHooks( 'ArticleViewHeader', array( &$this, &$outputDone, &$useParserCache ) ); // @fixme
275327
276 - if ( $this->mParserOutput !== false ) {
277 - wfDebug( __METHOD__ . ": showing parser cache contents\n" );
278 - $out->addParserOutput( $this->mParserOutput );
279 - # Ensure that UI elements requiring revision ID have
280 - # the correct version information.
281 - $out->setRevisionId( $this->getPage()->getLatest() );
282 - $outputDone = true;
283 - # Preload timestamp to avoid a DB hit
284 - if ( isset( $this->mParserOutput->mTimestamp ) ) {
285 - $this->getPage()->setTimestamp( $this->mParserOutput->mTimestamp );
286 - }
287 - }
288 - }
289 - break;
290 - case 3:
291 - $text = $this->getContent();
292 - if ( $text === false || $this->getPage()->getID() == 0 ) {
293 - wfDebug( __METHOD__ . ": showing missing article\n" );
294 - $this->showMissingArticle();
295 - wfProfileOut( __METHOD__ );
296 - return;
297 - }
 328+ # Try the parser cache for page output
 329+ if ( !$outputDone && $useParserCache ) {
 330+ $this->mParserOutput = $parserCache->get( $this->getPage(), $parserOptions );
298331
299 - # Another whitelist check in case oldid is altering the title
300 - if ( !$this->getTitle()->userCanRead() ) {
301 - wfDebug( __METHOD__ . ": denied on secondary read check\n" );
302 - $out->loginToUse();
303 - $out->output();
304 - $out->disable();
305 - wfProfileOut( __METHOD__ );
306 - return;
307 - }
 332+ if ( $this->mParserOutput !== false ) {
 333+ wfDebug( __METHOD__ . ": showing parser cache contents\n" );
 334+ $out->addParserOutput( $this->mParserOutput );
 335+ # Ensure that UI elements requiring revision ID have
 336+ # the correct version information.
 337+ $out->setRevisionId( $this->getPage()->getLatest() );
 338+ $outputDone = true;
 339+ # Preload timestamp to avoid a DB hit
 340+ if ( isset( $this->mParserOutput->mTimestamp ) ) {
 341+ $this->getPage()->setTimestamp( $this->mParserOutput->mTimestamp );
 342+ }
 343+ }
 344+ }
308345
309 - # Are we looking at an old revision
310 - if ( $oldid && !is_null( $this->mRevision ) ) {
311 - $this->setOldSubtitle( $oldid );
 346+ # At this point if we haven't found anything in any cache see if the page
 347+ # even exists, if not show a missing article page
 348+ if ( !$outputDone && $this->getPage()->getID() == 0 ) {
 349+ wfDebug( __METHOD__ . ": showing missing article\n" );
 350+ $this->showMissingArticle();
 351+ wfProfileOut( __METHOD__ );
 352+ return;
 353+ }
312354
313 - if ( !$this->showDeletedRevisionHeader() ) {
314 - wfDebug( __METHOD__ . ": cannot view deleted revision\n" );
315 - wfProfileOut( __METHOD__ );
316 - return;
317 - }
 355+ # Fetch the content and see if there is any specialty page handling to do instead of parsing
 356+ if ( !$outputDone ) {
 357+ $rev = $this->getRevision();
 358+
 359+ if ( $rev ) {
 360+ $text = $rev->getText( Revision::FOR_THIS_USER ); // Loads if user is allowed
 361+ } else {
 362+ $text = false;
 363+ }
 364+
 365+ wfRunHooks( 'ArticleAfterFetchContent', array( &$this, &$text ) ); // @fixme
 366+
 367+ # Check if the text is false, this can happen due to slow slaves (bad oldids too?)
 368+ if ( $text === false ) {
 369+ wfDebug( __METHOD__ . ": showing missing article due to false return from revision text\n" );
 370+ $this->showMissingArticle();
 371+ wfProfileOut( __METHOD__ );
 372+ return;
 373+ }
318374
319 - # If this "old" version is the current, then try the parser cache...
320 - if ( $oldid === $this->getPage()->getLatest() && $this->getPage()->isParserCacheUsed( $user, false ) ) {
321 - $this->mParserOutput = $parserCache->get( $this->getPage(), $parserOptions );
322 - if ( $this->mParserOutput ) {
323 - wfDebug( __METHOD__ . ": showing parser cache for current rev permalink\n" );
324 - $out->addParserOutput( $this->mParserOutput );
325 - $out->setRevisionId( $this->getPage()->getLatest() );
326 - $outputDone = true;
327 - break;
328 - }
329 - }
330 - }
 375+ # Ensure that UI elements requiring revision ID have
 376+ # the correct version information.
 377+ $out->setRevisionId( $rev->getId() );
331378
332 - # Ensure that UI elements requiring revision ID have
333 - # the correct version information.
334 - $out->setRevisionId( $this->getRevIdFetched() );
 379+ # Pages containing custom CSS or JavaScript get special treatment
 380+ if ( $this->getTitle()->isCssOrJsPage() || $this->getTitle()->isCssJsSubpage() ) {
 381+ wfDebug( __METHOD__ . ": showing CSS/JS source\n" );
 382+ $this->showCssOrJsPage();
 383+ $outputDone = true;
 384+ } elseif( !wfRunHooks( 'ArticleViewCustom', array( $text, $this->getTitle(), $out ) ) ) { // @fixme
 385+ # Allow extensions do their own custom view for certain pages
 386+ $outputDone = true;
 387+ } else {
 388+ $rt = Title::newFromRedirectArray( $text );
 389+ if ( $rt ) {
 390+ wfDebug( __METHOD__ . ": showing redirect=no page\n" );
 391+ # Viewing a redirect page (e.g. with parameter redirect=no)
 392+ # Don't append the subtitle if this was an old revision
 393+ $out->addHTML( $this->viewRedirect( $rt, !$wasRedirected && $this->isCurrent() ) );
 394+ # Parse just to get categories, displaytitle, etc.
 395+ $this->mParserOutput = $wgParser->parse( $text, $this->getTitle(), $parserOptions );
 396+ $out->addParserOutputNoText( $this->mParserOutput );
 397+ $outputDone = true;
 398+ }
 399+ }
 400+ }
335401
336 - # Pages containing custom CSS or JavaScript get special treatment
337 - if ( $this->getTitle()->isCssOrJsPage() || $this->getTitle()->isCssJsSubpage() ) {
338 - wfDebug( __METHOD__ . ": showing CSS/JS source\n" );
339 - $this->showCssOrJsPage();
340 - $outputDone = true;
341 - } elseif( !wfRunHooks( 'ArticleViewCustom', array( $this->mContent, $this->getTitle(), $out ) ) ) { // @fixme
342 - # Allow extensions do their own custom view for certain pages
343 - $outputDone = true;
344 - } else {
345 - $rt = Title::newFromRedirectArray( $text );
346 - if ( $rt ) {
347 - wfDebug( __METHOD__ . ": showing redirect=no page\n" );
348 - # Viewing a redirect page (e.g. with parameter redirect=no)
349 - # Don't append the subtitle if this was an old revision
350 - $out->addHTML( $this->viewRedirect( $rt, !$wasRedirected && $this->isCurrent() ) );
351 - # Parse just to get categories, displaytitle, etc.
352 - $this->mParserOutput = $wgParser->parse( $text, $this->getTitle(), $parserOptions );
353 - $out->addParserOutputNoText( $this->mParserOutput );
354 - $outputDone = true;
355 - }
356 - }
357 - break;
358 - case 4:
359 - # Run the parse, protected by a pool counter
360 - wfDebug( __METHOD__ . ": doing uncached parse\n" );
 402+ # Run the parse, protected by a pool counter
 403+ if ( !$outputDone ) {
 404+ wfDebug( __METHOD__ . ": doing uncached parse\n" );
361405
362 - $key = $parserCache->getKey( $this->getPage(), $parserOptions );
363 - $poolArticleView = new PoolWorkArticleView( $this, $key, $useParserCache, $parserOptions ); // @fixme
 406+ $key = $parserCache->getKey( $this->getPage(), $parserOptions );
 407+ $poolArticleView = new PoolWorkArticleView( $this, $key, $useParserCache, $parserOptions, $text );
364408
365 - if ( !$poolArticleView->execute() ) {
366 - # Connection or timeout error
367 - wfProfileOut( __METHOD__ );
368 - return;
369 - } else {
370 - $outputDone = true;
371 - }
372 - break;
373 - # Should be unreachable, but just in case...
374 - default:
375 - break 2;
 409+ if ( !$poolArticleView->execute() ) {
 410+ # Connection or timeout error
 411+ wfProfileOut( __METHOD__ );
 412+ return;
 413+ } else {
 414+ $outputDone = true;
376415 }
377416 }
378417
 418+ # Are we looking at an old revision
 419+ if ( $oldid ) {
 420+ $this->setOldSubtitle();
 421+
 422+ if ( !$this->showDeletedRevisionHeader() ) {
 423+ wfDebug( __METHOD__ . ": cannot view deleted revision\n" );
 424+ wfProfileOut( __METHOD__ );
 425+ return;
 426+ }
 427+ }
 428+
379429 # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
380430 if ( $this->mParserOutput ) {
381431 $titleText = $this->mParserOutput->getTitleText();
@@ -441,6 +491,7 @@
442492 $out->addInlineScript( "redirectToFragment(\"$fragment\");" );
443493 }
444494
 495+ // @fixme Always set a canonical that takes $wgCanonicalServer into account
445496 // Add a <link rel="canonical"> tag
446497 $out->addLink( array( 'rel' => 'canonical',
447498 'href' => $this->getTitle()->getLocalURL() )
@@ -620,13 +671,13 @@
621672 public function showDeletedRevisionHeader() {
622673 $out = $this->getOutput();
623674
624 - if ( !$this->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
 675+ if ( !$this->getRevision()->isDeleted( Revision::DELETED_TEXT ) ) {
625676 // Not deleted
626677 return true;
627678 }
628679
629680 // If the user is not allowed to see it...
630 - if ( !$this->mRevision->userCan( Revision::DELETED_TEXT ) ) {
 681+ if ( !$this->getRevision()->userCan( Revision::DELETED_TEXT ) ) {
631682 $out->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
632683 'rev-deleted-text-permission' );
633684
@@ -636,7 +687,7 @@
637688 # Give explanation and add a link to view the revision...
638689 $oldid = intval( $this->getOldID() );
639690 $link = $this->getTitle()->getFullUrl( "oldid={$oldid}&unhide=1" );
640 - $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
 691+ $msg = $this->getRevision()->isDeleted( Revision::DELETED_RESTRICTED ) ?
641692 'rev-suppressed-text-unhide' : 'rev-deleted-text-unhide';
642693 $out->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
643694 array( $msg, $link ) );
@@ -644,7 +695,7 @@
645696 return false;
646697 // We are allowed to see...
647698 } else {
648 - $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
 699+ $msg = $this->getRevision()->isDeleted( Revision::DELETED_RESTRICTED ) ?
649700 'rev-suppressed-text-view' : 'rev-deleted-text-view';
650701 $out->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", $msg );
651702
@@ -652,5 +703,327 @@
653704 }
654705 }
655706
 707+ /**
 708+ * Generate the navigation links when browsing through an article revisions
 709+ * It shows the information as:
 710+ * Revision as of \<date\>; view current revision
 711+ * \<- Previous version | Next Version -\>
 712+ */
 713+ public function setOldSubtitle() {
 714+ if ( !wfRunHooks( 'DisplayOldSubtitle', array( &$this, &$oldid ) ) ) {
 715+ return;
 716+ }
 717+
 718+ $request = $this->getRequest();
 719+ $lang = $this->getLang();
 720+
 721+ $unhide = $request->getInt( 'unhide' ) == 1;
 722+
 723+ # Cascade unhide param in links for easy deletion browsing
 724+ $extraParams = array();
 725+ if ( $request->getVal( 'unhide' ) ) {
 726+ $extraParams['unhide'] = 1;
 727+ }
 728+
 729+ $revision = $this->getRevision();
 730+ $timestamp = $revision->getTimestamp();
 731+
 732+ $current = $this->isCurrent();
 733+ $td = $lang->timeanddate( $timestamp, true );
 734+ $tddate = $lang->date( $timestamp, true );
 735+ $tdtime = $lang->time( $timestamp, true );
 736+
 737+ $lnk = $current
 738+ ? wfMsgHtml( 'currentrevisionlink' )
 739+ : Linker::link(
 740+ $this->getTitle(),
 741+ wfMsgHtml( 'currentrevisionlink' ),
 742+ array(),
 743+ $extraParams,
 744+ array( 'known', 'noclasses' )
 745+ );
 746+ $curdiff = $current
 747+ ? wfMsgHtml( 'diff' )
 748+ : Linker::link(
 749+ $this->getTitle(),
 750+ wfMsgHtml( 'diff' ),
 751+ array(),
 752+ array(
 753+ 'diff' => 'cur',
 754+ 'oldid' => $this->getOldID()
 755+ ) + $extraParams,
 756+ array( 'known', 'noclasses' )
 757+ );
 758+ $prev = $this->getTitle()->getPreviousRevisionID( $this->getOldID() ) ;
 759+ $prevlink = $prev
 760+ ? Linker::link(
 761+ $this->getTitle(),
 762+ wfMsgHtml( 'previousrevision' ),
 763+ array(),
 764+ array(
 765+ 'direction' => 'prev',
 766+ 'oldid' => $this->getOldID()
 767+ ) + $extraParams,
 768+ array( 'known', 'noclasses' )
 769+ )
 770+ : wfMsgHtml( 'previousrevision' );
 771+ $prevdiff = $prev
 772+ ? Linker::link(
 773+ $this->getTitle(),
 774+ wfMsgHtml( 'diff' ),
 775+ array(),
 776+ array(
 777+ 'diff' => 'prev',
 778+ 'oldid' => $this->getOldID()
 779+ ) + $extraParams,
 780+ array( 'known', 'noclasses' )
 781+ )
 782+ : wfMsgHtml( 'diff' );
 783+ $nextlink = $current
 784+ ? wfMsgHtml( 'nextrevision' )
 785+ : Linker::link(
 786+ $this->getTitle(),
 787+ wfMsgHtml( 'nextrevision' ),
 788+ array(),
 789+ array(
 790+ 'direction' => 'next',
 791+ 'oldid' => $this->getOldID()
 792+ ) + $extraParams,
 793+ array( 'known', 'noclasses' )
 794+ );
 795+ $nextdiff = $current
 796+ ? wfMsgHtml( 'diff' )
 797+ : Linker::link(
 798+ $this->getTitle(),
 799+ wfMsgHtml( 'diff' ),
 800+ array(),
 801+ array(
 802+ 'diff' => 'next',
 803+ 'oldid' => $this->getOldID()
 804+ ) + $extraParams,
 805+ array( 'known', 'noclasses' )
 806+ );
 807+
 808+ $cdel = '';
 809+
 810+ // User can delete revisions or view deleted revisions...
 811+ $canHide = $this->getUser()->isAllowed( 'deleterevision' );
 812+ if ( $canHide || ( $revision->getVisibility() && $this->getUser()->isAllowed( 'deletedhistory' ) ) ) {
 813+ if ( !$revision->userCan( Revision::DELETED_RESTRICTED ) ) {
 814+ $cdel = Linker::revDeleteLinkDisabled( $canHide ); // rev was hidden from Sysops
 815+ } else {
 816+ $query = array(
 817+ 'type' => 'revision',
 818+ 'target' => $this->getTitle()->getPrefixedDbkey(),
 819+ 'ids' => $this->getOldID()
 820+ );
 821+ $cdel = Linker::revDeleteLink( $query, $revision->isDeleted( File::DELETED_RESTRICTED ), $canHide );
 822+ }
 823+ $cdel .= ' ';
 824+ }
 825+
 826+ # Show user links if allowed to see them. If hidden, then show them only if requested...
 827+ $userlinks = Linker::revUserTools( $revision, !$unhide );
 828+
 829+ $infomsg = $current && !wfMessage( 'revision-info-current' )->isDisabled()
 830+ ? 'revision-info-current'
 831+ : 'revision-info';
 832+
 833+ $r = "\n\t\t\t\t<div id=\"mw-{$infomsg}\">" .
 834+ wfMsgExt(
 835+ $infomsg,
 836+ array( 'parseinline', 'replaceafter' ),
 837+ $td,
 838+ $userlinks,
 839+ $revision->getID(),
 840+ $tddate,
 841+ $tdtime,
 842+ $revision->getUser()
 843+ ) .
 844+ "</div>\n" .
 845+ "\n\t\t\t\t<div id=\"mw-revision-nav\">" . $cdel . wfMsgExt( 'revision-nav', array( 'escapenoentities', 'parsemag', 'replaceafter' ),
 846+ $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff ) . "</div>\n\t\t\t";
 847+
 848+ $this->getOutput()->setSubtitle( $r );
 849+ }
 850+
 851+ /** Code called by PoolWorkArticleView **/
 852+
 853+ /**
 854+ * Execute the uncached parse for action=view
 855+ */
 856+ public function doViewParse( $text ) {
 857+ $oldid = $this->getOldID();
 858+ $parserOptions = $this->getPage()->getParserOptions();
 859+
 860+ # Render printable version, use printable version cache
 861+ $parserOptions->setIsPrintable( $this->getOutput()->isPrintable() );
 862+
 863+ # Don't show section-edit links on old revisions... this way lies madness.
 864+ if ( !$this->isCurrent() || $this->getOutput() || !$this->getTitle()->quickUserCan( 'edit' ) ) {
 865+ $parserOptions->setEditSection( false );
 866+ }
 867+
 868+ $useParserCache = $this->getPage()->isParserCacheUsed( $this->getUser() ) && $this->isCurrent();
 869+ $this->outputWikiText( $text, $useParserCache, $parserOptions );
 870+
 871+ return true;
 872+ }
 873+
 874+ /**
 875+ * Add the primary page-view wikitext to the output buffer
 876+ * Saves the text into the parser cache if possible.
 877+ * Updates templatelinks if it is out of date.
 878+ *
 879+ * @param $text String
 880+ * @param $cache Boolean
 881+ * @param $parserOptions mixed ParserOptions object, or boolean false
 882+ */
 883+ public function outputWikiText( $text, $cache = true, $parserOptions = false ) {
 884+ $this->mParserOutput = $this->getOutputFromWikitext( $text, $cache, $parserOptions );
 885+
 886+ $this->doCascadeProtectionUpdates( $this->mParserOutput );
 887+
 888+ $this->getOutput()->addParserOutput( $this->mParserOutput );
 889+ }
 890+
 891+ /**
 892+ * This does all the heavy lifting for outputWikitext, except it returns the parser
 893+ * output instead of sending it straight to OutputPage. Makes things nice and simple for,
 894+ * say, embedding thread pages within a discussion system (LiquidThreads)
 895+ *
 896+ * @param $text string
 897+ * @param $cache boolean
 898+ * @param $parserOptions parsing options, defaults to false
 899+ * @return ParserOutput
 900+ */
 901+ public function getOutputFromWikitext( $text, $cache = true, $parserOptions = false ) {
 902+ global $wgParser, $wgEnableParserCache, $wgUseFileCache;
 903+
 904+ if ( !$parserOptions ) {
 905+ $parserOptions = $this->mPage->getParserOptions();
 906+ }
 907+
 908+ $time = - wfTime();
 909+ $this->mParserOutput = $wgParser->parse( $text, $this->getTitle(),
 910+ $parserOptions, true, true, $this->getRevision()->getId() );
 911+ $time += wfTime();
 912+
 913+ # Timing hack
 914+ if ( $time > 3 ) {
 915+ wfDebugLog( 'slow-parse', sprintf( "%-5.2f %s", $time,
 916+ $this->getTitle()->getPrefixedDBkey() ) );
 917+ }
 918+
 919+ if ( $wgEnableParserCache && $cache && $this->mParserOutput->isCacheable() ) {
 920+ $parserCache = ParserCache::singleton();
 921+ $parserCache->save( $this->mParserOutput, $this->getPage(), $parserOptions );
 922+ }
 923+
 924+ // Make sure file cache is not used on uncacheable content.
 925+ // Output that has magic words in it can still use the parser cache
 926+ // (if enabled), though it will generally expire sooner.
 927+ if ( !$this->mParserOutput->isCacheable() || $this->mParserOutput->containsOldMagic() ) {
 928+ $wgUseFileCache = false;
 929+ }
 930+
 931+ if ( $this->isCurrent() ) {
 932+ $this->mPage->doCascadeProtectionUpdates( $this->mParserOutput );
 933+ }
 934+
 935+ return $this->mParserOutput;
 936+ }
 937+
 938+ /**
 939+ * Try to fetch an expired entry from the parser cache. If it is present,
 940+ * output it and return true. If it is not present, output nothing and
 941+ * return false. This is used as a callback function for
 942+ * PoolCounter::executeProtected().
 943+ *
 944+ * @return boolean
 945+ */
 946+ public function tryDirtyCache() {
 947+ $out = $this->getOutput();
 948+ $parserCache = ParserCache::singleton();
 949+ $options = $this->mPage->getParserOptions();
 950+
 951+ if ( $out->isPrintable() ) {
 952+ $options->setIsPrintable( true );
 953+ $options->setEditSection( false );
 954+ }
 955+
 956+ $output = $parserCache->getDirty( $this, $options );
 957+
 958+ if ( $output ) {
 959+ wfDebug( __METHOD__ . ": sending dirty output\n" );
 960+ wfDebugLog( 'dirty', "dirty output " . $parserCache->getKey( $this, $options ) . "\n" );
 961+ $out->setSquidMaxage( 0 );
 962+ $this->mParserOutput = $output;
 963+ $out->addParserOutput( $output );
 964+ $out->addHTML( "<!-- parser cache is expired, sending anyway due to pool overload-->\n" );
 965+
 966+ return true;
 967+ } else {
 968+ wfDebugLog( 'dirty', "dirty missing\n" );
 969+ wfDebug( __METHOD__ . ": no dirty cache\n" );
 970+
 971+ return false;
 972+ }
 973+ }
656974 }
657975
 976+class PoolWorkArticleView extends PoolCounterWork {
 977+
 978+ /**
 979+ * @var PageView
 980+ */
 981+ private $view;
 982+
 983+ function __construct( $view, $key, $useParserCache, $parserOptions, $text ) {
 984+ parent::__construct( 'ArticleView', $key );
 985+ $this->view = $view;
 986+ $this->cacheable = $useParserCache;
 987+ $this->parserOptions = $parserOptions;
 988+ $this->text = $text;
 989+ }
 990+
 991+ function doWork() {
 992+ return $this->view->doViewParse( $this->text );
 993+ }
 994+
 995+ function getCachedWork() {
 996+ $parserCache = ParserCache::singleton();
 997+ $this->view->mParserOutput = $parserCache->get( $this->mArticle, $this->parserOptions );
 998+
 999+ if ( $this->mArticle->mParserOutput !== false ) {
 1000+ wfDebug( __METHOD__ . ": showing contents parsed by someone else\n" );
 1001+ $out = $this->view->getOutput();
 1002+ $out->addParserOutput( $this->view->mParserOutput );
 1003+ # Ensure that UI elements requiring revision ID have
 1004+ # the correct version information.
 1005+ $out->setRevisionId( $this->view->getPage()->getLatest() );
 1006+ return true;
 1007+ }
 1008+ return false;
 1009+ }
 1010+
 1011+ function fallback() {
 1012+ return $this->view->tryDirtyCache();
 1013+ }
 1014+
 1015+ /**
 1016+ * @param $status Status
 1017+ */
 1018+ function error( $status ) {
 1019+ $out = $this->view->getOutput();
 1020+
 1021+ $out->clearHTML(); // for release() errors
 1022+ $out->enableClientCache( false );
 1023+ $out->setRobotPolicy( 'noindex,nofollow' );
 1024+
 1025+ $errortext = $status->getWikiText( false, 'view-pool-error' );
 1026+ $out->addWikiText( '<div class="errorbox">' . $errortext . '</div>' );
 1027+
 1028+ return false;
 1029+ }
 1030+}

Status & tagging log