Bug 23699: Add trailing \n at the end of <div>s in wrapWikiMsg()
[lhc/web/wiklou.git] / includes / Article.php
index 17922b0..ab3e36c 100644 (file)
@@ -11,6 +11,7 @@
  * Note: edit user interface and cache support functions have been
  * moved to separate EditPage and HTMLFileCache classes.
  *
+ * @internal documentation reviewed 15 Mar 2010
  */
 class Article {
        /**@{{
@@ -33,15 +34,15 @@ class Article {
        var $mRedirectTarget = null;      // !< Title object if set
        var $mRedirectUrl = false;        // !<
        var $mRevIdFetched = 0;           // !<
-       var $mRevision;                   // !<
+       var $mRevision;                   // !< Revision object if set
        var $mTimestamp = '';             // !<
-       var $mTitle;                      // !<
+       var $mTitle;                      // !< Title object
        var $mTotalAdjustment = 0;        // !<
        var $mTouched = '19700101000000'; // !<
        var $mUser = -1;                  // !< Not loaded
-       var $mUserText = '';              // !<
-       var $mParserOptions;              // !<
-       var $mParserOutput;               // !<
+       var $mUserText = '';              // !< username from Revision if set
+       var $mParserOptions;              // !< ParserOptions object
+       var $mParserOutput;               // !< ParserCache object if set
        /**@}}*/
 
        /**
@@ -70,7 +71,7 @@ class Article {
         * from another page on the wiki.
         * @param $from Title object.
         */
-       public function setRedirectedFrom( $from ) {
+       public function setRedirectedFrom( Title $from ) {
                $this->mRedirectedFrom = $from;
        }
 
@@ -136,6 +137,7 @@ class Article {
        /**
         * Get the Title object this text redirects to
         *
+        * @param $text string article content containing redirect info
         * @return mixed false, Title of in-wiki target, or string with URL
         */
        public function followRedirectText( $text ) {
@@ -173,6 +175,7 @@ class Article {
 
        /**
         * get the title object of the article
+        * @return Title object of current title
         */
        public function getTitle() {
                return $this->mTitle;
@@ -349,6 +352,7 @@ class Article {
         * Fetch a page record with the given conditions
         * @param $dbr Database object
         * @param $conditions Array
+        * @return mixed Database result resource, or false on failure
         */
        protected function pageData( $dbr, $conditions ) {
                $fields = array(
@@ -376,8 +380,12 @@ class Article {
        }
 
        /**
+        * Fetch a page record matching the Title object's namespace and title
+        * using a sanitized title string
+        * 
         * @param $dbr Database object
         * @param $title Title object
+        * @return mixed Database result resource, or false on failure
         */
        public function pageDataFromTitle( $dbr, $title ) {
                return $this->pageData( $dbr, array(
@@ -386,6 +394,8 @@ class Article {
        }
 
        /**
+        * Fetch a page record matching the requested ID
+        *
         * @param $dbr Database
         * @param $id Integer
         */
@@ -431,8 +441,9 @@ class Article {
        /**
         * Get text of an article from database
         * Does *NOT* follow redirects.
+        * 
         * @param $oldid Int: 0 for whatever the latest revision is
-        * @return string
+        * @return mixed string containing article contents, or false if null
         */
        function fetchContent( $oldid = 0 ) {
                if ( $this->mContentLoaded ) {
@@ -498,6 +509,7 @@ class Article {
         * Read/write accessor to select FOR UPDATE
         *
         * @param $x Mixed: FIXME
+        * @return mixed value of $x, or value stored in Article::mForUpdate
         */
        public function forUpdate( $x = null ) {
                return wfSetVar( $this->mForUpdate, $x );
@@ -600,7 +612,7 @@ class Article {
        /**
         * Tests if the article text represents a redirect
         *
-        * @param $text String: FIXME
+        * @param $text mixed string containing article contents, or boolean
         * @return bool
         */
        public function isRedirect( $text = false ) {
@@ -652,6 +664,10 @@ class Article {
                        $this->mRevIdFetched = $this->mLastRevision->getId();
                }
        }
+       
+       /**
+        * @return string GMT timestamp of last article revision
+        **/
 
        public function getTimestamp() {
                // Check if the field has been filled by ParserCache::get()
@@ -661,27 +677,45 @@ class Article {
                return wfTimestamp( TS_MW, $this->mTimestamp );
        }
 
+       /**
+        * @return int user ID for the user that made the last article revision
+        */
        public function getUser() {
                $this->loadLastEdit();
                return $this->mUser;
        }
 
+       /**
+        * @return string username of the user that made the last article revision
+        */
        public function getUserText() {
                $this->loadLastEdit();
                return $this->mUserText;
        }
 
+       /**
+        * @return string Comment stored for the last article revision
+        */
        public function getComment() {
                $this->loadLastEdit();
                return $this->mComment;
        }
 
+       /**
+        * Returns true if last revision was marked as "minor edit"
+        * 
+        * @return boolean Minor edit indicator for the last article revision.
+        */
        public function getMinorEdit() {
                $this->loadLastEdit();
                return $this->mMinorEdit;
        }
 
-       /* Use this to fetch the rev ID used on page views */
+       /**
+        * Use this to fetch the rev ID used on page views
+        *
+        * @return int revision ID of last article revision
+        */
        public function getRevIdFetched() {
                $this->loadLastEdit();
                return $this->mRevIdFetched;
@@ -690,6 +724,7 @@ class Article {
        /**
         * @param $limit Integer: default 0.
         * @param $offset Integer: default 0.
+        * @return UserArrayFromResult object with User objects of article contributors for requested range
         */
        public function getContributors( $limit = 0, $offset = 0 ) {
                # XXX: this is expensive; cache this info somewhere.
@@ -770,8 +805,6 @@ class Article {
                        }
                }
 
-               $sk = $wgUser->getSkin();
-
                # getOldID may want us to redirect somewhere else
                if ( $this->mRedirectUrl ) {
                        $wgOut->redirect( $this->mRedirectUrl );
@@ -799,15 +832,6 @@ class Article {
                        wfIncrStats( 'pcache_miss_stub' );
                }
 
-               # For the main page, overwrite the <title> element with the con-
-               # tents of 'pagetitle-view-mainpage' instead of the default (if
-               # that's not empty).
-               if ( $this->mTitle->equals( Title::newMainPage() )
-                       && ( $m = wfMsgForContent( 'pagetitle-view-mainpage' ) ) !== '' )
-               {
-                       $wgOut->setHTMLTitle( $m );
-               }
-
                $wasRedirected = $this->showRedirectedFromHeader();
                $this->showNamespaceHeader();
 
@@ -815,6 +839,7 @@ class Article {
                # Keep going until $outputDone is set, or we run out of things to do.
                $pass = 0;
                $outputDone = false;
+               $this->mParserOutput = false;
                while ( !$outputDone && ++$pass ) {
                        switch( $pass ) {
                                case 1:
@@ -923,6 +948,23 @@ class Article {
                        }
                }
 
+               # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
+               if ( $this->mParserOutput ) {
+                       $titleText = $this->mParserOutput->getTitleText();
+                       if ( strval( $titleText ) !== '' ) {
+                               $wgOut->setPageTitle( $titleText );
+                       }
+               }
+
+               # For the main page, overwrite the <title> element with the con-
+               # tents of 'pagetitle-view-mainpage' instead of the default (if
+               # that's not empty).
+               if ( $this->mTitle->equals( Title::newMainPage() )
+                       && ( $m = wfMsgForContent( 'pagetitle-view-mainpage' ) ) !== '' )
+               {
+                       $wgOut->setHTMLTitle( $m );
+               }
+
                # Now that we've filled $this->mParserOutput, we know whether
                # there are any __NOINDEX__ tags on the page
                $policy = $this->getRobotPolicy( 'view' );
@@ -989,7 +1031,7 @@ class Article {
         *    array
         */
        public function getRobotPolicyForView() {
-               wfDeprecated( __FUNC__ );
+               wfDeprecated( __METHOD__ );
                $policy = $this->getRobotPolicy( 'view' );
                return $policy['index'] . ',' . $policy['follow'];
        }
@@ -1088,6 +1130,8 @@ class Article {
         * If this request is a redirect view, send "redirected from" subtitle to
         * $wgOut. Returns true if the header was needed, false if this is not a
         * redirect view. Handles both local and remote redirects.
+        *
+        * @return boolean
         */
        public function showRedirectedFromHeader() {
                global $wgOut, $wgUser, $wgRequest, $wgRedirectSources;
@@ -1142,7 +1186,7 @@ class Article {
                if ( $this->mTitle->isTalkPage() ) {
                        $msg = wfMsgNoTrans( 'talkpageheader' );
                        if ( $msg !== '-' && !wfEmptyMsg( 'talkpageheader', $msg ) ) {
-                               $wgOut->wrapWikiMsg( "<div class=\"mw-talkpageheader\">\n$1</div>", array( 'talkpageheader' ) );
+                               $wgOut->wrapWikiMsg( "<div class=\"mw-talkpageheader\">\n$1\n</div>", array( 'talkpageheader' ) );
                        }
                }
        }
@@ -1215,7 +1259,7 @@ class Article {
                        $user = User::newFromName( $rootPart, false /* allow IP users*/ );
                        $ip = User::isIP( $rootPart );
                        if ( !$user->isLoggedIn() && !$ip ) { # User does not exist
-                               $wgOut->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n\$1</div>",
+                               $wgOut->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>",
                                        array( 'userpage-userdoesnotexist-view', $rootPart ) );
                        } else if ( $user->isBlocked() ) { # Show log extract if the user is currently blocked
                                LogEventsList::showLogExtract(
@@ -1274,7 +1318,8 @@ class Article {
        /**
         * If the revision requested for view is deleted, check permissions.
         * Send either an error message or a warning header to $wgOut.
-        * Returns true if the view is allowed, false if not.
+        * 
+        * @return boolean true if the view is allowed, false if not.
         */
        public function showDeletedRevisionHeader() {
                global $wgOut, $wgRequest;
@@ -1284,7 +1329,7 @@ class Article {
                }
                // If the user is not allowed to see it...
                if ( !$this->mRevision->userCan( Revision::DELETED_TEXT ) ) {
-                       $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n",
+                       $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
                                'rev-deleted-text-permission' );
                        return false;
                // If the user needs to confirm that they want to see it...
@@ -1294,21 +1339,23 @@ class Article {
                        $link = $this->mTitle->getFullUrl( "oldid={$oldid}&unhide=1" );
                        $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
                                'rev-suppressed-text-unhide' : 'rev-deleted-text-unhide';
-                       $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n",
+                       $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
                                array( $msg, $link ) );
                        return false;
                // We are allowed to see...
                } else {
                        $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
                                'rev-suppressed-text-view' : 'rev-deleted-text-view';
-                       $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n", $msg );
+                       $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", $msg );
                        return true;
                }
        }
 
-       /*
-       * Should the parser cache be used?
-       */
+       /**
+        * Should the parser cache be used?
+        *
+        * @return boolean
+        */
        public function useParserCache( $oldid ) {
                global $wgUser, $wgEnableParserCache;
 
@@ -1341,6 +1388,8 @@ class Article {
         * output it and return true. If it is not present, output nothing and
         * return false. This is used as a callback function for
         * PoolCounter::executeProtected().
+        *
+        * @return boolean
         */
        public function tryDirtyCache() {
                global $wgOut;
@@ -1381,9 +1430,11 @@ class Article {
 
        /**
         * View redirect
+        * 
         * @param $target Title object or Array of destination(s) to redirect
         * @param $appendSubtitle Boolean [optional]
         * @param $forceKnown Boolean: should the image be shown as a bluelink regardless of existence?
+        * @return string containing HMTL with redirect link
         */
        public function viewRedirect( $target, $appendSubtitle = true, $forceKnown = false ) {
                global $wgOut, $wgContLang, $wgStylePath, $wgUser;
@@ -1434,6 +1485,9 @@ class Article {
 
        }
 
+       /**
+        * Builds trackback links for article display if $wgUseTrackbacks is set to true
+        */
        public function addTrackbacks() {
                global $wgOut, $wgUser;
                $dbr = wfGetDB( DB_SLAVE );
@@ -1459,10 +1513,12 @@ class Article {
                                        $o->tb_name,
                                        $rmvtxt );
                }
-               $wgOut->wrapWikiMsg( "<div id='mw_trackbacks'>$1</div>\n", array( 'trackbackbox', $tbtext ) );
-               $this->mTitle->invalidateCache();
+               $wgOut->wrapWikiMsg( "<div id='mw_trackbacks'>\n$1\n</div>\n", array( 'trackbackbox', $tbtext ) );
        }
 
+       /**
+        * Removes trackback record for current article from trackbacks table
+        */
        public function deletetrackback() {
                global $wgUser, $wgRequest, $wgOut;
                if ( !$wgUser->matchEditToken( $wgRequest->getVal( 'token' ) ) ) {
@@ -1482,6 +1538,10 @@ class Article {
                $wgOut->addWikiMsg( 'trackbackdeleteok' );
                $this->mTitle->invalidateCache();
        }
+       
+       /**
+        * Handle action=render
+        */
 
        public function render() {
                global $wgOut;
@@ -1544,7 +1604,7 @@ class Article {
        /**
         * Insert a new empty page record for this article.
         * This *must* be followed up by creating a revision
-        * and running $this->updateToLatest( $rev_id );
+        * and running $this->updateRevisionOn( ... );
         * or else the record will be left in a funky state.
         * Best if all done inside a transaction.
         *
@@ -1672,6 +1732,7 @@ class Article {
         *
         * @param $dbw Database object
         * @param $revision Revision object
+        * @return mixed 
         */
        public function updateIfNewerOn( &$dbw, $revision ) {
                wfProfileIn( __METHOD__ );
@@ -1701,6 +1762,9 @@ class Article {
 
        /**
         * @param $section empty/null/false or a section number (0, 1, 2, T1, T2...)
+        * @param $text String: new text of the section
+        * @param $summary String: new section's subject, only if $section is 'new'
+        * @param $edittime String: revision timestamp or null to use the current revision
         * @return string Complete article text, or null if error
         */
        public function replaceSection( $section, $text, $summary = '', $edittime = null ) {
@@ -1747,28 +1811,8 @@ class Article {
                        ( $suppressRC ? EDIT_SUPPRESS_RC : 0 ) |
                        ( $bot ? EDIT_FORCE_BOT : 0 );
 
-               # If this is a comment, add the summary as headline
-               if ( $comment && $summary != "" ) {
-                       $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $summary ) . "\n\n" . $text;
-               }
-
-               $this->doEdit( $text, $summary, $flags );
+               $this->doEdit( $text, $summary, $flags, false, null, $watchthis, $comment, '', true );
 
-               $dbw = wfGetDB( DB_MASTER );
-               if ( $watchthis ) {
-                       if ( !$this->mTitle->userIsWatching() ) {
-                               $dbw->begin();
-                               $this->doWatch();
-                               $dbw->commit();
-                       }
-               } else {
-                       if ( $this->mTitle->userIsWatching() ) {
-                               $dbw->begin();
-                               $this->doUnwatch();
-                               $dbw->commit();
-                       }
-               }
-               $this->doRedirect( $this->isRedirect( $text ) );
        }
 
        /**
@@ -1779,33 +1823,30 @@ class Article {
                        ( $minor ? EDIT_MINOR : 0 ) |
                        ( $forceBot ? EDIT_FORCE_BOT : 0 );
 
-               $status = $this->doEdit( $text, $summary, $flags );
+               $status = $this->doEdit( $text, $summary, $flags, false, null, $watchthis, false, $sectionanchor, true );
                if ( !$status->isOK() ) {
                        return false;
                }
 
-               $dbw = wfGetDB( DB_MASTER );
-               if ( $watchthis ) {
-                       if ( !$this->mTitle->userIsWatching() ) {
-                               $dbw->begin();
-                               $this->doWatch();
-                               $dbw->commit();
-                       }
-               } else {
-                       if ( $this->mTitle->userIsWatching() ) {
-                               $dbw->begin();
-                               $this->doUnwatch();
-                               $dbw->commit();
+               return true;
+       }
+
+       /**
+        * Check flags and add EDIT_NEW or EDIT_UPDATE to them as needed.
+        * @param $flags Int
+        * @return Int updated $flags
+        */
+       function checkFlags( $flags ) {
+               if ( !( $flags & EDIT_NEW ) && !( $flags & EDIT_UPDATE ) ) {
+                       if ( $this->mTitle->getArticleID() ) {
+                               $flags |= EDIT_UPDATE;
+                       } else {
+                               $flags |= EDIT_NEW;
                        }
                }
 
-               $extraQuery = ''; // Give extensions a chance to modify URL query on update
-               wfRunHooks( 'ArticleUpdateBeforeRedirect', array( $this, &$sectionanchor, &$extraQuery ) );
-
-               $this->doRedirect( $this->isRedirect( $text ), $sectionanchor, $extraQuery );
-               return true;
+               return $flags;
        }
-
        /**
         * Article::doEdit()
         *
@@ -1840,6 +1881,10 @@ class Article {
         *
         * @param $baseRevId the revision ID this edit was based off, if any
         * @param $user Optional user object, $wgUser will be used if not passed
+        * @param $watchthis Watch the page if true, unwatch the page if false, do nothing if null
+        * @param $sectionanchor The section anchor for the page; used for redirecting the user back to the page
+        *              after the edit is successfully committed
+        * @param $redirect If true, redirect the user back to the page after the edit is successfully committed
         *
         * @return Status object. Possible errors:
         *     edit-hook-aborted:       The ArticleSave hook aborted the edit but didn't set the fatal flag of $status
@@ -1856,7 +1901,8 @@ class Article {
         *
         *  Compatibility note: this function previously returned a boolean value indicating success/failure
         */
-       public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) {
+       public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null , $watchthis = null,
+                       $comment = false, $sectionanchor = '', $redirect = false) {
                global $wgUser, $wgDBtransactions, $wgUseAutomaticEditSummaries;
 
                # Low-level sanity check
@@ -1872,17 +1918,15 @@ class Article {
                # Load $this->mTitle->getArticleID() and $this->mLatest if it's not already
                $this->loadPageData();
 
-               if ( !( $flags & EDIT_NEW ) && !( $flags & EDIT_UPDATE ) ) {
-                       $aid = $this->mTitle->getArticleID();
-                       if ( $aid ) {
-                               $flags |= EDIT_UPDATE;
-                       } else {
-                               $flags |= EDIT_NEW;
-                       }
+               $flags = $this->checkFlags( $flags );
+               
+               # If this is a comment, add the summary as headline
+               if ( $comment && $summary != "" ) {
+                       $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $summary ) . "\n\n" . $text;
                }
 
                if ( !wfRunHooks( 'ArticleSave', array( &$this, &$user, &$text, &$summary,
-                       $flags & EDIT_MINOR, null, null, &$flags, &$status ) ) )
+                       $flags & EDIT_MINOR, &$watchthis, null, &$flags, &$status) ) )
                {
                        wfDebug( __METHOD__ . ": ArticleSave hook aborted save!\n" );
                        wfProfileOut( __METHOD__ );
@@ -2075,7 +2119,7 @@ class Article {
                        Article::onArticleCreate( $this->mTitle );
 
                        wfRunHooks( 'ArticleInsertComplete', array( &$this, &$user, $text, $summary,
-                               $flags & EDIT_MINOR, null, null, &$flags, $revision ) );
+                               $flags & EDIT_MINOR, &$watchthis, null, &$flags, $revision ) );
                }
 
                # Do updates right now unless deferral was requested
@@ -2087,9 +2131,37 @@ class Article {
                $status->value['revision'] = $revision;
 
                wfRunHooks( 'ArticleSaveComplete', array( &$this, &$user, $text, $summary,
-                       $flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId ) );
-
+                       $flags & EDIT_MINOR, &$watchthis, null, &$flags, $revision, &$status, $baseRevId,
+                       &$redirect) );
+               
+               # Watch or unwatch the page
+               if ( $watchthis === true ) {
+                       if ( !$this->mTitle->userIsWatching() ) {
+                               $dbw->begin();
+                               $this->doWatch();
+                               $dbw->commit();
+                       }
+               } elseif ( $watchthis === false ) {
+                       if ( $this->mTitle->userIsWatching() ) {
+                               $dbw->begin();
+                               $this->doUnwatch();
+                               $dbw->commit();
+                       }
+               }
+                       
+               # Give extensions a chance to modify URL query on update
+               $extraQuery = ''; 
+               wfRunHooks( 'ArticleUpdateBeforeRedirect', array( $this, &$sectionanchor, &$extraQuery ) );
+               if ( $redirect ) {
+                       if ( $sectionanchor || $extraQuery ) {
+                               $this->doRedirect( $this->isRedirect( $text ), $sectionanchor, $extraQuery );
+                       } else {
+                               $this->doRedirect( $this->isRedirect( $text ) );
+                       }
+               }
+               
                wfProfileOut( __METHOD__ );
+               
                return $status;
        }
 
@@ -2451,7 +2523,10 @@ class Article {
 
        /**
         * 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 generateReason( &$hasHistory ) {
                global $wgContLang;
@@ -2487,13 +2562,17 @@ class Article {
 
                $hasHistory = ( $res->numRows() > 1 );
                $row = $dbw->fetchObject( $res );
-               $onlyAuthor = $row->rev_user_text;
-               // Try to find a second contributor
-               foreach ( $res as $row ) {
-                       if ( $row->rev_user_text != $onlyAuthor ) {
-                               $onlyAuthor = false;
-                               break;
+               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;
                }
                $dbw->freeResult( $res );
 
@@ -2594,7 +2673,7 @@ class Article {
                $bigHistory = $this->isBigDeletion();
                if ( $bigHistory && !$this->mTitle->userCan( 'bigdelete' ) ) {
                        global $wgLang, $wgDeleteRevisionsLimit;
-                       $wgOut->wrapWikiMsg( "<div class='error'>\n$1</div>\n",
+                       $wgOut->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n",
                                array( 'delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) );
                        return;
                }
@@ -2625,7 +2704,7 @@ class Article {
                        );
                        if ( $bigHistory ) {
                                global $wgDeleteRevisionsLimit;
-                               $wgOut->wrapWikiMsg( "<div class='error'>\n$1</div>\n",
+                               $wgOut->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n",
                                        array( 'delete-warning-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) );
                        }
                }
@@ -2766,7 +2845,7 @@ class Article {
                                ) ) .
                                "</td>
                        </tr>";
-               # Dissalow watching is user is not logged in
+               # Disallow watching if user is not logged in
                if ( $wgUser->isLoggedIn() ) {
                        $form .= "
                        <tr>
@@ -2857,9 +2936,18 @@ class Article {
        /**
         * Back-end article deletion
         * Deletes the article with database consistency, writes logs, purges caches
-        * Returns success
+        *
+        * @param $reason string delete reason for deletion log
+        * @param suppress 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
+        * @return boolean true if successful
         */
-       public function doDeleteArticle( $reason, $suppress = false, $id = 0 ) {
+       public function doDeleteArticle( $reason, $suppress = false, $id = 0, $commit = true ) {
                global $wgUseSquid, $wgDeferredUpdateList;
                global $wgUseTrackbacks;
 
@@ -2984,7 +3072,9 @@ class Article {
                # Make sure logging got through
                $log->addEntry( 'delete', $this->mTitle, $reason, array() );
 
-               $dbw->commit();
+               if ( $commit ) {
+                       $dbw->commit();
+               }
 
                return true;
        }
@@ -3396,8 +3486,7 @@ class Article {
                        return;
                }
 
-               $unhide = $wgRequest->getInt( 'unhide' ) == 1 &&
-                       $wgUser->matchEditToken( $wgRequest->getVal( 'token' ), $oldid );
+               $unhide = $wgRequest->getInt( 'unhide' ) == 1;
                # Cascade unhide param in links for easy deletion browsing
                $extraParams = array();
                if ( $wgRequest->getVal( 'unhide' ) ) {
@@ -3527,7 +3616,9 @@ class Article {
         * This function is called right before saving the wikitext,
         * so we can do things like signatures and links-in-context.
         *
-        * @param $text String
+        * @param $text String article contents
+        * @return string article contents with altered wikitext markup (signatures
+        *      converted, {{subst:}}, templates, etc.)
         */
        public function preSaveTransform( $text ) {
                global $wgParser, $wgUser;
@@ -3540,6 +3631,8 @@ class Article {
         * checkLastModified returns true if it has taken care of all
         * output to the client that is necessary for this request.
         * (that is, it has sent a cached version of the page)
+        *
+        * @return boolean true if cached version send, false otherwise
         */
        protected function tryFileCache() {
                static $called = false;
@@ -3582,7 +3675,7 @@ class Article {
 
        /**
         * Loads page_touched and returns a value indicating if it should be used
-        *
+        * @return boolean true if not a redirect
         */
        public function checkTouched() {
                if ( !$this->mDataLoaded ) {
@@ -3593,6 +3686,7 @@ class Article {
 
        /**
         * Get the page_touched field
+        * @return string containing GMT timestamp
         */
        public function getTouched() {
                # Ensure that page data has been loaded
@@ -3604,6 +3698,7 @@ class Article {
 
        /**
         * Get the page_latest field
+        * @return integer rev_id of current revision
         */
        public function getLatest() {
                if ( !$this->mDataLoaded ) {
@@ -3726,7 +3821,10 @@ class Article {
                $title->purgeSquid();
                $title->deleteTitleProtection();
        }
-
+       
+       /**
+        * Clears caches when article is deleted
+        */
        public static function onArticleDelete( $title ) {
                global $wgMessageCache;
                # Update existence markers on article/talk tabs...
@@ -3764,8 +3862,11 @@ class Article {
 
        /**
         * Purge caches on page update etc
+        *
+        * @param $title Title object
+        * @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, $flags = '' ) {
+       public static function onArticleEdit( $title ) {
                global $wgDeferredUpdateList;
 
                // Invalidate caches of articles which include this page
@@ -3856,7 +3957,7 @@ class Article {
         * on a given page. If page does not exist, returns false.
         *
         * @param $title Title object
-        * @return array
+        * @return mixed array or boolean false
         */
        public function pageCountInfo( $title ) {
                $id = $title->getArticleId();
@@ -3986,6 +4087,7 @@ class Article {
         *
         * @param $text String
         * @param $cache Boolean
+        * @param $parserOptions mixed ParserOptions object, or boolean false
         */
        public function outputWikiText( $text, $cache = true, $parserOptions = false ) {
                global $wgOut;
@@ -3998,6 +4100,11 @@ class Article {
         * This does all the heavy lifting for outputWikitext, except it returns the parser
         * output instead of sending it straight to $wgOut. Makes things nice and simple for,
         * say, embedding thread pages within a discussion system (LiquidThreads)
+        *
+        * @param $text string
+        * @param $cache boolean
+        * @param $parserOptions parsing options, defaults to false
+        * @return string containing parsed output
         */
        public function getOutputFromWikitext( $text, $cache = true, $parserOptions = false ) {
                global $wgParser, $wgOut, $wgEnableParserCache, $wgUseFileCache;
@@ -4033,6 +4140,7 @@ class Article {
 
        /**
         * Get parser options suitable for rendering the primary article wikitext
+        * @return mixed ParserOptions object or boolean false
         */
        public function getParserOptions() {
                global $wgUser;
@@ -4043,6 +4151,12 @@ class Article {
                }
                return $this->mParserOptions;
        }
+       
+       /**
+        * Updates cascading protections
+        *
+        * @param $parserOutput mixed ParserOptions object, or boolean false
+        **/
 
        protected function doCascadeProtectionUpdates( $parserOutput ) {
                if ( !$this->isCurrent() || wfReadOnly() || !$this->mTitle->areRestrictionsCascading() ) {
@@ -4097,7 +4211,6 @@ class Article {
         *
         * @param $added array   The names of categories that were added
         * @param $deleted array The names of categories that were deleted
-        * @return null
         */
        public function updateCategoryCounts( $added, $deleted ) {
                $ns = $this->mTitle->getNamespace();
@@ -4151,11 +4264,14 @@ class Article {
                }
        }
 
-       /** Lightweight method to get the parser output for a page, checking the parser cache
+       /**
+        * 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 Article::view is forced to
         * consider, so it's not appropriate to use there.
+        *
+        * @param $oldid mixed integer Revision ID or null
         */
-       function getParserOutput( $oldid = null ) {
+       public function getParserOutput( $oldid = null ) {
                global $wgEnableParserCache, $wgUser, $wgOut;
 
                // Should the parser cache be used?