docu cleanup; marked contenthandler stuff as @since 1.WD
[lhc/web/wiklou.git] / includes / WikiPage.php
index f880d05..658d7fa 100644 (file)
@@ -13,6 +13,30 @@ abstract class Page {}
  * @internal documentation reviewed 15 Mar 2010
  */
 class WikiPage extends Page {
+       // doDeleteArticleReal() return values. Values less than zero indicate fatal errors,
+       // values greater than zero indicate that there were problems not resulting in page
+       // not being deleted
+
+       /**
+        * Delete operation aborted by hook
+        */
+       const DELETE_HOOK_ABORTED = -1;
+
+       /**
+        * Deletion successful
+        */
+       const DELETE_SUCCESS = 0;
+
+       /**
+        * Page not found
+        */
+       const DELETE_NO_PAGE = 1;
+
+       /**
+        * No revisions found to delete
+        */
+       const DELETE_NO_REVISIONS = 2;
+
        /**
         * @var Title
         */
@@ -94,7 +118,7 @@ class WikiPage extends Page {
         *
         * @param $id Int article ID to load
         *
-        * @return WikiPage
+        * @return WikiPage|null
         */
        public static function newFromID( $id ) {
                $t = Title::newFromID( $id );
@@ -115,9 +139,23 @@ class WikiPage extends Page {
         * @return Array
         */
        public function getActionOverrides() {
-               return array();
+        $content_handler = $this->getContentHandler();
+               return $content_handler->getActionOverrides();
        }
 
+    /**
+     * Returns the ContentHandler instance to be used to deal with the content of this WikiPage.
+     *
+     * Shorthand for ContentHandler::getForModelName( $this->getContentModelName() );
+     *
+     * @return ContentHandler
+     *
+     * @since 1.WD
+     */
+    public function getContentHandler() {
+        return ContentHandler::getForModelName( $this->getContentModelName() );
+    }
+
        /**
         * Get the title object of the article
         * @return Title object of this page
@@ -308,6 +346,25 @@ class WikiPage extends Page {
         else return $content->isRedirect();
        }
 
+    /**
+     * Returns the page's content model name. Will use the revisions actual content model if the page exists,
+     * and the page's default if the page doesn't exist yet.
+     *
+     * @return int
+     *
+     * @since 1.WD
+     */
+    public function getContentModelName() {
+        if ( $this->exists() ) {
+            # look at the revision's actual content model
+            $rev = $this->getRevision();
+            return $rev->getContentModelName();
+        } else {
+            # use the default model for this page
+            return $this->mTitle->getContentModelName();
+        }
+    }
+
        /**
         * Loads page_touched and returns a value indicating if it should be used
         * @return boolean true if not a redirect
@@ -389,13 +446,15 @@ class WikiPage extends Page {
      *      Revision::FOR_THIS_USER    to be displayed to $wgUser
      *      Revision::RAW              get the text regardless of permissions
      * @return Content|null The content of the current revision
+     *
+     * @since 1.WD
      */
     public function getContent( $audience = Revision::FOR_PUBLIC ) {
         $this->loadLastEdit();
         if ( $this->mLastRevision ) {
             return $this->mLastRevision->getContent( $audience );
         }
-        return false;
+        return null;
     }
 
        /**
@@ -406,10 +465,11 @@ 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
-     * @deprecated as of 1.20, getContent() should be used instead.
+     * @deprecated as of 1.WD, getContent() should be used instead.
         */
-       public function getText( $audience = Revision::FOR_PUBLIC ) { #FIXME: deprecated, replace usage!
-        wfDeprecated( __METHOD__, '1.20' );
+       public function getText( $audience = Revision::FOR_PUBLIC ) { #@todo: deprecated, replace usage!
+        wfDeprecated( __METHOD__, '1.WD' );
+
                $this->loadLastEdit();
                if ( $this->mLastRevision ) {
                        return $this->mLastRevision->getText( $audience );
@@ -420,9 +480,12 @@ class WikiPage extends Page {
        /**
         * Get the text of the current revision. No side-effects...
         *
-        * @return String|false The text of the current revision
+        * @return String|bool The text of the current revision. False on failure
+        * @deprecated as of 1.WD, getContent() should be used instead.
         */
-       public function getRawText() { #FIXME: deprecated, replace usage!
+       public function getRawText() { #@todo: deprecated, replace usage!
+               wfDeprecated( __METHOD__, '1.WD' );
+
                return $this->getText( Revision::RAW );
        }
 
@@ -430,6 +493,8 @@ class WikiPage extends Page {
      * Get the content of the current revision. No side-effects...
      *
      * @return Contet|false The text of the current revision
+     *
+     * @since 1.WD
      */
     protected function getNativeData() { #FIXME: examine all uses carefully! caller must be aware of content model!
         $content = $this->getContent( Revision::RAW );
@@ -446,6 +511,7 @@ class WikiPage extends Page {
                if ( !$this->mTimestamp ) {
                        $this->loadLastEdit();
                }
+               
                return wfTimestamp( TS_MW, $this->mTimestamp );
        }
 
@@ -559,8 +625,7 @@ class WikiPage extends Page {
                }
 
         if ( $editInfo ) {
-            $content = ContentHandler::makeContent( $editInfo->pst, $this->mTitle );
-            # TODO: take model and format from edit info!
+            $content = $editInfo->pstContent;
         } else {
             $content = $this->getContent();
         }
@@ -829,7 +894,7 @@ class WikiPage extends Page {
                        && $parserOptions->getStubThreshold() == 0
                        && $this->mTitle->exists()
                        && ( $oldid === null || $oldid === 0 || $oldid === $this->getLatest() )
-                       && $this->mTitle->isWikitextPage(); #FIXME: ask ContentHandler if cachable!
+                       && $this->getContentHandler()->isParserCacheSupported();
        }
 
        /**
@@ -840,9 +905,11 @@ class WikiPage extends Page {
         * @param $parserOptions ParserOptions to use for the parse operation
         * @param $oldid Revision ID to get the text from, passing null or 0 will
         *               get the current revision (default value)
+        * @param $context IContextSource context for parsing
+        *
         * @return ParserOutput or false if the revision was not found
         */
-       public function getParserOutput( ParserOptions $parserOptions, $oldid = null ) {
+       public function getParserOutput( ParserOptions $parserOptions, $oldid = null, IContextSource $context = null ) {
                wfProfileIn( __METHOD__ );
 
                $useParserCache = $this->isParserCacheUsed( $parserOptions, $oldid );
@@ -863,7 +930,7 @@ class WikiPage extends Page {
                        $oldid = $this->getLatest();
                }
 
-               $pool = new PoolWorkArticleView( $this, $parserOptions, $oldid, $useParserCache );
+               $pool = new PoolWorkArticleView( $this, $parserOptions, $oldid, $useParserCache, null, $context );
                $pool->execute();
 
                wfProfileOut( __METHOD__ );
@@ -893,6 +960,7 @@ class WikiPage extends Page {
 
        /**
         * Perform the actions of a page purging
+        * @return bool
         */
        public function doPurge() {
                global $wgUseSquid;
@@ -908,7 +976,7 @@ class WikiPage extends Page {
                if ( $wgUseSquid ) {
                        // Commit the transaction before the purge is sent
                        $dbw = wfGetDB( DB_MASTER );
-                       $dbw->commit();
+                       $dbw->commit( __METHOD__ );
 
                        // Send purge
                        $update = SquidUpdate::newSimplePurge( $this->mTitle );
@@ -1003,6 +1071,7 @@ class WikiPage extends Page {
                                'page_is_new'      => ( $lastRevision === 0 ) ? 1 : 0,
                                'page_is_redirect' => $rt !== null ? 1 : 0,
                                'page_len'         => $len,
+                               'page_content_model' => $revision->getContentModelName(),
                        ),
                        $conditions,
                        __METHOD__ );
@@ -1028,7 +1097,7 @@ class WikiPage extends Page {
         * @param $dbw DatabaseBase
         * @param $redirectTitle Title object pointing to the redirect target,
         *                       or NULL if this is not a redirect
-        * @param $lastRevIsRedirect If given, will optimize adding and
+        * @param $lastRevIsRedirect null|bool If given, will optimize adding and
         *                           removing rows in redirect table.
         * @return bool true on success, false on failure
         * @private
@@ -1064,7 +1133,7 @@ class WikiPage extends Page {
         * If the given revision is newer than the currently set page_latest,
         * update the page record. Otherwise, do nothing.
         *
-        * @param $dbw Database object
+        * @param $dbw DatabaseBase object
         * @param $revision Revision object
         * @return mixed
         */
@@ -1105,35 +1174,42 @@ class WikiPage extends Page {
         * @param $undo Revision
         * @param $undoafter Revision Must be an earlier revision than $undo
         * @return mixed string on success, false on failure
-     * @deprecated since 1.20: use ContentHandler::getUndoContent() instead.
+        * @deprecated since 1.WD: use ContentHandler::getUndoContent() instead.
         */
        public function getUndoText( Revision $undo, Revision $undoafter = null ) { #FIXME: replace usages.
-        $this->loadLastEdit();
+               wfDeprecated( __METHOD__, '1.WD' );
 
-        if ( $this->mLastRevision ) {
-            $handler = ContentHandler::getForTitle( $this->getTitle() );
-            $undone = $handler->getUndoContent( $this->mLastRevision, $undo, $undoafter );
+               $this->loadLastEdit();
 
-            if ( !$undone ) {
-                return false;
-            } else {
-                return ContentHandler::getContentText( $undone );
-            }
-        }
+               if ( $this->mLastRevision ) {
+                       if ( is_null( $undoafter ) ) {
+                               $undoafter = $undo->getPrevious();
+                       }
 
-        return false;
+                       $handler = $this->getContentHandler();
+                       $undone = $handler->getUndoContent( $this->mLastRevision, $undo, $undoafter );
+
+                       if ( !$undone ) {
+                               return false;
+                       } else {
+                               return ContentHandler::getContentText( $undone );
+                       }
+               }
+
+               return false;
        }
 
        /**
-        * @param $section empty/null/false or a section number (0, 1, 2, T1, T2...)
+        * @param $section null|bool|int or a section number (0, 1, 2, T1, T2...)
         * @param $text String: new text of the section
         * @param $sectionTitle String: new section's subject, only if $section is 'new'
         * @param $edittime String: revision timestamp or null to use the current revision
-        * @return Content new complete article content, or null if error
-     * @deprected since 1.20, use replaceSectionContent() instead
+        * @return String new complete article text, or null if error
+        *
+        * @deprecated since 1.WD, use replaceSectionContent() instead
         */
        public function replaceSection( $section, $text, $sectionTitle = '', $edittime = null ) { #FIXME: use replaceSectionContent() instead!
-        wfDeprecated( __METHOD__, '1.20' );
+        wfDeprecated( __METHOD__, '1.WD' );
 
         $sectionContent = ContentHandler::makeContent( $text, $this->getTitle() ); #XXX: could make section title, but that's not required.
 
@@ -1142,7 +1218,17 @@ class WikiPage extends Page {
                return ContentHandler::getContentText( $newContent ); #XXX: unclear what will happen for non-wikitext!
        }
 
-    public function replaceSectionContent( $section, $sectionContent, $sectionTitle = '', $edittime = null ) {
+       /**
+        * @param $section null|bool|int or a section number (0, 1, 2, T1, T2...)
+        * @param $content Content: new content of the section
+        * @param $sectionTitle String: new section's subject, only if $section is 'new'
+        * @param $edittime String: revision timestamp or null to use the current revision
+        *
+        * @return Content new complete article content, or null if error
+        *
+        * @since 1.WD
+        */
+    public function replaceSectionContent( $section, Content $sectionContent, $sectionTitle = '', $edittime = null ) {
         wfProfileIn( __METHOD__ );
 
         if ( strval( $section ) == '' ) {
@@ -1223,7 +1309,7 @@ class WikiPage extends Page {
         * edit-already-exists error will be returned. These two conditions are also possible with
         * auto-detection due to MediaWiki's performance-optimised locking strategy.
         *
-        * @param $baseRevId the revision ID this edit was based off, if any
+        * @param $baseRevId int the revision ID this edit was based off, if any
         * @param $user User the user doing the edit
         *
         * @return Status object. Possible errors:
@@ -1240,10 +1326,12 @@ class WikiPage extends Page {
         *     revision:                The revision object for the inserted revision, or null
         *
         *  Compatibility note: this function previously returned a boolean value indicating success/failure
-     * @deprecated since 1.20: use doEditContent() instead.
+        *
+        * @deprecated since 1.WD: use doEditContent() instead.
         */
     public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) { #FIXME: use doEditContent() instead
-        #TODO: log use of deprecated function
+        wfDeprecated( __METHOD__, '1.WD' );
+
         $content = ContentHandler::makeContent( $text, $this->getTitle() );
 
         return $this->doEditContent( $content, $summary, $flags, $baseRevId, $user );
@@ -1294,7 +1382,7 @@ class WikiPage extends Page {
      *     new:                     Boolean indicating if the function attempted to create a new article
      *     revision:                The revision object for the inserted revision, or null
      *
-     *  Compatibility note: this function previously returned a boolean value indicating success/failure
+     * @since 1.WD
      */
        public function doEditContent( Content $content, $summary, $flags = 0, $baseRevId = false,
                                    User $user = null, $serialisation_format = null ) { #FIXME: use this
@@ -1328,7 +1416,7 @@ class WikiPage extends Page {
 
             if ( $txt !== $content_text ) {
                 # if the text changed, unserialize the new version to create an updated Content object.
-                $content = $content->getContentHandler()->unserialize( $txt );
+                $content = $content->getContentHandler()->unserializeContent( $txt );
             }
         }
 
@@ -1358,6 +1446,7 @@ class WikiPage extends Page {
 
                # Provide autosummaries if one is not provided and autosummaries are enabled.
                if ( $wgUseAutomaticEditSummaries && $flags & EDIT_AUTOSUMMARY && $summary == '' ) {
+            if ( !$old_content ) $old_content = null;
                        $summary = $handler->getAutosummary( $old_content, $content, $flags );
                }
 
@@ -1397,13 +1486,15 @@ class WikiPage extends Page {
                                'parent_id'  => $oldid,
                                'user'       => $user->getId(),
                                'user_text'  => $user->getName(),
-                               'timestamp'  => $now
+                               'timestamp'  => $now,
+                'content_model' => $content->getModelName(),
+                'content_format' => $serialisation_format,
                        ) );
 
                        $changed = !$content->equals( $old_content );
 
                        if ( $changed ) {
-                               $dbw->begin();
+                               $dbw->begin( __METHOD__ );
                                $revisionId = $revision->insertOn( $dbw );
 
                                # Update page
@@ -1425,7 +1516,7 @@ class WikiPage extends Page {
                                        }
 
                                        $revisionId = 0;
-                                       $dbw->rollback();
+                                       $dbw->rollback( __METHOD__ );
                                } else {
                                        global $wgUseRCPatrol;
                                        wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
@@ -1442,11 +1533,11 @@ class WikiPage extends Page {
 
                                                # Log auto-patrolled edits
                                                if ( $patrolled ) {
-                                                       PatrolLog::record( $rc, true );
+                                                       PatrolLog::record( $rc, true, $user );
                                                }
                                        }
                                        $user->incEditCount();
-                                       $dbw->commit();
+                                       $dbw->commit( __METHOD__ );
                                }
                        } else {
                                // Bug 32948: revision ID must be set to page {{REVISIONID}} and
@@ -1479,14 +1570,14 @@ class WikiPage extends Page {
                        # Create new article
                        $status->value['new'] = true;
 
-                       $dbw->begin();
+                       $dbw->begin( __METHOD__ );
 
                        # Add the page record; stake our claim on this title!
                        # This will return false if the article already exists
                        $newid = $this->insertOn( $dbw );
 
                        if ( $newid === false ) {
-                               $dbw->rollback();
+                               $dbw->rollback( __METHOD__ );
                                $status->fatal( 'edit-already-exists' );
 
                                wfProfileOut( __METHOD__ );
@@ -1502,7 +1593,9 @@ class WikiPage extends Page {
                 'len'        => $newsize,
                                'user'       => $user->getId(),
                                'user_text'  => $user->getName(),
-                               'timestamp'  => $now
+                               'timestamp'  => $now,
+                'content_model' => $content->getModelName(),
+                'content_format' => $serialisation_format,
                        ) );
                        $revisionId = $revision->insertOn( $dbw );
 
@@ -1524,11 +1617,11 @@ class WikiPage extends Page {
 
                                # Log auto-patrolled edits
                                if ( $patrolled ) {
-                                       PatrolLog::record( $rc, true );
+                                       PatrolLog::record( $rc, true, $user );
                                }
                        }
                        $user->incEditCount();
-                       $dbw->commit();
+                       $dbw->commit( __METHOD__ );
 
                        # Update links, etc.
                        $this->doEditUpdates( $revision, $user, array( 'created' => true ) );
@@ -1581,7 +1674,8 @@ class WikiPage extends Page {
        /**
         * Prepare text which is about to be saved.
         * Returns a stdclass with source, pst and output members
-     * @deprecated in 1.20: use prepareContentForEdit instead.
+        *
+        * @deprecated in 1.WD: use prepareContentForEdit instead.
         */
     public function prepareTextForEdit( $text, $revid = null, User $user = null ) {  #FIXME: use prepareContentForEdit() instead #XXX: who uses this?!
         #TODO: log use of deprecated function
@@ -1597,7 +1691,10 @@ class WikiPage extends Page {
      * @param null $revid
      * @param null|\User $user
      * @param null $serialization_format
+     *
      * @return bool|object
+     *
+     * @since 1.WD
      */
        public function prepareContentForEdit( Content $content, $revid = null, User $user = null, $serialization_format = null ) { #FIXME: use this #XXX: really public?!
                global $wgParser, $wgContLang, $wgUser;
@@ -1626,7 +1723,11 @@ class WikiPage extends Page {
         $edit->format = $serialization_format;
 
                $edit->popts = $this->makeParserOptions( 'canonical' );
-               $edit->output = $edit->pstContent->getParserOutput( $this->mTitle, $revid, $edit->popts );
+
+               // TODO: is there no better way to obtain a context here?
+               $context = RequestContext::getMain();
+               $context->setTitle( $this->mTitle );
+               $edit->output = $edit->pstContent->getParserOutput( $context, $revid, $edit->popts );
 
         $edit->newContent = $content;
                $edit->oldContent = $this->getContent( Revision::RAW );
@@ -1645,7 +1746,6 @@ class WikiPage extends Page {
         * Purges pages that include this page if the text was changed here.
         * Every 100th edit, prune the recent changes table.
         *
-        * @private
         * @param $revision Revision object
         * @param $user User object that did the revision
         * @param $options Array of options, following indexes are used:
@@ -1680,9 +1780,9 @@ class WikiPage extends Page {
                        $parserCache->save( $editInfo->output, $this, $editInfo->popts );
                }
 
-               # Update the links tables
-               $u = new LinksUpdate( $this->mTitle, $editInfo->output );
-               $u->doUpdate();
+               # Update the links tables and other secondary data
+        $updates = $editInfo->output->getSecondaryDataUpdates( $this->mTitle );
+        SecondaryDataUpdate::runUpdates( $updates );
 
                wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
 
@@ -1776,11 +1876,14 @@ class WikiPage extends Page {
         * @param $user User The relevant user
         * @param $comment String: comment submitted
         * @param $minor Boolean: whereas it's a minor modification
+        *
+        * @deprecated since 1.WD, use doEditContent() instead.
         */
     public function doQuickEdit( $text, User $user, $comment = '', $minor = 0 ) {
-        #TODO: log use of deprecated function
+        wfDeprecated( __METHOD__, "1.WD" );
+
         $content = ContentHandler::makeContent( $text, $this->getTitle() );
-        return $this->doQuickEdit( $content, $user, $comment , $minor );
+        return $this->doQuickEditContent( $content, $user, $comment , $minor );
     }
 
     /**
@@ -2048,23 +2151,46 @@ class WikiPage extends Page {
        }
 
        /**
-        * Back-end article deletion
+        * Same as doDeleteArticleReal(), but returns more detailed success/failure status
         * Deletes the article with database consistency, writes logs, purges caches
         *
         * @param $reason string delete reason for deletion log
-        * @param $suppress bitfield
+        * @param $suppress int bitfield
         *      Revision::DELETED_TEXT
         *      Revision::DELETED_COMMENT
         *      Revision::DELETED_USER
         *      Revision::DELETED_RESTRICTED
         * @param $id int article ID
         * @param $commit boolean defaults to true, triggers transaction end
-        * @param &$errors Array of errors to append to
-        * @param $user User The relevant user
+        * @param &$error Array of errors to append to
+        * @param $user User The deleting user
         * @return boolean true if successful
         */
        public function doDeleteArticle(
                $reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
+       ) {
+               return $this->doDeleteArticleReal( $reason, $suppress, $id, $commit, $error, $user )
+                       == WikiPage::DELETE_SUCCESS;
+       }
+
+       /**
+        * Back-end article deletion
+        * Deletes the article with database consistency, writes logs, purges caches
+        *
+        * @param $reason string delete reason for deletion log
+        * @param $suppress int bitfield
+        *      Revision::DELETED_TEXT
+        *      Revision::DELETED_COMMENT
+        *      Revision::DELETED_USER
+        *      Revision::DELETED_RESTRICTED
+        * @param $id int article ID
+        * @param $commit boolean defaults to true, triggers transaction end
+        * @param &$error Array of errors to append to
+        * @param $user User The deleting user
+        * @return int: One of WikiPage::DELETE_* constants
+        */
+       public function doDeleteArticleReal(
+               $reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
        ) {
                global $wgUser;
                $user = is_null( $user ) ? $wgUser : $user;
@@ -2072,14 +2198,14 @@ class WikiPage extends Page {
                wfDebug( __METHOD__ . "\n" );
 
                if ( ! wfRunHooks( 'ArticleDelete', array( &$this, &$user, &$reason, &$error ) ) ) {
-                       return false;
+                       return WikiPage::DELETE_HOOK_ABORTED;
                }
                $dbw = wfGetDB( DB_MASTER );
                $t = $this->mTitle->getDBkey();
                $id = $id ? $id : $this->mTitle->getArticleID( Title::GAID_FOR_UPDATE );
 
                if ( $t === '' || $id == 0 ) {
-                       return false;
+                       return WikiPage::DELETE_NO_PAGE;
                }
 
                // Bitfields to further suppress the content
@@ -2094,7 +2220,7 @@ class WikiPage extends Page {
                        $bitfield = 'rev_deleted';
                }
 
-               $dbw->begin();
+               $dbw->begin( __METHOD__ );
                // For now, shunt the revision data into the archive table.
                // Text is *not* removed from the text table; bulk storage
                // is left intact to avoid breaking block-compression or
@@ -2133,11 +2259,11 @@ class WikiPage extends Page {
 
                # Now that it's safely backed up, delete it
                $dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__ );
-               $ok = ( $dbw->affectedRows() > 0 ); // getArticleId() uses slave, could be laggy
+               $ok = ( $dbw->affectedRows() > 0 ); // getArticleID() uses slave, could be laggy
 
                if ( !$ok ) {
-                       $dbw->rollback();
-                       return false;
+                       $dbw->rollback( __METHOD__ );
+                       return WikiPage::DELETE_NO_REVISIONS;
                }
 
                $this->doDeleteUpdates( $id );
@@ -2153,11 +2279,11 @@ class WikiPage extends Page {
                $logEntry->publish( $logid );
 
                if ( $commit ) {
-                       $dbw->commit();
+                       $dbw->commit( __METHOD__ );
                }
 
                wfRunHooks( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id ) );
-               return true;
+               return WikiPage::DELETE_SUCCESS;
        }
 
        /**
@@ -2183,6 +2309,8 @@ class WikiPage extends Page {
 
                $this->updateCategoryCounts( array(), $cats );
 
+        #TODO: move this to an Update object!
+
                # If using cascading deletes, we can skip some explicit deletes
                if ( !$dbw->cascadingDeletes() ) {
                        $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
@@ -2215,6 +2343,9 @@ class WikiPage extends Page {
                # Clear caches
                self::onArticleDelete( $this->mTitle );
 
+               # Reset this object
+               $this->clear();
+
                # Clear the cached article id so the interface doesn't act like we exist
                $this->mTitle->resetArticleID( 0 );
        }
@@ -2283,6 +2414,7 @@ class WikiPage extends Page {
         *
         * @param $resultDetails Array: contains result-specific array of additional values
         * @param $guser User The user performing the rollback
+        * @return array
         */
        public function commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser ) {
                global $wgUseRCPatrol, $wgContLang;
@@ -2294,7 +2426,7 @@ class WikiPage extends Page {
                }
 
                # Get the last editor
-               $current = Revision::newFromTitle( $this->mTitle );
+               $current = $this->getRevision();
                if ( is_null( $current ) ) {
                        # Something wrong... no page?
                        return array( array( 'notanarticle' ) );
@@ -2529,18 +2661,20 @@ class WikiPage extends Page {
 
        /**
        * Return an applicable autosummary if one exists for the given edit.
-       * @param $oldtext String: the previous text of the page.
-       * @param $newtext String: The submitted text of the page.
+       * @param $oldtext String|null: the previous text of the page.
+       * @param $newtext String|null: The submitted text of the page.
        * @param $flags Int bitmask: a bitmask of flags submitted for the edit.
        * @return string An appropriate autosummary, or an empty string.
-    * @deprecated since 1.20, use ContentHandler::getAutosummary() instead
+    * @deprecated since 1.WD, use ContentHandler::getAutosummary() instead
        */
        public static function getAutosummary( $oldtext, $newtext, $flags ) {
                # NOTE: stub for backwards-compatibility. assumes the given text is wikitext. will break horribly if it isn't.
 
+               wfDeprecated( __METHOD__, '1.WD' );
+
         $handler = ContentHandler::getForModelName( CONTENT_MODEL_WIKITEXT );
-        $oldContent = $handler->unserialize( $oldtext );
-        $newContent = $handler->unserialize( $newtext );
+        $oldContent = is_null( $oldtext ) ? null : $handler->unserializeContent( $oldtext );
+        $newContent = is_null( $newtext ) ? null : $handler->unserializeContent( $newtext );
 
         return $handler->getAutosummary( $oldContent, $newContent, $flags );
        }
@@ -2551,13 +2685,100 @@ class WikiPage extends Page {
         * @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
-     * @deprecated since 1.20, use ContentHandler::getAutoDeleteReason() instead
+     * @deprecated since 1.WD, use ContentHandler::getAutoDeleteReason() instead
         */
        public function getAutoDeleteReason( &$hasHistory ) {
         #NOTE: stub for backwards-compatibility.
 
+               wfDeprecated( __METHOD__, '1.WD' );
+
                $handler = ContentHandler::getForTitle( $this->getTitle() );
         $handler->getAutoDeleteReason( $this->getTitle(), $hasHistory );
+               global $wgContLang;
+
+               // Get the last revision
+               $rev = $this->getRevision();
+
+               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;
+                       }
+               }
+
+               $dbw = wfGetDB( DB_MASTER );
+
+               // 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;
+               }
+
+               $hasHistory = ( $res->numRows() > 1 );
+               $row = $dbw->fetchObject( $res );
+
+               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;
+                               }
+                       }
+               } else {
+                       $onlyAuthor = false;
+               }
+
+               // 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;
        }
 
        /**
@@ -2669,6 +2890,7 @@ class WikiPage extends Page {
 
                if ( count( $templates_diff ) > 0 ) {
                        # Whee, link updates time.
+            # Note: we are only interested in links here. We don't need to get other SecondaryDataUpdate items from the parser output.
                        $u = new LinksUpdate( $this->mTitle, $parserOutput, false );
                        $u->doUpdate();
                }
@@ -2790,6 +3012,7 @@ class WikiPage extends Page {
 
        /**
         * @deprecated since 1.18
+        * @return bool
         */
        public function useParserCache( $oldid ) {
                wfDeprecated( __METHOD__, '1.18' );
@@ -2826,7 +3049,7 @@ class PoolWorkArticleView extends PoolCounterWork {
        private $text;
 
        /**
-        * @var ParserOutput|false
+        * @var ParserOutput|bool
         */
        private $parserOutput = false;
 
@@ -2836,7 +3059,7 @@ class PoolWorkArticleView extends PoolCounterWork {
        private $isDirty = false;
 
        /**
-        * @var Status|false
+        * @var Status|bool
         */
        private $error = false;
 
@@ -2848,16 +3071,23 @@ class PoolWorkArticleView extends PoolCounterWork {
         * @param $useParserCache Boolean: whether to use the parser cache
         * @param $parserOptions parserOptions to use for the parse operation
         * @param $content Content|String: content to parse or null to load it; may also be given as a wikitext string, for BC
+        * @param $context IContextSource context for parsing
         */
-       function __construct( Page $page, ParserOptions $parserOptions, $revid, $useParserCache, $content = null ) {
+       function __construct( Page $page, ParserOptions $parserOptions, $revid, $useParserCache, $content = null, IContextSource $context = null ) {
         if ( is_string($content) ) { #BC: old style call
             $modelName = $page->getRevision()->getContentModelName();
             $format = $page->getRevision()->getContentFormat();
             $content = ContentHandler::makeContent( $content, $page->getTitle(), $modelName, $format );
         }
 
+               if ( is_null( $context ) ) {
+                       $context = RequestContext::getMain();
+                       #XXX: clone and then set title?
+               }
+
                $this->page = $page;
                $this->revid = $revid;
+               $this->context = $context;
                $this->cacheable = $useParserCache;
                $this->parserOptions = $parserOptions;
                $this->content = $content;
@@ -2886,7 +3116,7 @@ class PoolWorkArticleView extends PoolCounterWork {
        /**
         * Get a Status object in case of error or false otherwise
         *
-        * @return Status|false
+        * @return Status|bool
         */
        public function getError() {
                return $this->error;
@@ -2896,7 +3126,9 @@ class PoolWorkArticleView extends PoolCounterWork {
         * @return bool
         */
        function doWork() {
-               global $wgParser, $wgUseFileCache;
+               global $wgUseFileCache;
+
+               // @todo: several of the methods called on $this->page are not declared in Page, but present in WikiPage and delegated by Article.
 
                $isCurrent = $this->revid === $this->page->getLatest();
 
@@ -2912,9 +3144,10 @@ class PoolWorkArticleView extends PoolCounterWork {
             $content = $rev->getContent(); #XXX: why use PUBLIC audience here (default), and RAW above?
                }
 
-               $time = - wfTime();
-               $this->parserOutput = $content->getParserOutput( $this->page->getTitle(), $this->revid, $this->parserOptions );
-               $time += wfTime();
+               $time = - microtime( true );
+               // TODO: page might not have this method? Hard to tell what page is supposed to be here...
+               $this->parserOutput = $content->getParserOutput( $this->context, $this->revid, $this->parserOptions );
+               $time += microtime( true );
 
                # Timing hack
                if ( $time > 3 ) {
@@ -2975,6 +3208,7 @@ class PoolWorkArticleView extends PoolCounterWork {
 
        /**
         * @param $status Status
+        * @return bool
         */
        function error( $status ) {
                $this->error = $status;