63 private $performer =
null;
69 private $revisionOutput =
null;
75 private $slotsOutput = [];
81 private $combineOutput;
86 private $saveParseLogger;
91 private $contentRenderer;
113 callable $combineOutput,
117 $this->options = $options;
119 $this->setRevisionInternal( $revision );
121 $this->contentRenderer = $contentRenderer;
122 $this->combineOutput = $combineOutput;
123 $this->saveParseLogger =
new NullLogger();
126 throw new InvalidArgumentException(
127 'User must be specified when setting audience to FOR_THIS_USER'
131 $this->audience = $audience;
132 $this->performer = $performer;
139 $this->saveParseLogger = $saveParseLogger;
153 return $this->revision;
160 return $this->options;
174 $this->revisionOutput = $output;
194 $withHtml = $hints[
'generate-html'] ??
true;
196 if ( !$this->revisionOutput
197 || ( $withHtml && !$this->revisionOutput->hasText() )
199 $output = call_user_func( $this->combineOutput, $this, $hints );
201 Assert::postcondition(
203 'Callback did not return a ParserOutput object!'
206 $this->revisionOutput = $output;
209 return $this->revisionOutput;
224 $withHtml = $hints[
'generate-html'] ??
true;
226 if ( !isset( $this->slotsOutput[ $role ] )
227 || ( $withHtml && !$this->slotsOutput[ $role ]->hasText() )
229 $content = $this->revision->getContentOrThrow( $role, $this->audience, $this->performer );
232 $output = $this->getSlotParserOutputUncached(
$content, $withHtml );
234 if ( $withHtml && !$output->hasText() ) {
235 throw new LogicException(
236 'HTML generation was requested, but '
239 .
'ContentRenderer::getParserOutput() returns a ParserOutput with no text set.'
244 $this->options->registerWatcher(
null );
246 $this->slotsOutput[ $role ] = $output;
249 return $this->slotsOutput[$role];
258 private function getSlotParserOutputUncached(
Content $content, $withHtml ) {
259 $parserOutput = $this->contentRenderer->getParserOutput(
261 $this->revision->getPage(),
262 $this->revision->getId(),
268 $parserOutput->
setTimestamp( $this->revision->getTimestamp() );
269 return $parserOutput;
282 if ( $rev->
getId() === $this->revision->getId() ) {
286 if ( $this->revision->getId() ) {
287 throw new LogicException(
'RenderedRevision already has a revision with ID '
288 . $this->revision->getId() .
', can\'t update to revision with ID ' . $rev->
getId() );
291 if ( !$this->revision->getSlots()->hasSameContent( $rev->
getSlots() ) ) {
292 throw new LogicException(
'Cannot update to a revision with different content!' );
295 $this->setRevisionInternal( $rev );
297 $this->pruneRevisionSensitiveOutput(
298 $this->revision->getPageId(),
299 $this->revision->getId(),
300 $this->revision->getTimestamp()
317 private function pruneRevisionSensitiveOutput(
322 if ( $this->revisionOutput ) {
323 if ( $this->outputVariesOnRevisionMetaData(
324 $this->revisionOutput,
329 $this->revisionOutput =
null;
332 $this->saveParseLogger->debug( __METHOD__ .
": no prepared revision output" );
335 foreach ( $this->slotsOutput as $role => $output ) {
336 if ( $this->outputVariesOnRevisionMetaData(
342 unset( $this->slotsOutput[$role] );
350 private function setRevisionInternal( RevisionRecord $revision ) {
351 $this->revision = $revision;
383 if ( $this->revision->isReadyForInsertion() || !$this->revision->getId() ) {
384 $oldCallback = $this->options->getCurrentRevisionRecordCallback();
385 $this->options->setCurrentRevisionRecordCallback(
386 function ( PageReference $parserPage, $parser =
null ) use ( $oldCallback ) {
387 if ( $this->revision->getPage()->isSamePageAs( $parserPage ) ) {
388 return $this->revision;
390 return call_user_func( $oldCallback, $parserPage, $parser );
410 private function outputVariesOnRevisionMetaData(
416 $logger = $this->saveParseLogger;
417 $varyMsg = __METHOD__ .
": cannot use prepared output for '{title}'";
418 $context = [
'title' => (string)$this->revision->getPage() ];
420 if ( $parserOutput->
getOutputFlag( ParserOutputFlags::VARY_REVISION ) ) {
422 $logger->info(
"$varyMsg (vary-revision)", $context );
425 $parserOutput->
getOutputFlag( ParserOutputFlags::VARY_REVISION_ID )
426 && $actualRevId !==
false
429 $logger->info(
"$varyMsg (vary-revision-id and wrong ID)", $context );
432 $parserOutput->
getOutputFlag( ParserOutputFlags::VARY_REVISION_TIMESTAMP )
433 && $actualRevTimestamp !==
false
434 && ( $actualRevTimestamp ===
true ||
437 $logger->info(
"$varyMsg (vary-revision-timestamp and wrong timestamp)", $context );
440 $parserOutput->
getOutputFlag( ParserOutputFlags::VARY_PAGE_ID )
441 && $actualPageId !==
false
444 $logger->info(
"$varyMsg (vary-page-id and wrong ID)", $context );
446 } elseif ( $parserOutput->
getOutputFlag( ParserOutputFlags::VARY_REVISION_EXISTS ) ) {
450 $logger->info(
"$varyMsg (vary-revision-exists)", $context );
453 $parserOutput->
getOutputFlag( ParserOutputFlags::VARY_REVISION_SHA1 ) &&
458 $logger->info(
"$varyMsg (vary-revision-sha1 with wrong SHA-1)", $context );
469 $logger->debug( __METHOD__ .
": reusing prepared output for '{title}'", $context );
Base interface for representing page content.