Warn if stateful ParserOutput transforms are used
[lhc/web/wiklou.git] / includes / parser / ParserOutput.php
index 2dd4085..be574f0 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
         */
@@ -144,9 +150,10 @@ class ParserOutput extends CacheTime {
        public $mSections = [];
 
        /**
+        * @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.
@@ -164,6 +171,7 @@ class ParserOutput extends CacheTime {
        public $mTimestamp;
 
        /**
+        * @deprecated since 1.31 Use getText() options.
         * @var bool $mTOCEnabled Whether TOC should be shown, can't override __NOTOC__.
         */
        public $mTOCEnabled = true;
@@ -223,7 +231,7 @@ class ParserOutput extends CacheTime {
        // finalizeAdaptiveCacheExpiry() uses TTL = MAX( m * PARSE_TIME + b, MIN_AR_TTL)
        // Current values imply that m=3933.333333 and b=-333.333333
        // See https://www.nngroup.com/articles/website-response-times/
-       const PARSE_FAST_SEC = .100; // perceived "fast" page parse
+       const PARSE_FAST_SEC = 0.100; // perceived "fast" page parse
        const PARSE_SLOW_SEC = 1.0; // perceived "slow" page parse
        const FAST_AR_TTL = 60; // adaptive TTL for "fast" pages
        const SLOW_AR_TTL = 3600; // adaptive TTL for "slow" pages
@@ -243,22 +251,55 @@ class ParserOutput extends CacheTime {
         * return value is suitable for writing back via setText() but is not valid
         * for display to the user.
         *
+        * @return string
         * @since 1.27
         */
        public function getRawText() {
                return $this->mText;
        }
 
-       public function getText() {
+       /**
+        * Get the output HTML
+        *
+        * @param array $options (since 1.31) Transformations to apply to the HTML
+        *  - allowTOC: (bool) Show the TOC, assuming there were enough headings
+        *     to generate one and `__NOTOC__` wasn't used. Default is true,
+        *     but might be statefully overridden.
+        *  - enableSectionEditLinks: (bool) Include section edit links, assuming
+        *    section edit link tokens are present in the HTML. Default is true,
+        *     but might be statefully overridden.
+        * @return string HTML
+        */
+       public function getText( $options = [] ) {
+               if ( !array_key_exists( 'allowTOC', $options ) && empty( $this->mTOCEnabled ) ) {
+                       wfDeprecated( 'ParserOutput stateful allowTOC', '1.31' );
+               }
+
+               //  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.
+               if ( !array_key_exists( 'enableSectionEditLinks', $options ) && !$this->mEditSectionTokens ) {
+                       wfDeprecated( 'ParserOutput stateful enableSectionEditLinks', '1.31' );
+               }
+
+               $options += [
+                       // empty() here because old cached versions might lack the field somehow.
+                       // In that situation, the historical behavior (possibly buggy) is to remove the TOC.
+                       'allowTOC' => !empty( $this->mTOCEnabled ),
+                       'enableSectionEditLinks' => $this->mEditSectionTokens,
+               ];
                $text = $this->mText;
-               if ( $this->mEditSectionTokens ) {
+
+               Hooks::runWithoutAbort( 'ParserOutputPostCacheTransform', [ $this, &$text, &$options ] );
+
+               if ( $options['enableSectionEditLinks'] ) {
                        $text = preg_replace_callback(
                                self::EDITSECTION_REGEX,
                                function ( $m ) {
                                        global $wgOut, $wgLang;
                                        $editsectionPage = Title::newFromText( htmlspecialchars_decode( $m[1] ) );
                                        $editsectionSection = htmlspecialchars_decode( $m[2] );
-                                       $editsectionContent = isset( $m[4] ) ? $m[3] : null;
+                                       $editsectionContent = isset( $m[4] ) ? Sanitizer::decodeCharReferences( $m[3] ) : null;
 
                                        if ( !is_object( $editsectionPage ) ) {
                                                throw new MWException( "Bad parser output text." );
@@ -277,8 +318,7 @@ class ParserOutput extends CacheTime {
                        $text = preg_replace( self::EDITSECTION_REGEX, '', $text );
                }
 
-               // If you have an old cached version of this class - sorry, you can't disable the TOC
-               if ( isset( $this->mTOCEnabled ) && $this->mTOCEnabled ) {
+               if ( $options['allowTOC'] ) {
                        $text = str_replace( [ Parser::TOC_START, Parser::TOC_END ], '', $text );
                } else {
                        $text = preg_replace(
@@ -287,6 +327,7 @@ class ParserOutput extends CacheTime {
                                $text
                        );
                }
+
                return $text;
        }
 
@@ -298,7 +339,10 @@ class ParserOutput extends CacheTime {
                $this->mSpeculativeRevId = $id;
        }
 
-       /** @since 1.28 */
+       /**
+        * @return int|null
+        * @since 1.28
+        */
        public function getSpeculativeRevIdUsed() {
                return $this->mSpeculativeRevId;
        }
@@ -320,6 +364,7 @@ class ParserOutput extends CacheTime {
        }
 
        /**
+        * @return array
         * @since 1.25
         */
        public function getIndicators() {
@@ -334,6 +379,9 @@ class ParserOutput extends CacheTime {
                return $this->mSections;
        }
 
+       /**
+        * @deprecated since 1.31 Use getText() options.
+        */
        public function getEditSectionTokens() {
                return $this->mEditSectionTokens;
        }
@@ -382,7 +430,10 @@ class ParserOutput extends CacheTime {
                return $this->mModuleStyles;
        }
 
-       /** @since 1.23 */
+       /**
+        * @return array
+        * @since 1.23
+        */
        public function getJsConfigVars() {
                return $this->mJsConfigVars;
        }
@@ -418,6 +469,9 @@ class ParserOutput extends CacheTime {
                return $this->mLimitReportJSData;
        }
 
+       /**
+        * @deprecated since 1.31 Use getText() options.
+        */
        public function getTOCEnabled() {
                return $this->mTOCEnabled;
        }
@@ -446,6 +500,9 @@ class ParserOutput extends CacheTime {
                return wfSetVar( $this->mSections, $toc );
        }
 
+       /**
+        * @deprecated since 1.31 Use getText() options.
+        */
        public function setEditSectionTokens( $t ) {
                return wfSetVar( $this->mEditSectionTokens, $t );
        }
@@ -462,6 +519,9 @@ class ParserOutput extends CacheTime {
                return wfSetVar( $this->mTimestamp, $timestamp );
        }
 
+       /**
+        * @deprecated since 1.31 Use getText() options.
+        */
        public function setTOCEnabled( $flag ) {
                return wfSetVar( $this->mTOCEnabled, $flag );
        }
@@ -471,6 +531,8 @@ class ParserOutput extends CacheTime {
        }
 
        /**
+        * @param string $id
+        * @param string $content
         * @since 1.25
         */
        public function setIndicator( $id, $content ) {
@@ -836,6 +898,8 @@ class ParserOutput extends CacheTime {
         * @code
         *    $parser->getOutput()->my_ext_foo = '...';
         * @endcode
+        * @param string $name
+        * @param mixed $value
         */
        public function setProperty( $name, $value ) {
                $this->mProperties[$name] = $value;