Use stashed ParserOutput during saving.
[lhc/web/wiklou.git] / includes / Revision / RevisionRenderer.php
index 8f44a19..265ad13 100644 (file)
@@ -24,7 +24,6 @@ namespace MediaWiki\Revision;
 
 use Html;
 use InvalidArgumentException;
-use MediaWiki\Storage\RevisionRecord;
 use ParserOptions;
 use ParserOutput;
 use Psr\Log\LoggerInterface;
@@ -65,6 +64,13 @@ class RevisionRenderer {
                $this->saveParseLogger = new NullLogger();
        }
 
+       /**
+        * @param LoggerInterface $saveParseLogger
+        */
+       public function setLogger( LoggerInterface $saveParseLogger ) {
+               $this->saveParseLogger = $saveParseLogger;
+       }
+
        /**
         * @param RevisionRecord $rev
         * @param ParserOptions|null $options
@@ -76,6 +82,11 @@ class RevisionRenderer {
         *      - 'audience' the audience to use for content access. Default is
         *        RevisionRecord::FOR_PUBLIC if $forUser is not set, RevisionRecord::FOR_THIS_USER
         *        if $forUser is set. Can be set to RevisionRecord::RAW to disable audience checks.
+        *      - 'known-revision-output' a combined ParserOutput for the revision, perhaps from
+        *        some cache. the caller is responsible for ensuring that the ParserOutput indeed
+        *        matched the $rev and $options. This mechanism is intended as a temporary stop-gap,
+        *        for the time until caches have been changed to store RenderedRevision states instead
+        *        of ParserOutput objects.
         *
         * @return RenderedRevision|null The rendered revision, or null if the audience checks fails.
         */
@@ -118,8 +129,8 @@ class RevisionRenderer {
                        $title,
                        $rev,
                        $options,
-                       function ( RenderedRevision $rrev ) {
-                               return $this->combineSlotOutput( $rrev );
+                       function ( RenderedRevision $rrev, array $hints ) {
+                               return $this->combineSlotOutput( $rrev, $hints );
                        },
                        $audience,
                        $forUser
@@ -127,6 +138,10 @@ class RevisionRenderer {
 
                $renderedRevision->setSaveParseLogger( $this->saveParseLogger );
 
+               if ( isset( $hints['known-revision-output'] ) ) {
+                       $renderedRevision->setRevisionParserOutput( $hints['known-revision-output'] );
+               }
+
                return $renderedRevision;
        }
 
@@ -154,54 +169,65 @@ class RevisionRenderer {
         * @todo Use placement hints from SlotRoleHandlers instead of hard-coding the layout.
         *
         * @param RenderedRevision $rrev
+        * @param array $hints see RenderedRevision::getRevisionParserOutput()
+        *
         * @return ParserOutput
         */
-       private function combineSlotOutput( RenderedRevision $rrev ) {
+       private function combineSlotOutput( RenderedRevision $rrev, array $hints = [] ) {
                $revision = $rrev->getRevision();
                $slots = $revision->getSlots()->getSlots();
 
+               $withHtml = $hints['generate-html'] ?? true;
+
                // short circuit if there is only the main slot
-               if ( array_keys( $slots ) === [ 'main' ] ) {
-                       return $rrev->getSlotParserOutput( 'main' );
+               if ( array_keys( $slots ) === [ SlotRecord::MAIN ] ) {
+                       return $rrev->getSlotParserOutput( SlotRecord::MAIN );
                }
 
                // TODO: put fancy layout logic here, see T200915.
 
                // move main slot to front
-               if ( isset( $slots['main'] ) ) {
-                       $slots = [ 'main' => $slots['main'] ] + $slots;
+               if ( isset( $slots[SlotRecord::MAIN] ) ) {
+                       $slots = [ SlotRecord::MAIN => $slots[SlotRecord::MAIN] ] + $slots;
                }
 
-               $output = new ParserOutput();
+               $combinedOutput = new ParserOutput( null );
+               $slotOutput = [];
+
                $options = $rrev->getOptions();
-               $options->registerWatcher( [ $output, 'recordOption' ] );
+               $options->registerWatcher( [ $combinedOutput, 'recordOption' ] );
 
-               $html = '';
-               $first = true;
                foreach ( $slots as $role => $slot ) {
+                       $out = $rrev->getSlotParserOutput( $role, $hints );
+                       $slotOutput[$role] = $out;
 
-                       if ( $first ) {
-                               // skip header for the first slot
-                               $first = false;
-                       } else {
-                               // NOTE: this placeholder is hydrated by ParserOutput::getText().
-                               $headText = Html::element( 'mw:slotheader', [], $role );
-                               $html .= Html::rawElement( 'h1', [ 'class' => 'mw-slot-header' ], $headText );
-                       }
-
-                       $slotOutput = $rrev->getSlotParserOutput( $role );
+                       $combinedOutput->mergeInternalMetaDataFrom( $out, $role );
+                       $combinedOutput->mergeTrackingMetaDataFrom( $out );
+               }
 
-                       $html .= $slotOutput->getRawText();
+               if ( $withHtml ) {
+                       $html = '';
+                       $first = true;
+                       /** @var ParserOutput $out */
+                       foreach ( $slotOutput as $role => $out ) {
+                               if ( $first ) {
+                                       // skip header for the first slot
+                                       $first = false;
+                               } else {
+                                       // NOTE: this placeholder is hydrated by ParserOutput::getText().
+                                       $headText = Html::element( 'mw:slotheader', [], $role );
+                                       $html .= Html::rawElement( 'h1', [ 'class' => 'mw-slot-header' ], $headText );
+                               }
+
+                               $html .= $out->getRawText();
+                               $combinedOutput->mergeHtmlMetaDataFrom( $out );
+                       }
 
-                       $output->mergeInternalMetaDataFrom( $slotOutput );
-                       $output->mergeHtmlMetaDataFrom( $slotOutput );
-                       $output->mergeTrackingMetaDataFrom( $slotOutput );
+                       $combinedOutput->setText( $html );
                }
 
-               $output->setText( $html );
-
                $options->registerWatcher( null );
-               return $output;
+               return $combinedOutput;
        }
 
 }