Some cleanup to Article::view() and related:
[lhc/web/wiklou.git] / includes / WikiPage.php
index ede63c1..9b7a02c 100644 (file)
@@ -13,28 +13,33 @@ abstract class Page {}
  * @internal documentation reviewed 15 Mar 2010
  */
 class WikiPage extends Page {
+       /**
+        * @var Title
+        */
+       public $mTitle = null;
+
        /**@{{
         * @protected
-        * Fields are public for backwards-compatibility. Use accessors.
-        * In the past, this class was part of Article.php and everything was public.
-        */
-       public $mTitle = null;               // !< Title object
-       public $mCounter = -1;               // !< Not loaded
-       public $mDataLoaded = false;         // !<
-       public $mIsRedirect = false;         // !<
-       public $mLatest = false;             // !<
-       public $mPreparedEdit = false;           // !<
-       public $mRedirectTarget = null;          // !< Title object
-       public $mLastRevision = null;            // !< Revision object
-       public $mTimestamp = '';             // !<
-       public $mTouched = '19700101000000'; // !<
-       /**@}}*/
+        */
+       public $mCounter = -1;               // !< Integer (-1 means "not loaded")
+       public $mDataLoaded = false;         // !< Boolean
+       public $mIsRedirect = false;         // !< Boolean
+       public $mLatest = false;             // !< Integer (false means "not loaded")
+       public $mPreparedEdit = false;           // !< Array
 
        /**
-        * @protected
-        * @var ParserOptions: ParserOptions object for $wgUser articles
+        * @var Title
         */
-       public $mParserOptions;
+       protected $mRedirectTarget = null;
+
+       /**
+        * @var Revision
+        */
+       protected $mLastRevision = null;
+
+       protected $mTimestamp = '';             // !< String
+       protected $mTouched = '19700101000000'; // !< String
+       /**@}}*/
 
        /**
         * Constructor and clear the article
@@ -45,17 +50,61 @@ class WikiPage extends Page {
        }
 
        /**
-        * Constructor from a page id
+        * Create a WikiPage object of the appropriate class for the given title.
         *
-        * Always override this for all subclasses (until we use PHP with LSB)
+        * @param $title Title
+        * @return WikiPage object of the appropriate type
+        */
+       public static function factory( Title $title ) {
+               $ns = $title->getNamespace();
+
+               if ( $ns == NS_MEDIA ) {
+                       throw new MWException( "NS_MEDIA is a virtual namespace; use NS_FILE." );
+               } elseif ( $ns < 0 ) {
+                       throw new MWException( "Invalid or virtual namespace $ns given." );
+               }
+
+               switch ( $ns ) {
+                       case NS_FILE:
+                               $page = new WikiFilePage( $title );
+                               break;
+                       case NS_CATEGORY:
+                               $page = new WikiCategoryPage( $title );
+                               break;
+                       default:
+                               $page = new WikiPage( $title );
+               }
+
+               return $page;
+       }
+
+       /**
+        * Constructor from a page id
         *
         * @param $id Int article ID to load
+        *
+        * @return WikiPage
         */
        public static function newFromID( $id ) {
                $t = Title::newFromID( $id );
-               # @todo FIXME: Doesn't inherit right
-               return $t == null ? null : new self( $t );
-               # return $t == null ? null : new static( $t ); // PHP 5.3
+               if ( $t ) {
+                       return self::factory( $t );
+               }
+               return null;
+       }
+
+       /**
+        * Returns overrides for action handlers.
+        * Classes listed here will be used instead of the default one when
+        * (and only when) $wgActions[$action] === true. This allows subclasses
+        * to override the default behavior.
+        *
+        * @todo: move this UI stuff somewhere else
+        *
+        * @return Array
+        */
+       public function getActionOverrides() {
+               return array();
        }
 
        /**
@@ -78,7 +127,7 @@ class WikiPage extends Page {
                $dbr = wfGetDB( DB_SLAVE );
                $row = $dbr->selectRow( 'redirect',
                        array( 'rd_namespace', 'rd_title', 'rd_fragment', 'rd_interwiki' ),
-                       array( 'rd_from' => $this->getID() ),
+                       array( 'rd_from' => $this->getId() ),
                        __METHOD__
                );
 
@@ -118,11 +167,11 @@ class WikiPage extends Page {
                $dbw = wfGetDB( DB_MASTER );
                $dbw->replace( 'redirect', array( 'rd_from' ),
                        array(
-                               'rd_from'               => $this->getID(),
-                               'rd_namespace'  => $rt->getNamespace(),
-                               'rd_title'              => $rt->getDBkey(),
-                               'rd_fragment'   => $rt->getFragment(),
-                               'rd_interwiki'  => $rt->getInterwiki(),
+                               'rd_from'      => $this->getId(),
+                               'rd_namespace' => $rt->getNamespace(),
+                               'rd_title'     => $rt->getDBkey(),
+                               'rd_fragment'  => $rt->getFragment(),
+                               'rd_interwiki' => $rt->getInterwiki(),
                        ),
                        __METHOD__
                );
@@ -156,7 +205,7 @@ class WikiPage extends Page {
                                        return $rt->getFullURL( 'rdfrom=' . urlencode( $source ) );
                                }
                        } else {
-                               if ( $rt->getNamespace() == NS_SPECIAL ) {
+                               if ( $rt->isSpecialPage() ) {
                                        // Gotta handle redirects to special pages differently:
                                        // Fill the HTTP response "Location" header and ignore
                                        // the rest of the page we're on.
@@ -234,6 +283,8 @@ class WikiPage extends Page {
        /**
         * Return the list of revision fields that should be selected to create
         * a new page.
+        *
+        * @return array
         */
        public static function selectFields() {
                return array(
@@ -277,7 +328,7 @@ class WikiPage extends Page {
         * @param $title Title object
         * @return mixed Database result resource, or false on failure
         */
-       protected function pageDataFromTitle( $dbr, $title ) {
+       public function pageDataFromTitle( $dbr, $title ) {
                return $this->pageData( $dbr, array(
                        'page_namespace' => $title->getNamespace(),
                        'page_title'     => $title->getDBkey() ) );
@@ -290,7 +341,7 @@ class WikiPage extends Page {
         * @param $id Integer
         * @return mixed Database result resource, or false on failure
         */
-       protected function pageDataFromId( $dbr, $id ) {
+       public function pageDataFromId( $dbr, $id ) {
                return $this->pageData( $dbr, array( 'page_id' => $id ) );
        }
 
@@ -298,20 +349,33 @@ class WikiPage extends Page {
         * Set the general counter, title etc data loaded from
         * some source.
         *
-        * @param $data Object|String $res->fetchObject() object or the string "fromdb" to reload
+        * @param $data Object|String One of the following:
+        *              A DB query result object or...
+        *              "fromdb" to get from a slave DB or...
+        *              "fromdbmaster" to get from the master DB
+        * @return void
         */
        public function loadPageData( $data = 'fromdb' ) {
-               if ( $data === 'fromdb' ) {
-                       $dbr = wfGetDB( DB_SLAVE );
-                       $data = $this->pageDataFromTitle( $dbr, $this->mTitle );
+               if ( $data === 'fromdbmaster' ) {
+                       $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
+               } elseif ( $data === 'fromdb' ) { // slave
+                       $data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle );
+                       # Use a "last rev inserted" timestamp key to dimish the issue of slave lag.
+                       # Note that DB also stores the master position in the session and checks it.
+                       $touched = $this->getCachedLastEditTime();
+                       if ( $touched ) { // key set
+                               if ( !$data || $touched > wfTimestamp( TS_MW, $data->page_touched ) ) {
+                                       $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
+                               }
+                       }
                }
 
                $lc = LinkCache::singleton();
 
                if ( $data ) {
-                       $lc->addGoodLinkObj( $data->page_id, $this->mTitle, $data->page_len, $data->page_is_redirect, $data->page_latest );
+                       $lc->addGoodLinkObjFromRow( $this->mTitle, $data );
 
-                       $this->mTitle->mArticleID = intval( $data->page_id );
+                       $this->mTitle->loadFromRow( $data );
 
                        # Old-fashioned restrictions
                        $this->mTitle->loadRestrictions( $data->page_restrictions );
@@ -322,7 +386,8 @@ class WikiPage extends Page {
                        $this->mLatest      = intval( $data->page_latest );
                } else {
                        $lc->addBadLinkObj( $this->mTitle );
-                       $this->mTitle->mArticleID = 0;
+
+                       $this->mTitle->loadFromRow( false );
                }
 
                $this->mDataLoaded = true;
@@ -331,7 +396,7 @@ class WikiPage extends Page {
        /**
         * @return int Page ID
         */
-       public function getID() {
+       public function getId() {
                return $this->mTitle->getArticleID();
        }
 
@@ -359,7 +424,7 @@ class WikiPage extends Page {
         */
        public function getCount() {
                if ( -1 == $this->mCounter ) {
-                       $id = $this->getID();
+                       $id = $this->getId();
 
                        if ( $id == 0 ) {
                                $this->mCounter = 0;
@@ -446,14 +511,13 @@ class WikiPage extends Page {
                        return; // already loaded
                }
 
-               # New or non-existent articles have no user information
-               $id = $this->getID();
-               if ( 0 == $id ) {
-                       return;
+               $latest = $this->getLatest();
+               if ( !$latest ) {
+                       return; // page doesn't exist or is missing page_latest info
                }
 
-               $revision = Revision::loadFromPageId( wfGetDB( DB_MASTER ), $id );
-               if ( $revision ) {
+               $revision = Revision::newFromPageId( $this->getId(), $latest );
+               if ( $revision ) { // sanity
                        $this->setLastEdit( $revision );
                }
        }
@@ -468,14 +532,14 @@ class WikiPage extends Page {
 
        /**
         * Get the latest revision
-        * @return Revision|false
+        * @return Revision|null
         */
        public function getRevision() {
                $this->loadLastEdit();
                if ( $this->mLastRevision ) {
                        return $this->mLastRevision;
                }
-               return false;
+               return null;
        }
 
        /**
@@ -486,7 +550,7 @@ class WikiPage extends Page {
         *      Revision::FOR_THIS_USER    to be displayed to $wgUser
         *      Revision::RAW              get the text regardless of permissions
         * @return String|false The text of the current revision
-        */     
+        */
        public function getText( $audience = Revision::FOR_PUBLIC ) {
                $this->loadLastEdit();
                if ( $this->mLastRevision ) {
@@ -512,7 +576,7 @@ class WikiPage extends Page {
         * @return string MW timestamp of last article revision
         */
        public function getTimestamp() {
-               // Check if the field has been filled by ParserCache::get()
+               // Check if the field has been filled by WikiPage::setTimestamp()
                if ( !$this->mTimestamp ) {
                        $this->loadLastEdit();
                }
@@ -603,7 +667,7 @@ class WikiPage extends Page {
                if ( $dbr->implicitGroupby() ) {
                        $realNameField = 'user_real_name';
                } else {
-                       $realNameField = 'FIRST(user_real_name) AS user_real_name';
+                       $realNameField = 'MIN(user_real_name) AS user_real_name';
                }
 
                $tables = array( 'revision', 'user' );
@@ -645,6 +709,7 @@ class WikiPage extends Page {
         * Should the parser cache be used?
         *
         * @param $user User The relevant user
+        * @param $oldid int
         * @return boolean
         */
        public function isParserCacheUsed( User $user, $oldid ) {
@@ -653,9 +718,8 @@ class WikiPage extends Page {
                return $wgEnableParserCache
                        && $user->getStubThreshold() == 0
                        && $this->exists()
-                       && empty( $oldid )
-                       && !$this->mTitle->isCssOrJsPage()
-                       && !$this->mTitle->isCssJsSubpage();
+                       && ( $oldid === null || $oldid === 0 || $oldid === $this->getLatest() )
+                       && $this->mTitle->isWikitextPage();
        }
 
        /**
@@ -683,7 +747,7 @@ class WikiPage extends Page {
                }
 
                if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
-                       if ( $this->getID() == 0 ) {
+                       if ( $this->getId() == 0 ) {
                                $text = false;
                        } else {
                                $text = $this->getRawText();
@@ -702,7 +766,6 @@ class WikiPage extends Page {
         *
         * @param $dbw DatabaseBase
         * @return int The newly created page_id key, or false if the title already existed
-        * @private
         */
        public function insertOn( $dbw ) {
                wfProfileIn( __METHOD__ );
@@ -738,7 +801,7 @@ class WikiPage extends Page {
         *
         * @param $dbw DatabaseBase: object
         * @param $revision Revision: For ID number, and text used to set
-                                               length and redirect status fields
+        *                  length and redirect status fields
         * @param $lastRevision Integer: if given, will not overwrite the page field
         *                      when different from the currently set value.
         *                      Giving 0 indicates the new page flag should be set
@@ -761,10 +824,11 @@ class WikiPage extends Page {
                        $conditions['page_latest'] = $lastRevision;
                }
 
+               $now = wfTimestampNow();
                $dbw->update( 'page',
                        array( /* SET */
                                'page_latest'      => $revision->getId(),
-                               'page_touched'     => $dbw->timestamp(),
+                               'page_touched'     => $dbw->timestamp( $now ),
                                'page_is_new'      => ( $lastRevision === 0 ) ? 1 : 0,
                                'page_is_redirect' => $rt !== null ? 1 : 0,
                                'page_len'         => strlen( $text ),
@@ -775,12 +839,36 @@ class WikiPage extends Page {
                $result = $dbw->affectedRows() != 0;
                if ( $result ) {
                        $this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect );
+                       $this->setCachedLastEditTime( $now );
                }
 
                wfProfileOut( __METHOD__ );
                return $result;
        }
 
+       /**
+        * Get the cached timestamp for the last time the page changed.
+        * This is only used to help handle slave lag by comparing to page_touched.
+        * @return string MW timestamp
+        */
+       protected function getCachedLastEditTime() {
+               global $wgMemc;
+               $key = wfMemcKey( 'page-lastedit', md5( $this->mTitle->getPrefixedDBkey() ) );
+               return $wgMemc->get( $key );
+       }
+
+       /**
+        * Set the cached timestamp for the last time the page changed.
+        * This is only used to help handle slave lag by comparing to page_touched.
+        * @param $timestamp string
+        * @return void
+        */
+       public function setCachedLastEditTime( $timestamp ) {
+               global $wgMemc;
+               $key = wfMemcKey( 'page-lastedit', md5( $this->mTitle->getPrefixedDBkey() ) );
+               $wgMemc->set( $key, wfTimestamp( TS_MW, $timestamp ), 60*15 );
+       }
+
        /**
         * Add row to the redirect table if this is a redirect, remove otherwise.
         *
@@ -889,9 +977,11 @@ class WikiPage extends Page {
                        if ( $section == 'new' ) {
                                # Inserting a new section
                                $subject = $summary ? wfMsgForContent( 'newsectionheaderdefaultlevel', $summary ) . "\n\n" : '';
-                               $text = strlen( trim( $oldtext ) ) > 0
+                               if ( wfRunHooks( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) {
+                                       $text = strlen( trim( $oldtext ) ) > 0
                                                ? "{$oldtext}\n\n{$subject}{$text}"
                                                : "{$subject}{$text}";
+                               }
                        } else {
                                # Replacing an existing section; roll out the big guns
                                global $wgParser;
@@ -944,7 +1034,7 @@ class WikiPage extends Page {
         *          Fill in blank summaries with generated text where possible
         *
         * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the article will be detected.
-        * If EDIT_UPDATE is specified and the article doesn't exist, the function will an
+        * If EDIT_UPDATE is specified and the article doesn't exist, the function will return an
         * edit-gone-missing error. If EDIT_NEW is specified and the article does exist, an
         * edit-already-exists error will be returned. These two conditions are also possible with
         * auto-detection due to MediaWiki's performance-optimised locking strategy.
@@ -981,7 +1071,7 @@ class WikiPage extends Page {
                $status = Status::newGood( array() );
 
                # Load $this->mTitle->getArticleID() and $this->mLatest if it's not already
-               $this->loadPageData();
+               $this->loadPageData( 'fromdbmaster' );
 
                $flags = $this->checkFlags( $flags );
 
@@ -1004,10 +1094,11 @@ class WikiPage extends Page {
 
                $oldtext = $this->getRawText(); // current revision
                $oldsize = strlen( $oldtext );
+               $oldcountable = $this->isCountable();
 
                # Provide autosummaries if one is not provided and autosummaries are enabled.
                if ( $wgUseAutomaticEditSummaries && $flags & EDIT_AUTOSUMMARY && $summary == '' ) {
-                       $summary = $this->getAutosummary( $oldtext, $text, $flags );
+                       $summary = self::getAutosummary( $oldtext, $text, $flags );
                }
 
                $editInfo = $this->prepareTextForEdit( $text, null, $user );
@@ -1027,6 +1118,17 @@ class WikiPage extends Page {
                                $userAbort = ignore_user_abort( true );
                        }
 
+                       $revision = new Revision( array(
+                               'page'       => $this->getId(),
+                               'comment'    => $summary,
+                               'minor_edit' => $isminor,
+                               'text'       => $text,
+                               'parent_id'  => $this->mLatest,
+                               'user'       => $user->getId(),
+                               'user_text'  => $user->getName(),
+                               'timestamp'  => $now
+                       ) );
+
                        $changed = ( strcmp( $text, $oldtext ) != 0 );
 
                        if ( $changed ) {
@@ -1039,17 +1141,6 @@ class WikiPage extends Page {
                                        return $status;
                                }
 
-                               $revision = new Revision( array(
-                                       'page'       => $this->getId(),
-                                       'comment'    => $summary,
-                                       'minor_edit' => $isminor,
-                                       'text'       => $text,
-                                       'parent_id'  => $this->mLatest,
-                                       'user'       => $user->getId(),
-                                       'user_text'  => $user->getName(),
-                                       'timestamp'  => $now
-                               ) );
-
                                $dbw->begin();
                                $revisionId = $revision->insertOn( $dbw );
 
@@ -1095,14 +1186,6 @@ class WikiPage extends Page {
                                        $user->incEditCount();
                                        $dbw->commit();
                                }
-                       } else {
-                               $status->warning( 'edit-no-change' );
-                               $revision = null;
-                               // Keep the same revision ID, but do some updates on it
-                               $revisionId = $this->getLatest();
-                               // Update page_touched, this is usually implicit in the page update
-                               // Other cache updates are done in onArticleEdit()
-                               $this->mTitle->invalidateCache();
                        }
 
                        if ( !$wgDBtransactions ) {
@@ -1115,11 +1198,19 @@ class WikiPage extends Page {
                                return $status;
                        }
 
-                       # Invalidate cache of this article and all pages using this article
-                       # as a template. Partly deferred.
-                       self::onArticleEdit( $this->mTitle );
                        # Update links tables, site stats, etc.
-                       $this->doEditUpdates( $text, $user, $summary, $isminor, $revisionId, $changed );
+                       $this->doEditUpdates( $revision, $user, array( 'changed' => $changed,
+                               'oldcountable' => $oldcountable ) );
+
+                       if ( !$changed ) {
+                               $status->warning( 'edit-no-change' );
+                               $revision = null;
+                               // Keep the same revision ID, but do some updates on it
+                               $revisionId = $this->getLatest();
+                               // Update page_touched, this is usually implicit in the page update
+                               // Other cache updates are done in onArticleEdit()
+                               $this->mTitle->invalidateCache();
+                       }
                } else {
                        # Create new article
                        $status->value['new'] = true;
@@ -1180,10 +1271,7 @@ class WikiPage extends Page {
                        $dbw->commit();
 
                        # Update links, etc.
-                       $this->doEditUpdates( $text, $user, $summary, $isminor, $revisionId, true, true );
-
-                       # Clear caches
-                       self::onArticleCreate( $this->mTitle );
+                       $this->doEditUpdates( $revision, $user, array( 'created' => true ) );
 
                        wfRunHooks( 'ArticleInsertComplete', array( &$this, &$user, $text, $summary,
                                $flags & EDIT_MINOR, null, null, &$flags, $revision ) );
@@ -1191,7 +1279,7 @@ class WikiPage extends Page {
 
                # Do updates right now unless deferral was requested
                if ( !( $flags & EDIT_DEFER_UPDATES ) ) {
-                       wfDoUpdates();
+                       DeferredUpdates::doUpdates();
                }
 
                // Return the new revision (or null) to the caller
@@ -1210,6 +1298,8 @@ class WikiPage extends Page {
        /**
         * Update the article's restriction field, and leave a log entry.
         *
+        * @todo: seperate the business/permission stuff out from backend code
+        *
         * @param $limit Array: set of restriction keys
         * @param $reason String
         * @param &$cascade Integer. Set to false if cascading protection isn't allowed.
@@ -1237,7 +1327,7 @@ class WikiPage extends Page {
                        return false;
                }
 
-               if ( !$this->mTitle->userCan( 'protect' ) ) {
+               if ( count( $this->mTitle->getUserPermissionsErrors( 'protect', $user ) ) ) {
                        wfDebug( "updateRestrictions failed: insufficient permissions\n" );
                        return false;
                }
@@ -1266,7 +1356,9 @@ class WikiPage extends Page {
                                # If something changed, we need to log it. Checking $aRChanged
                                # assures that "unprotecting" a page that is not protected does
                                # not log just because the expiry was "changed".
-                               if ( $aRChanged && $this->mTitle->mRestrictionsExpiry[$action] != $expiry[$action] ) {
+                               if ( $aRChanged &&
+                                       $this->mTitle->getRestrictionExpiry( $action ) != $expiry[$action] )
+                               {
                                        $changed = true;
                                }
                        }
@@ -1322,7 +1414,7 @@ class WikiPage extends Page {
 
                                        $encodedExpiry[$action] = $dbw->encodeExpiry( $expiry[$action] );
                                        if ( $restrictions != '' ) {
-                                               $protect_description .= "[$action=$restrictions] (";
+                                               $protect_description .= $wgContLang->getDirMark() . "[$action=$restrictions] (";
                                                if ( $encodedExpiry[$action] != 'infinity' ) {
                                                        $protect_description .= wfMsgForContent( 'protect-expiring',
                                                                $wgContLang->timeanddate( $expiry[$action], false, false ) ,
@@ -1439,10 +1531,6 @@ class WikiPage extends Page {
         */
        public function estimateRevisionCount() {
                $dbr = wfGetDB( DB_SLAVE );
-
-               // For an exact count...
-               // return $dbr->selectField( 'revision', 'COUNT(*)',
-               //      array( 'rev_page' => $this->getId() ), __METHOD__ );
                return $dbr->estimateRowCount( 'revision', '*',
                        array( 'rev_page' => $this->getId() ), __METHOD__ );
        }
@@ -1504,7 +1592,7 @@ class WikiPage extends Page {
         * Deletes the article with database consistency, writes logs, purges caches
         *
         * @param $reason string delete reason for deletion log
-        * @param suppress bitfield
+        * @param $suppress bitfield
         *      Revision::DELETED_TEXT
         *      Revision::DELETED_COMMENT
         *      Revision::DELETED_USER
@@ -1518,7 +1606,7 @@ class WikiPage extends Page {
        public function doDeleteArticle(
                $reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
        ) {
-               global $wgDeferredUpdateList, $wgUseTrackbacks, $wgUser;
+               global $wgUseTrackbacks, $wgUser;
                $user = is_null( $user ) ? $wgUser : $user;
 
                wfDebug( __METHOD__ . "\n" );
@@ -1534,8 +1622,9 @@ class WikiPage extends Page {
                        return false;
                }
 
-               $u = new SiteStatsUpdate( 0, 1, - (int)$this->isCountable(), -1 );
-               array_push( $wgDeferredUpdateList, $u );
+               DeferredUpdates::addUpdate(
+                       new SiteStatsUpdate( 0, 1, - (int)$this->isCountable(), -1 )
+               );
 
                // Bitfields to further suppress the content
                if ( $suppress ) {
@@ -1570,12 +1659,14 @@ class WikiPage extends Page {
                                'ar_timestamp'  => 'rev_timestamp',
                                'ar_minor_edit' => 'rev_minor_edit',
                                'ar_rev_id'     => 'rev_id',
+                               'ar_parent_id'  => 'rev_parent_id',
                                'ar_text_id'    => 'rev_text_id',
                                'ar_text'       => '\'\'', // Be explicit to appease
                                'ar_flags'      => '\'\'', // MySQL's "strict mode"...
                                'ar_len'        => 'rev_len',
                                'ar_page_id'    => 'page_id',
-                               'ar_deleted'    => $bitfield
+                               'ar_deleted'    => $bitfield,
+                               'ar_sha1'       => 'rev_sha1'
                        ), array(
                                'page_id' => $id,
                                'page_id = rev_page'
@@ -1608,18 +1699,20 @@ class WikiPage extends Page {
                if ( !$dbw->cascadingDeletes() ) {
                        $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
 
-                       if ( $wgUseTrackbacks )
+                       if ( $wgUseTrackbacks ) {
                                $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), __METHOD__ );
+                       }
 
                        # Delete outgoing links
-                       $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) );
-                       $dbw->delete( 'imagelinks', array( 'il_from' => $id ) );
-                       $dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
-                       $dbw->delete( 'templatelinks', array( 'tl_from' => $id ) );
-                       $dbw->delete( 'externallinks', array( 'el_from' => $id ) );
-                       $dbw->delete( 'langlinks', array( 'll_from' => $id ) );
-                       $dbw->delete( 'iwlinks', array( 'iwl_from' => $id ) );
-                       $dbw->delete( 'redirect', array( 'rd_from' => $id ) );
+                       $dbw->delete( 'pagelinks', array( 'pl_from' => $id ), __METHOD__ );
+                       $dbw->delete( 'imagelinks', array( 'il_from' => $id ), __METHOD__ );
+                       $dbw->delete( 'categorylinks', array( 'cl_from' => $id ), __METHOD__ );
+                       $dbw->delete( 'templatelinks', array( 'tl_from' => $id ), __METHOD__ );
+                       $dbw->delete( 'externallinks', array( 'el_from' => $id ), __METHOD__ );
+                       $dbw->delete( 'langlinks', array( 'll_from' => $id ), __METHOD__ );
+                       $dbw->delete( 'iwlinks', array( 'iwl_from' => $id ), __METHOD__ );
+                       $dbw->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ );
+                       $dbw->delete( 'page_props', array( 'pp_page' => $id ), __METHOD__ );
                }
 
                # If using cleanup triggers, we can skip some manual deletes
@@ -1643,10 +1736,13 @@ class WikiPage extends Page {
 
                # Log the deletion, if the page was suppressed, log it at Oversight instead
                $logtype = $suppress ? 'suppress' : 'delete';
-               $log = new LogPage( $logtype );
 
-               # Make sure logging got through
-               $log->addEntry( 'delete', $this->mTitle, $reason, array() );
+               $logEntry = new ManualLogEntry( $logtype, 'delete' );
+               $logEntry->setPerformer( $user );
+               $logEntry->setTarget( $this->mTitle );
+               $logEntry->setComment( $reason );
+               $logid = $logEntry->insert();
+               $logEntry->publish( $logid );
 
                if ( $commit ) {
                        $dbw->commit();
@@ -1662,6 +1758,8 @@ class WikiPage extends Page {
         * roll back to, e.g. user is the sole contributor. This function
         * performs permissions checks on $user, then calls commitRollback()
         * to do the dirty work
+        * 
+        * @todo: seperate the business/permission stuff out from backend code
         *
         * @param $fromP String: Name of the user whose edits to rollback.
         * @param $summary String: Custom summary. Set to default summary if empty.
@@ -1679,11 +1777,8 @@ class WikiPage extends Page {
         * OutputPage::showPermissionsErrorPage().
         */
        public function doRollback(
-               $fromP, $summary, $token, $bot, &$resultDetails, User $user = null
+               $fromP, $summary, $token, $bot, &$resultDetails, User $user
        ) {
-               global $wgUser;
-               $user = is_null( $user ) ? $wgUser : $user;
-
                $resultDetails = null;
 
                # Check permissions
@@ -1704,7 +1799,7 @@ class WikiPage extends Page {
                        return $errors;
                }
 
-               return $this->commitRollback( $user, $fromP, $summary, $bot, $resultDetails );
+               return $this->commitRollback( $fromP, $summary, $bot, $resultDetails, $user );
        }
 
        /**
@@ -1712,7 +1807,7 @@ class WikiPage extends Page {
         * and return value documentation
         *
         * NOTE: This function does NOT check ANY permissions, it just commits the
-        * rollback to the DB Therefore, you should only call this function direct-
+        * rollback to the DB. Therefore, you should only call this function direct-
         * ly if you want to use custom permissions checks. If you don't, use
         * doRollback() instead.
         * @param $fromP String: Name of the user whose edits to rollback.
@@ -1722,9 +1817,8 @@ class WikiPage extends Page {
         * @param $resultDetails Array: contains result-specific array of additional values
         * @param $guser User The user performing the rollback
         */
-       public function commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser = null ) {
-               global $wgUseRCPatrol, $wgUser, $wgContLang;
-               $guser = is_null( $guser ) ? $wgUser : $guser;
+       public function commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser ) {
+               global $wgUseRCPatrol, $wgContLang;
 
                $dbw = wfGetDB( DB_MASTER );
 
@@ -1846,15 +1940,15 @@ class WikiPage extends Page {
         * @param $user User The relevant user
         */
        public function doViewUpdates( User $user ) {
-               global $wgDeferredUpdateList, $wgDisableCounters;
+               global $wgDisableCounters;
                if ( wfReadOnly() ) {
                        return;
                }
 
                # Don't update page view counters on views from bot users (bug 14044)
-               if ( !$wgDisableCounters && !$user->isAllowed( 'bot' ) && $this->getID() ) {
-                       $wgDeferredUpdateList[] = new ViewCountUpdate( $this->getID() );
-                       $wgDeferredUpdateList[] = new SiteStatsUpdate( 1, 0, 0 );
+               if ( !$wgDisableCounters && !$user->isAllowed( 'bot' ) && $this->getId() ) {
+                       DeferredUpdates::addUpdate( new ViewCountUpdate( $this->getId() ) );
+                       DeferredUpdates::addUpdate( new SiteStatsUpdate( 1, 0, 0 ) );
                }
 
                # Update newtalk / watchlist notification status
@@ -1866,7 +1960,7 @@ class WikiPage extends Page {
         * Returns a stdclass with source, pst and output members
         */
        public function prepareTextForEdit( $text, $revid = null, User $user = null ) {
-               global $wgParser, $wgUser;
+               global $wgParser, $wgContLang, $wgUser;
                $user = is_null( $user ) ? $wgUser : $user;
                // @TODO fixme: check $user->getId() here???
                if ( $this->mPreparedEdit
@@ -1877,14 +1971,14 @@ class WikiPage extends Page {
                        return $this->mPreparedEdit;
                }
 
-               $popts = ParserOptions::newFromUser( $user );
+               $popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
                wfRunHooks( 'ArticlePrepareTextForEdit', array( $this, $popts ) );
 
                $edit = (object)array();
                $edit->revid = $revid;
                $edit->newText = $text;
                $edit->pst = $this->preSaveTransform( $text, $user, $popts );
-               $edit->popts = $this->getParserOptions( true );
+               $edit->popts = $this->makeParserOptions( 'canonical' );
                $edit->output = $wgParser->parse( $edit->pst, $this->mTitle, $edit->popts, true, true, $revid );
                $edit->oldText = $this->getRawText();
 
@@ -1900,26 +1994,29 @@ class WikiPage extends Page {
         * Every 100th edit, prune the recent changes table.
         *
         * @private
-        * @param $text String: New text of the article
-        * @param $user User object: User doing the edit
-        * @param $summary String: Edit summary
-        * @param $minoredit Boolean: Minor edit
-        * @param $newid Integer: rev_id value of the new revision
-        * @param $changed Boolean: Whether or not the content actually changed
-        * @param $created Boolean: Whether the edit created the page
-        */
-       public function doEditUpdates(
-               $text, $user, $summary, $minoredit, $newid, $changed = true, $created = false
-       ) {
-               global $wgDeferredUpdateList, $wgEnableParserCache;
+        * @param $revision Revision object
+        * @param $user User object that did the revision
+        * @param $options Array of options, following indexes are used:
+        * - changed: boolean, whether the revision changed the content (default true)
+        * - created: boolean, whether the revision created the page (default false)
+        * - oldcountable: boolean or null (default null):
+        *   - boolean: whether the page was counted as an article before that
+        *     revision, only used in changed is true and created is false
+        *   - null: don't change the article count
+        */
+       public function doEditUpdates( Revision $revision, User $user, array $options = array() ) {
+               global $wgEnableParserCache;
 
                wfProfileIn( __METHOD__ );
 
+               $options += array( 'changed' => true, 'created' => false, 'oldcountable' => null );
+               $text = $revision->getText();
+
                # Parse the text
                # Be careful not to double-PST: $text is usually already PST-ed once
                if ( !$this->mPreparedEdit || $this->mPreparedEdit->output->getFlag( 'vary-revision' ) ) {
                        wfDebug( __METHOD__ . ": No prepared edit or vary-revision is set...\n" );
-                       $editInfo = $this->prepareTextForEdit( $text, $newid, $user );
+                       $editInfo = $this->prepareTextForEdit( $text, $revision->getId(), $user );
                } else {
                        wfDebug( __METHOD__ . ": No vary-revision, using prepared edit...\n" );
                        $editInfo = $this->mPreparedEdit;
@@ -1935,7 +2032,7 @@ class WikiPage extends Page {
                $u = new LinksUpdate( $this->mTitle, $editInfo->output );
                $u->doUpdate();
 
-               wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $changed ) );
+               wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
 
                if ( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
                        if ( 0 == mt_rand( 0, 99 ) ) {
@@ -1953,7 +2050,7 @@ class WikiPage extends Page {
                        }
                }
 
-               $id = $this->getID();
+               $id = $this->getId();
                $title = $this->mTitle->getPrefixedDBkey();
                $shortTitle = $this->mTitle->getDBkey();
 
@@ -1962,26 +2059,30 @@ class WikiPage extends Page {
                        return;
                }
 
-               if ( !$changed ) {
+               if ( !$options['changed'] ) {
                        $good = 0;
                        $total = 0;
-               } elseif ( $created ) {
+               } elseif ( $options['created'] ) {
                        $good = (int)$this->isCountable( $editInfo );
                        $total = 1;
+               } elseif ( $options['oldcountable'] !== null ) {
+                       $good = (int)$this->isCountable( $editInfo ) - (int)$options['oldcountable'];
+                       $total = 0;
                } else {
-                       $good = (int)$this->isCountable( $editInfo ) - (int)$this->isCountable();
+                       $good = 0;
                        $total = 0;
                }
 
-               $wgDeferredUpdateList[] = new SiteStatsUpdate( 0, 1, $good, $total );
-               $wgDeferredUpdateList[] = new SearchUpdate( $id, $title, $text );
+               DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 1, $good, $total ) );
+               DeferredUpdates::addUpdate( new SearchUpdate( $id, $title, $text ) );
 
-               # If this is another user's talk page, update newtalk
-               # Don't do this if $changed = false otherwise some idiot can null-edit a
-               # load of user talk pages and piss people off, nor if it's a minor edit
-               # by a properly-flagged bot.
-               if ( $this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $user->getTitleKey() && $changed
-                       && !( $minoredit && $user->isAllowed( 'nominornewtalk' ) )
+               # If this is another user's talk page, update newtalk.
+               # Don't do this if $options['changed'] = false (null-edits) nor if
+               # it's a minor edit and the user doesn't want notifications for those.
+               if ( $options['changed']
+                       && $this->mTitle->getNamespace() == NS_USER_TALK
+                       && $shortTitle != $user->getTitleKey()
+                       && !( $revision->isMinor() && $user->isAllowed( 'nominornewtalk' ) )
                ) {
                        if ( wfRunHooks( 'ArticleEditUpdateNewTalk', array( &$this ) ) ) {
                                $other = User::newFromName( $shortTitle, false );
@@ -2002,6 +2103,12 @@ class WikiPage extends Page {
                        MessageCache::singleton()->replace( $shortTitle, $text );
                }
 
+               if( $options['created'] ) {
+                       self::onArticleCreate( $this->mTitle );
+               } else {
+                       self::onArticleEdit( $this->mTitle );
+               }
+
                wfProfileOut( __METHOD__ );
        }
 
@@ -2013,12 +2120,11 @@ class WikiPage extends Page {
         * @todo This is a shitty interface function. Kill it and replace the
         * other shitty functions like doEditUpdates and such so it's not needed
         * anymore.
-        * @deprecated since 1.19, use doEditUpdates()
+        * @deprecated since 1.18, use doEditUpdates()
         */
        public function createUpdates( $rev ) {
                global $wgUser;
-               $this->doEditUpdates( $rev->getText(), $wgUser, $rev->getComment(),
-                       $rev->isMinor(), $rev->getId(), true, true );
+               $this->doEditUpdates( $rev, $wgUser, array( 'created' => true ) );
        }
 
        /**
@@ -2051,7 +2157,6 @@ class WikiPage extends Page {
                if ( !$this->mDataLoaded ) {
                        $this->loadPageData();
                }
-
                return !$this->mIsRedirect;
        }
 
@@ -2063,7 +2168,6 @@ class WikiPage extends Page {
                if ( !$this->mDataLoaded ) {
                        $this->loadPageData();
                }
-
                return $this->mTouched;
        }
 
@@ -2075,7 +2179,6 @@ class WikiPage extends Page {
                if ( !$this->mDataLoaded ) {
                        $this->loadPageData();
                }
-
                return (int)$this->mLatest;
        }
 
@@ -2184,13 +2287,12 @@ class WikiPage extends Page {
         * @todo:  verify that $title is always a Title object (and never false or null), add Title hint to parameter $title
         */
        public static function onArticleEdit( $title ) {
-               global $wgDeferredUpdateList;
-
                // Invalidate caches of articles which include this page
-               $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'templatelinks' );
+               DeferredUpdates::addHTMLCacheUpdate( $title, 'templatelinks' );
+
 
                // Invalidate the caches of all pages which redirect here
-               $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'redirect' );
+               DeferredUpdates::addHTMLCacheUpdate( $title, 'redirect' );
 
                # Purge squid for this page only
                $title->purgeSquid();
@@ -2277,7 +2379,13 @@ class WikiPage extends Page {
                $rt = Title::newFromRedirect( $newtext );
 
                if ( is_object( $rt ) && ( !is_object( $ot ) || !$rt->equals( $ot ) || $ot->getFragment() != $rt->getFragment() ) ) {
-                       return wfMsgForContent( 'autoredircomment', $rt->getFullText() );
+                       $truncatedtext = $wgContLang->truncate(
+                               str_replace( "\n", ' ', $newtext ),
+                               max( 0, 250
+                                       - strlen( wfMsgForContent( 'autoredircomment' ) )
+                                       - strlen( $rt->getFullText() )
+                               ) );
+                       return wfMsgForContent( 'autoredircomment', $rt->getFullText(), $truncatedtext );
                }
 
                # New page autosummaries
@@ -2310,36 +2418,111 @@ class WikiPage extends Page {
        }
 
        /**
-        * Get parser options suitable for rendering the primary article wikitext
-        * @param $canonical boolean Determines that the generated options must not depend on user preferences (see bug 14404)
-        * @return mixed ParserOptions object or boolean false
+        * Auto-generates a deletion reason
+        *
+        * @param &$hasHistory Boolean: whether the page has a history
+        * @return mixed String containing deletion reason or empty string, or boolean false
+        *    if no revision occurred
         */
-       public function getParserOptions( $canonical = false ) {
-               global $wgUser, $wgLanguageCode;
+       public function getAutoDeleteReason( &$hasHistory ) {
+               global $wgContLang;
+
+               $dbw = wfGetDB( DB_MASTER );
+               // Get the last revision
+               $rev = Revision::newFromTitle( $this->getTitle() );
+
+               if ( is_null( $rev ) ) {
+                       return false;
+               }
+
+               // Get the article's contents
+               $contents = $rev->getText();
+               $blank = false;
+
+               // If the page is blank, use the text from the previous revision,
+               // which can only be blank if there's a move/import/protect dummy revision involved
+               if ( $contents == '' ) {
+                       $prev = $rev->getPrevious();
+
+                       if ( $prev )    {
+                               $contents = $prev->getText();
+                               $blank = true;
+                       }
+               }
+
+               // Find out if there was only one contributor
+               // Only scan the last 20 revisions
+               $res = $dbw->select( 'revision', 'rev_user_text',
+                       array( 'rev_page' => $this->getID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ),
+                       __METHOD__,
+                       array( 'LIMIT' => 20 )
+               );
+
+               if ( $res === false ) {
+                       // This page has no revisions, which is very weird
+                       return false;
+               }
 
-               if ( !$this->mParserOptions || $canonical ) {
-                       $user = !$canonical ? $wgUser : new User;
-                       $parserOptions = new ParserOptions( $user );
-                       $parserOptions->setTidy( true );
-                       $parserOptions->enableLimitReport();
+               $hasHistory = ( $res->numRows() > 1 );
+               $row = $dbw->fetchObject( $res );
 
-                       if ( $canonical ) {
-                               $parserOptions->setUserLang( $wgLanguageCode ); # Must be set explicitely
-                               return $parserOptions;
+               if ( $row ) { // $row is false if the only contributor is hidden
+                       $onlyAuthor = $row->rev_user_text;
+                       // Try to find a second contributor
+                       foreach ( $res as $row ) {
+                               if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999
+                                       $onlyAuthor = false;
+                                       break;
+                               }
                        }
-                       $this->mParserOptions = $parserOptions;
+               } else {
+                       $onlyAuthor = false;
                }
-               // Clone to allow modifications of the return value without affecting cache
-               return clone $this->mParserOptions;
+
+               // Generate the summary with a '$1' placeholder
+               if ( $blank ) {
+                       // The current revision is blank and the one before is also
+                       // blank. It's just not our lucky day
+                       $reason = wfMsgForContent( 'exbeforeblank', '$1' );
+               } else {
+                       if ( $onlyAuthor ) {
+                               $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
+                       } else {
+                               $reason = wfMsgForContent( 'excontent', '$1' );
+                       }
+               }
+
+               if ( $reason == '-' ) {
+                       // Allow these UI messages to be blanked out cleanly
+                       return '';
+               }
+
+               // Replace newlines with spaces to prevent uglyness
+               $contents = preg_replace( "/[\n\r]/", ' ', $contents );
+               // Calculate the maximum amount of chars to get
+               // Max content length = max comment length - length of the comment (excl. $1)
+               $maxLength = 255 - ( strlen( $reason ) - 2 );
+               $contents = $wgContLang->truncate( $contents, $maxLength );
+               // Remove possible unfinished links
+               $contents = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $contents );
+               // Now replace the '$1' placeholder
+               $reason = str_replace( '$1', $contents, $reason );
+
+               return $reason;
        }
 
        /**
        * Get parser options suitable for rendering the primary article wikitext
-       * @param User $user
+       * @param User|string $user User object or 'canonical'
        * @return ParserOptions
        */
-       public function makeParserOptions( User $user ) {
-               $options = ParserOptions::newFromUser( $user );
+       public function makeParserOptions( $user ) {
+               global $wgContLang;
+               if ( $user instanceof User ) { // settings per user (even anons)
+                       $options = ParserOptions::newFromUser( $user );
+               } else { // canonical settings
+                       $options = ParserOptions::newFromUserAndLang( new User, $wgContLang );
+               }
                $options->enableLimitReport(); // show inclusion/loop reports
                $options->setTidy( true ); // fix bad HTML
                return $options;
@@ -2409,83 +2592,75 @@ class WikiPage extends Page {
        }
 
        /**
-        * Lightweight method to get the parser output for a page, checking the parser cache
-        * and so on. Doesn't consider most of the stuff that WikiPage::view is forced to
-        * consider, so it's not appropriate to use there.
-        *
-        * @since 1.16 (r52326) for LiquidThreads
+        * Updates cascading protections
         *
-        * @param $oldid mixed integer Revision ID or null
-        * @param $user User The relevant user
-        * @return ParserOutput or false if the given revsion ID is not found
+        * @param $parserOutput ParserOutput object for the current version
         */
-       public function getParserOutput( $oldid = null, User $user = null ) {
-               global $wgEnableParserCache, $wgUser;
-               $user = is_null( $user ) ? $wgUser : $user;
+       public function doCascadeProtectionUpdates( ParserOutput $parserOutput ) {
+               if ( wfReadOnly() || !$this->mTitle->areRestrictionsCascading() ) {
+                       return;
+               }
 
-               // Should the parser cache be used?
-               $useParserCache = $wgEnableParserCache &&
-                       $user->getStubThreshold() == 0 &&
-                       $this->exists() &&
-                       $oldid === null;
+               // templatelinks table may have become out of sync,
+               // especially if using variable-based transclusions.
+               // For paranoia, check if things have changed and if
+               // so apply updates to the database. This will ensure
+               // that cascaded protections apply as soon as the changes
+               // are visible.
 
-               wfDebug( __METHOD__ . ': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
+               # Get templates from templatelinks
+               $id = $this->mTitle->getArticleID();
 
-               if ( $user->getStubThreshold() ) {
-                       wfIncrStats( 'pcache_miss_stub' );
-               }
+               $tlTemplates = array();
 
-               if ( $useParserCache ) {
-                       $parserOutput = ParserCache::singleton()->get( $this, $this->getParserOptions() );
-                       if ( $parserOutput !== false ) {
-                               return $parserOutput;
-                       }
+               $dbr = wfGetDB( DB_SLAVE );
+               $res = $dbr->select( array( 'templatelinks' ),
+                       array( 'tl_namespace', 'tl_title' ),
+                       array( 'tl_from' => $id ),
+                       __METHOD__
+               );
+
+               foreach ( $res as $row ) {
+                       $tlTemplates["{$row->tl_namespace}:{$row->tl_title}"] = true;
                }
 
-               // Cache miss; parse and output it.
-               if ( $oldid === null ) {
-                       $text = $this->getRawText();
-               } else {
-                       $rev = Revision::newFromTitle( $this->getTitle(), $oldid );
-                       if ( $rev === null ) {
-                               return false;
+               # Get templates from parser output.
+               $poTemplates = array();
+               foreach ( $parserOutput->getTemplates() as $ns => $templates ) {
+                       foreach ( $templates as $dbk => $id ) {
+                               $poTemplates["$ns:$dbk"] = true;
                        }
-                       $text = $rev->getText();
                }
 
-               return $this->getOutputFromWikitext( $text, $useParserCache );
+               # Get the diff
+               $templates_diff = array_diff_key( $poTemplates, $tlTemplates );
+
+               if ( count( $templates_diff ) > 0 ) {
+                       # Whee, link updates time.
+                       $u = new LinksUpdate( $this->mTitle, $parserOutput, false );
+                       $u->doUpdate();
+               }
        }
 
-       /*
-       * @deprecated since 1.19
-       */
+       /**
+        * @deprecated since 1.18
+        */
        public function quickEdit( $text, $comment = '', $minor = 0 ) {
                global $wgUser;
                return $this->doQuickEdit( $text, $wgUser, $comment, $minor );
        }
 
-       /*
-       * @deprecated since 1.19
-       */
-       public function editUpdates(
-               $text, $summary, $minoredit, $timestamp_of_pagechange, $newid,
-               $changed = true, User $user = null, $created = false
-       ) {
-               global $wgUser;
-               return $this->doEditUpdates( $text, $wgUser, $summary, $minoredit, $newid, $changed, $created );
-       }
-
-       /*
-       * @deprecated since 1.19
-       */
+       /**
+        * @deprecated since 1.18
+        */
        public function viewUpdates() {
                global $wgUser;
                return $this->doViewUpdates( $wgUser );
        }
 
-       /*
-       * @deprecated since 1.19
-       */
+       /**
+        * @deprecated since 1.18
+        */
        public function useParserCache( $oldid ) {
                global $wgUser;
                return $this->isParserCacheUsed( $wgUser, $oldid );