Merge branch 'Wikidata' of ssh://gerrit.wikimedia.org:29418/mediawiki/core into Wikidata
[lhc/web/wiklou.git] / includes / WikiPage.php
index eaf32fe..fdb0792 100644 (file)
@@ -471,7 +471,7 @@ class WikiPage extends Page {
         * @param $text mixed string containing article contents, or boolean
         * @return bool
         */
-       public function isRedirect( $text = false ) {
+       public function isRedirect( $text = false ) { #TODO: investiage whether we need the text param
                if ( $text === false ) $content = $this->getContent();
                else $content = ContentHandler::makeContent( $text, $this->mTitle ); # TODO: allow model and format to be provided; or better, expect a Content object
 
@@ -575,11 +575,7 @@ class WikiPage extends Page {
                }
 
                wfProfileOut( __METHOD__ );
-               if ( $row ) {
-                       return Revision::newFromRow( $row );
-               } else {
-                       return null;
-               }
+               return $row ? Revision::newFromRow( $row ) : null;
        }
 
        /**
@@ -1093,11 +1089,10 @@ 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, IContextSource $context = null ) {
+       public function getParserOutput( ParserOptions $parserOptions, $oldid = null ) {
                wfProfileIn( __METHOD__ );
 
                $useParserCache = $this->isParserCacheUsed( $parserOptions, $oldid );
@@ -1118,7 +1113,7 @@ class WikiPage extends Page {
                        $oldid = $this->getLatest();
                }
 
-               $pool = new PoolWorkArticleView( $this, $parserOptions, $oldid, $useParserCache, null, $context );
+               $pool = new PoolWorkArticleView( $this, $parserOptions, $oldid, $useParserCache );
                $pool->execute();
 
                wfProfileOut( __METHOD__ );
@@ -1173,7 +1168,7 @@ class WikiPage extends Page {
 
                if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
                        if ( $this->mTitle->exists() ) {
-                               $text = ContentHandler::getContentText( $this->getContent() );
+                               $text = ContentHandler::getContentText( $this->getContent() ); #XXX: get native data directly?
                        } else {
                                $text = false;
                        }
@@ -1409,6 +1404,8 @@ class WikiPage extends Page {
                $sectionContent = ContentHandler::makeContent( $text, $this->getTitle() ); #XXX: could make section title, but that's not required.
 
                $newContent = $this->replaceSectionContent( $section, $sectionContent, $sectionTitle, $edittime );
+               #TODO: check $newContent == false. throw exception??
+               #TODO: add ContentHandler::supportsSections()
 
                return ContentHandler::getContentText( $newContent ); #XXX: unclear what will happen for non-wikitext!
        }
@@ -1604,12 +1601,12 @@ class WikiPage extends Page {
                $hook_ok = wfRunHooks( 'ArticleContentSave', array( &$this, &$user, &$content, &$summary,
                        $flags & EDIT_MINOR, null, null, &$flags, &$status ) );
 
-               if ( $hook_ok && !empty( $wgHooks['ArticleSave'] ) ) { # avoid serialization overhead if the hook isn't present
+               if ( $hook_ok && !empty( $wgHooks['ArticleSave'] ) ) { #FIXME: use wfHasHook or whatever. # avoid serialization overhead if the hook isn't present
                        $content_text = $content->serialize();
                        $txt = $content_text; # clone
 
                        $hook_ok = wfRunHooks( 'ArticleSave', array( &$this, &$user, &$txt, &$summary,
-                               $flags & EDIT_MINOR, null, null, &$flags, &$status ) );
+                               $flags & EDIT_MINOR, null, null, &$flags, &$status ) ); #TODO: survey extensions using this hook
 
                        if ( $txt !== $content_text ) {
                                # if the text changed, unserialize the new version to create an updated Content object.
@@ -1686,14 +1683,14 @@ class WikiPage extends Page {
                                'timestamp'  => $now,
                                'content_model' => $content->getModel(),
                                'content_format' => $serialisation_format,
-                       ) );
+                       ) ); #XXX: pass content object?!
 
                        $changed = !$content->equals( $old_content );
 
                        if ( $changed ) {
                                // TODO: validate!
                                if ( $content->isValid() ) {
-
+                                       #XXX: do it! throw exception??
                                }
 
                                $dbw->begin( __METHOD__ );
@@ -1757,8 +1754,6 @@ class WikiPage extends Page {
                                return $status;
                        }
 
-                       // TODO: create content diff to pass to update objects that might need it
-
                        # Update links tables, site stats, etc.
                        $this->doEditUpdates(
                                $revision,
@@ -1929,15 +1924,12 @@ class WikiPage extends Page {
                $edit->revid = $revid;
 
                $edit->pstContent = $content->preSaveTransform( $this->mTitle, $user, $popts );
-               $edit->pst = $edit->pstContent->serialize( $serialization_format );
+               $edit->pst = $edit->pstContent->serialize( $serialization_format ); #XXX: do we need this??
                $edit->format = $serialization_format;
 
                $edit->popts = $this->makeParserOptions( 'canonical' );
 
-               // 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->output = $edit->pstContent->getParserOutput( $this->mTitle, $revid, $edit->popts );
 
                $edit->newContent = $content;
                $edit->oldContent = $this->getContent( Revision::RAW );
@@ -1991,7 +1983,7 @@ class WikiPage extends Page {
                }
 
                # Update the links tables and other secondary data
-               $updates = $editInfo->output->getSecondaryDataUpdates( $this->mTitle );
+               $updates = $editInfo->output->getSecondaryDataUpdates( $this->getTitle() ); #FIXME: call ContentHandler::getSecondaryLinkUpdates. Don't parse iuf not needed! But don't parse too early either, only after saving, so we have an article ID!
                DataUpdate::runUpdates( $updates );
 
                wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
@@ -2036,7 +2028,7 @@ class WikiPage extends Page {
                }
 
                DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 1, $good, $total ) );
-               DeferredUpdates::addUpdate( new SearchUpdate( $id, $title, $content->getTextForSearchIndex() ) );
+               DeferredUpdates::addUpdate( new SearchUpdate( $id, $title, $content->getTextForSearchIndex() ) ); #TODO: let the search engine decide what to do with the content object
 
                # If this is another user's talk page, update newtalk.
                # Don't do this if $options['changed'] = false (null-edits) nor if
@@ -2119,7 +2111,7 @@ class WikiPage extends Page {
                        'length'     => $content->getSize(),
                        'comment'    => $comment,
                        'minor_edit' => $minor ? 1 : 0,
-               ) );
+               ) ); #XXX: set the content object
                $revision->insertOn( $dbw );
                $this->updateRevisionOn( $dbw, $revision );
 
@@ -2435,6 +2427,9 @@ class WikiPage extends Page {
                        $bitfield = 'rev_deleted';
                }
 
+               // we need to remember the old content so we can use it to generate all deletion updates.
+               $content = $this->getContent( Revision::RAW );
+
                $dbw = wfGetDB( DB_MASTER );
                $dbw->begin( __METHOD__ );
                // For now, shunt the revision data into the archive table.
@@ -2489,21 +2484,7 @@ class WikiPage extends Page {
                        return WikiPage::DELETE_NO_REVISIONS;
                }
 
-               # update site status
-               DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 1, - (int)$this->isCountable(), -1 ) );
-
-               # remove secondary indexes, etc
-               $updates = $this->getDeletionUpdates( );
-               DataUpdate::runUpdates( $updates );
-
-               # Clear caches
-               WikiPage::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 );
+               $this->doDeleteUpdates( $id, $content );
 
                # Log the deletion, if the page was suppressed, log it at Oversight instead
                $logtype = $suppress ? 'suppress' : 'delete';
@@ -2523,13 +2504,38 @@ class WikiPage extends Page {
                return WikiPage::DELETE_SUCCESS;
        }
 
+       /**
+        * Do some database updates after deletion
+        *
+        * @param $id Int: page_id value of the page being deleted (B/C, currently unused)
+        * @param $content Content: optional page content to be used when determining the required updates.
+        *        This may be needed because $this->getContent() may already return null when the page proper was deleted.
+        */
+       public function doDeleteUpdates( $id, Content $content = null ) {
+               # update site status
+               DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 1, - (int)$this->isCountable(), -1 ) );
+
+               # remove secondary indexes, etc
+               $updates = $this->getDeletionUpdates( $content );
+               DataUpdate::runUpdates( $updates );
+
+               # Clear caches
+               WikiPage::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 );
+       }
+
        /**
         * Roll back the most recent consecutive set of edits to a page
         * from the same user; fails if there are no eligible edits to
         * 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.
@@ -2866,92 +2872,7 @@ class WikiPage extends Page {
                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;
+               return $handler->getAutoDeleteReason( $this->getTitle(), $hasHistory );
        }
 
        /**
@@ -3193,12 +3114,26 @@ class WikiPage extends Page {
                return $this->isParserCacheUsed( ParserOptions::newFromUser( $wgUser ), $oldid );
        }
 
-       public function getDeletionUpdates() {
-               $updates = $this->getContentHandler()->getDeletionUpdates( $this );
+       /**
+        * Returns a list of updates to be performed when this page is deleted. The updates should remove any infomration
+        * about this page from secondary data stores such as links tables.
+        *
+        * @param Content|null $content optional Content object for determining the necessary updates
+        * @return Array an array of DataUpdates objects
+        */
+       public function getDeletionUpdates( Content $content = null ) {
+               if ( !$content ) {
+                       // load content object, which may be used to determine the necessary updates
+                       // XXX: the content may not be needed to determine the updates, then this would be overhead.
+                       $content = $this->getContent( Revision::RAW );
+               }
+
+               $updates = $this->getContentHandler()->getDeletionUpdates( $content, $this->mTitle );
 
                wfRunHooks( 'WikiPageDeletionUpdates', array( $this, &$updates ) );
                return $updates;
        }
+
 }
 
 class PoolWorkArticleView extends PoolCounterWork {
@@ -3224,9 +3159,9 @@ class PoolWorkArticleView extends PoolCounterWork {
        private $parserOptions;
 
        /**
-        * @var string|null
+        * @var Content|null
         */
-       private $text;
+       private $content = null;
 
        /**
         * @var ParserOutput|bool
@@ -3251,23 +3186,16 @@ 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, IContextSource $context = null ) {
+       function __construct( Page $page, ParserOptions $parserOptions, $revid, $useParserCache, $content = null ) {
                if ( is_string($content) ) { #BC: old style call
                        $modelId = $page->getRevision()->getContentModel();
                        $format = $page->getRevision()->getContentFormat();
                        $content = ContentHandler::makeContent( $content, $page->getTitle(), $modelId, $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;
@@ -3326,7 +3254,7 @@ class PoolWorkArticleView extends PoolCounterWork {
 
                $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 );
+               $this->parserOutput = $content->getParserOutput( $this->page->getTitle(), $this->revid, $this->parserOptions );
                $time += microtime( true );
 
                # Timing hack