Use ParserOutput stateless transforms
authorBrad Jorsch <bjorsch@wikimedia.org>
Wed, 22 Nov 2017 20:07:51 +0000 (15:07 -0500)
committerBrad Jorsch <bjorsch@wikimedia.org>
Thu, 30 Nov 2017 19:27:49 +0000 (14:27 -0500)
We still set the state in many cases for benefit of extensions, but all
calls within core should no longer be using non-default state.

Change-Id: I78b62ec33fcb8273acb9b3b4e9012215442be94c
Depends-On: I140ff32373430b61b92226689ef9b58cca317450

13 files changed:
includes/EditPage.php
includes/Message.php
includes/OutputPage.php
includes/Status.php
includes/api/ApiParse.php
includes/content/WikiTextStructure.php
includes/diff/DifferenceEngine.php
includes/installer/Installer.php
includes/page/Article.php
includes/parser/ParserOutput.php
includes/specials/SpecialRecentchanges.php
includes/specials/SpecialUndelete.php
tests/parser/ParserTestRunner.php

index ff224c5..bcaab3a 100644 (file)
@@ -4012,7 +4012,10 @@ class EditPage {
                $parserOutput->setEditSectionTokens( false ); // no section edit links
                return [
                        'parserOutput' => $parserOutput,
-                       'html' => $parserOutput->getText() ];
+                       'html' => $parserOutput->getText( [
+                               'enableSectionEditLinks' => false
+                       ] )
+               ];
        }
 
        /**
index 3b2f3cc..16ae839 100644 (file)
@@ -1244,7 +1244,9 @@ class Message implements MessageSpecifier, Serializable {
                        $this->getLanguage()
                );
 
-               return $out instanceof ParserOutput ? $out->getText() : $out;
+               return $out instanceof ParserOutput
+                       ? $out->getText( [ 'enableSectionEditLinks' => false ] )
+                       : $out;
        }
 
        /**
index a5f9c18..92963fd 100644 (file)
@@ -1783,7 +1783,9 @@ class OutputPage extends ContextSource {
 
                $popts->setTidy( $oldTidy );
 
-               $this->addParserOutput( $parserOutput );
+               $this->addParserOutput( $parserOutput, [
+                       'enableSectionEditLinks' => false,
+               ] );
        }
 
        /**
@@ -1868,9 +1870,10 @@ class OutputPage extends ContextSource {
         *
         * @since 1.24
         * @param ParserOutput $parserOutput
+        * @param array $poOptions Options to ParserOutput::getText()
         */
-       public function addParserOutputContent( $parserOutput ) {
-               $this->addParserOutputText( $parserOutput );
+       public function addParserOutputContent( $parserOutput, $poOptions = [] ) {
+               $this->addParserOutputText( $parserOutput, $poOptions );
 
                $this->addModules( $parserOutput->getModules() );
                $this->addModuleScripts( $parserOutput->getModuleScripts() );
@@ -1884,9 +1887,10 @@ class OutputPage extends ContextSource {
         *
         * @since 1.24
         * @param ParserOutput $parserOutput
+        * @param array $poOptions Options to ParserOutput::getText()
         */
-       public function addParserOutputText( $parserOutput ) {
-               $text = $parserOutput->getText();
+       public function addParserOutputText( $parserOutput, $poOptions = [] ) {
+               $text = $parserOutput->getText( $poOptions );
                // Avoid PHP 7.1 warning of passing $this by reference
                $outputPage = $this;
                Hooks::runWithoutAbort( 'OutputPageBeforeHTML', [ &$outputPage, &$text ] );
@@ -1897,16 +1901,22 @@ class OutputPage extends ContextSource {
         * Add everything from a ParserOutput object.
         *
         * @param ParserOutput $parserOutput
+        * @param array $poOptions Options to ParserOutput::getText()
         */
-       function addParserOutput( $parserOutput ) {
+       function addParserOutput( $parserOutput, $poOptions = [] ) {
                $this->addParserOutputMetadata( $parserOutput );
 
                // Touch section edit links only if not previously disabled
                if ( $parserOutput->getEditSectionTokens() ) {
                        $parserOutput->setEditSectionTokens( $this->mEnableSectionEditLinks );
                }
+               if ( !$this->mEnableSectionEditLinks
+                       && !array_key_exists( 'enableSectionEditLinks', $poOptions )
+               ) {
+                       $poOptions['enableSectionEditLinks'] = false;
+               }
 
-               $this->addParserOutputText( $parserOutput );
+               $this->addParserOutputText( $parserOutput, $poOptions );
        }
 
        /**
@@ -1957,7 +1967,9 @@ class OutputPage extends ContextSource {
                        $popts->setTargetLanguage( $oldLang );
                }
 
-               return $parserOutput->getText();
+               return $parserOutput->getText( [
+                       'enableSectionEditLinks' => false,
+               ] );
        }
 
        /**
@@ -3957,6 +3969,7 @@ class OutputPage extends ContextSource {
         * Enables/disables section edit links, doesn't override __NOEDITSECTION__
         * @param bool $flag
         * @since 1.23
+        * @deprecated since 1.31, use $poOptions to addParserOutput() instead.
         */
        public function enableSectionEditLinks( $flag = true ) {
                $this->mEnableSectionEditLinks = $flag;
@@ -3965,6 +3978,7 @@ class OutputPage extends ContextSource {
        /**
         * @return bool
         * @since 1.23
+        * @deprecated since 1.31, use $poOptions to addParserOutput() instead.
         */
        public function sectionEditLinksEnabled() {
                return $this->mEnableSectionEditLinks;
index a35af6e..f17f173 100644 (file)
@@ -316,7 +316,9 @@ class Status extends StatusValue {
                $lang = $this->languageFromParam( $lang );
                $text = $this->getWikiText( $shortContext, $longContext, $lang );
                $out = MessageCache::singleton()->parse( $text, null, true, true, $lang );
-               return $out instanceof ParserOutput ? $out->getText() : $out;
+               return $out instanceof ParserOutput
+                       ? $out->getText( [ 'enableSectionEditLinks' => false ] )
+                       : $out;
        }
 
        /**
index 15b94fb..ec015da 100644 (file)
@@ -288,10 +288,6 @@ class ApiParse extends ApiBase {
                        $result_array['textsuppressed'] = true;
                }
 
-               if ( $params['disabletoc'] ) {
-                       $p_result->setTOCEnabled( false );
-               }
-
                if ( isset( $params['useskin'] ) ) {
                        $factory = MediaWikiServices::getInstance()->getSkinFactory();
                        $skin = $factory->makeSkin( Skin::normalizeKey( $params['useskin'] ) );
@@ -347,7 +343,10 @@ class ApiParse extends ApiBase {
                }
 
                if ( isset( $prop['text'] ) ) {
-                       $result_array['text'] = $p_result->getText();
+                       $result_array['text'] = $p_result->getText( [
+                               'allowTOC' => !$params['disabletoc'],
+                               'enableSectionEditLinks' => !$params['disableeditsection'],
+                       ] );
                        $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
                }
 
index aeb96b6..0eadc3c 100644 (file)
@@ -146,9 +146,10 @@ class WikiTextStructure {
                if ( !is_null( $this->allText ) ) {
                        return;
                }
-               $this->parserOutput->setEditSectionTokens( false );
-               $this->parserOutput->setTOCEnabled( false );
-               $text = $this->parserOutput->getText();
+               $text = $this->parserOutput->getText( [
+                       'enableSectionEditTokens' => false,
+                       'allowTOC' => false,
+               ] );
                if ( strlen( $text ) == 0 ) {
                        $this->allText = "";
                        // empty text - nothing to seek here
index 51b9f15..7e05be6 100644 (file)
@@ -634,7 +634,10 @@ class DifferenceEngine extends ContextSource {
                                        if ( Hooks::run( 'DifferenceEngineRenderRevisionAddParserOutput',
                                                [ $this, $out, $parserOutput, $wikiPage ] )
                                        ) {
-                                               $out->addParserOutput( $parserOutput );
+                                               $out->addParserOutput( $parserOutput, [
+                                                       'enableSectionEditLinks' => $this->mNewRev->isCurrent()
+                                                               && $this->mNewRev->getTitle()->quickUserCan( 'edit', $this->getUser() ),
+                                               ] );
                                        }
                                }
                        }
index 2906a83..46978e1 100644 (file)
@@ -688,7 +688,9 @@ abstract class Installer {
 
                try {
                        $out = $wgParser->parse( $text, $this->parserTitle, $this->parserOptions, $lineStart );
-                       $html = $out->getText();
+                       $html = $out->getText( [
+                               'enableSectionEditLinks' => false,
+                       ] );
                } catch ( MediaWiki\Services\ServiceDisabledException $e ) {
                        $html = '<!--DB access attempted during parse-->  ' . htmlspecialchars( $text );
 
index c9dc273..dadf311 100644 (file)
@@ -75,6 +75,13 @@ class Article implements Page {
        /** @var ParserOutput */
        public $mParserOutput;
 
+       /**
+        * @var bool Whether render() was called. With the way subclasses work
+        * here, there doesn't seem to be any other way to stop calling
+        * OutputPage::enableSectionEditLinks() and still have it work as it did before.
+        */
+       private $disableSectionEditForRender = false;
+
        /**
         * Constructor and clear the article
         * @param Title $title Reference to a Title object.
@@ -469,12 +476,17 @@ class Article implements Page {
                $parserCache = MediaWikiServices::getInstance()->getParserCache();
 
                $parserOptions = $this->getParserOptions();
+               $poOptions = [];
                # Render printable version, use printable version cache
                if ( $outputPage->isPrintable() ) {
                        $parserOptions->setIsPrintable( true );
                        $parserOptions->setEditSection( false );
-               } elseif ( !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit', $user ) ) {
+                       $poOptions['enableSectionEditLinks'] = false;
+               } elseif ( $this->disableSectionEditForRender
+                       || !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit', $user )
+               ) {
                        $parserOptions->setEditSection( false );
+                       $poOptions['enableSectionEditLinks'] = false;
                }
 
                # Try client and file cache
@@ -533,7 +545,7 @@ class Article implements Page {
                                                        } else {
                                                                wfDebug( __METHOD__ . ": showing parser cache contents\n" );
                                                        }
-                                                       $outputPage->addParserOutput( $this->mParserOutput );
+                                                       $outputPage->addParserOutput( $this->mParserOutput, $poOptions );
                                                        # Ensure that UI elements requiring revision ID have
                                                        # the correct version information.
                                                        $outputPage->setRevisionId( $this->mPage->getLatest() );
@@ -597,7 +609,7 @@ class Article implements Page {
                                        }
 
                                        $this->mParserOutput = $poolArticleView->getParserOutput();
-                                       $outputPage->addParserOutput( $this->mParserOutput );
+                                       $outputPage->addParserOutput( $this->mParserOutput, $poOptions );
                                        if ( $content->getRedirectTarget() ) {
                                                $outputPage->addSubtitle( "<span id=\"redirectsub\">" .
                                                        $this->getContext()->msg( 'redirectpagesub' )->parse() . "</span>" );
@@ -1515,6 +1527,7 @@ class Article implements Page {
                $this->getContext()->getRequest()->response()->header( 'X-Robots-Tag: noindex' );
                $this->getContext()->getOutput()->setArticleBodyOnly( true );
                $this->getContext()->getOutput()->enableSectionEditLinks( false );
+               $this->disableSectionEditForRender = true;
                $this->view();
        }
 
index 59c27e5..ff9c28d 100644 (file)
  * @ingroup Parser
  */
 class ParserOutput extends CacheTime {
+       /**
+        * Feature flag to indicate to extensions that MediaWiki core supports and
+        * uses getText() stateless transforms.
+        */
+       const SUPPORTS_STATELESS_TRANSFORMS = 1;
+
        /**
         * @var string $mText The output text
         */
@@ -147,7 +153,7 @@ class ParserOutput extends CacheTime {
         * @deprecated since 1.31 Use getText() options.
         * @var bool $mEditSectionTokens prefix/suffix markers if edit sections were output as tokens.
         */
-       public $mEditSectionTokens = false;
+       public $mEditSectionTokens = true;
 
        /**
         * @var array $mProperties Name/value pairs to be cached in the DB.
@@ -269,7 +275,7 @@ class ParserOutput extends CacheTime {
 
                // @todo Warn if !array_key_exists( 'enableSectionEditLinks', $options )
                //     && !$this->mEditSectionTokens
-               //  Note that while $this->mEditSectionTokens defaults to false,
+               //  Note that while $this->mEditSectionTokens formerly defaulted to false,
                //  ParserOptions->getEditSection() defaults to true and Parser copies
                //  that to us so true makes more sense as the stateless default.
 
index dfa13b6..cfc7a85 100644 (file)
@@ -608,7 +608,9 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
                                /*interface*/false,
                                $wgContLang
                        );
-                       $content = $parserOutput->getText();
+                       $content = $parserOutput->getText( [
+                               'enableSectionEditLinks' => false,
+                       ] );
                        // Add only metadata here (including the language links), text is added below
                        $this->getOutput()->addParserOutputMetadata( $parserOutput );
 
index 71dee3d..0c038c1 100644 (file)
@@ -455,7 +455,9 @@ class SpecialUndelete extends SpecialPage {
                        $popts->setEditSection( false );
 
                        $pout = $content->getParserOutput( $this->mTargetObj, $rev->getId(), $popts, true );
-                       $out->addParserOutput( $pout );
+                       $out->addParserOutput( $pout, [
+                               'enableSectionEditLinks' => false,
+                       ] );
                }
 
                if ( $isText ) {
index 149ba80..44a00a8 100644 (file)
@@ -853,8 +853,9 @@ class ParserTestRunner {
                        $out = $parser->getPreloadText( $test['input'], $title, $options );
                } else {
                        $output = $parser->parse( $test['input'], $title, $options, true, true, 1337 );
-                       $output->setTOCEnabled( !isset( $opts['notoc'] ) );
-                       $out = $output->getText();
+                       $out = $output->getText( [
+                               'allowTOC' => !isset( $opts['notoc'] )
+                       ] );
                        if ( isset( $opts['tidy'] ) ) {
                                $out = preg_replace( '/\s+$/', '', $out );
                        }