MediaWiki master
ParsoidOutputAccess.php
Go to the documentation of this file.
1<?php
21
35use Wikimedia\Parsoid\Core\ClientError;
36use Wikimedia\Parsoid\Core\ResourceLimitExceededException;
37
52 private ParsoidParserFactory $parsoidParserFactory;
53 private PageLookup $pageLookup;
54 private RevisionLookup $revisionLookup;
55 private ParserOutputAccess $parserOutputAccess;
56 private SiteConfig $siteConfig;
57 private IContentHandlerFactory $contentHandlerFactory;
58
67 public function __construct(
68 ParsoidParserFactory $parsoidParserFactory,
69 ParserOutputAccess $parserOutputAccess,
70 PageLookup $pageLookup,
71 RevisionLookup $revisionLookup,
72 SiteConfig $siteConfig,
73 IContentHandlerFactory $contentHandlerFactory
74 ) {
75 $this->parsoidParserFactory = $parsoidParserFactory;
76 $this->parserOutputAccess = $parserOutputAccess;
77 $this->pageLookup = $pageLookup;
78 $this->revisionLookup = $revisionLookup;
79 $this->siteConfig = $siteConfig;
80 $this->contentHandlerFactory = $contentHandlerFactory;
81 }
82
92 public function getParserOutput(
93 PageIdentity $page,
94 ParserOptions $parserOpts,
95 $revision = null,
96 int $options = 0,
97 bool $lenientRevHandling = false
98 ): Status {
99 [ $page, $revision, $uncacheable ] = $this->resolveRevision( $page, $revision, $lenientRevHandling );
100
101 try {
102 if ( $uncacheable ) {
103 $options |= ParserOutputAccess::OPT_NO_UPDATE_CACHE;
104 }
105
106 $this->adjustParserOptions( $revision, $parserOpts );
107 $status = $this->parserOutputAccess->getParserOutput(
108 $page, $parserOpts, $revision, $options
109 );
110 } catch ( ClientError $e ) {
111 $status = Status::newFatal( 'parsoid-client-error', $e->getMessage() );
112 } catch ( ResourceLimitExceededException $e ) {
113 $status = Status::newFatal( 'parsoid-resource-limit-exceeded', $e->getMessage() );
114 }
115 return $status;
116 }
117
126 public function getCachedParserOutput(
127 PageIdentity $page,
128 ParserOptions $parserOpts,
129 $revision = null,
130 bool $lenientRevHandling = false
131 ): ?ParserOutput {
132 [ $page, $revision, $ignored ] = $this->resolveRevision( $page, $revision, $lenientRevHandling );
133
134 $this->adjustParserOptions( $revision, $parserOpts );
135 return $this->parserOutputAccess->getCachedParserOutput( $page, $parserOpts, $revision );
136 }
137
149 public function parseUncacheable(
150 PageIdentity $page,
151 ParserOptions $parserOpts,
152 $revision,
153 bool $lenientRevHandling = false
154 ): Status {
155 // NOTE: If we have a RevisionRecord already, just use it, there is no need to resolve $page to
156 // a PageRecord (and it may not be possible if the page doesn't exist).
157 if ( !$revision instanceof RevisionRecord ) {
158 [ $page, $revision, $ignored ] = $this->resolveRevision( $page, $revision, $lenientRevHandling );
159 }
160
161 // Enforce caller expectation
162 $revId = $revision->getId();
163 if ( $revId !== 0 && $revId !== null ) {
164 return Status::newFatal( 'parsoid-revision-access',
165 "parseUncacheable should not be called for a real revision" );
166 }
167
168 try {
169 // Since we aren't caching this output, there is no need to
170 // call setUseParsoid() here.
171 $parser = $this->parsoidParserFactory->create();
172 $parserOutput = $this->parsoidParserFactory->create()->parseFakeRevision(
173 $revision, $page, $parserOpts );
174 $parserOutput->updateCacheExpiry( 0 ); // Ensure this isn't accidentally cached
175 $status = Status::newGood( $parserOutput );
176 } catch ( RevisionAccessException $e ) {
177 return Status::newFatal( 'parsoid-revision-access', $e->getMessage() );
178 } catch ( ClientError $e ) {
179 $status = Status::newFatal( 'parsoid-client-error', $e->getMessage() );
180 } catch ( ResourceLimitExceededException $e ) {
181 $status = Status::newFatal( 'parsoid-resource-limit-exceeded', $e->getMessage() );
182 }
183 return $status;
184 }
185
193 private function resolveRevision( PageIdentity $page, $revision, bool $lenientRevHandling = false ): array {
194 $uncacheable = false;
195 if ( !$page instanceof PageRecord ) {
196 $name = "$page";
197 $page = $this->pageLookup->getPageByReference( $page );
198 if ( !$page ) {
199 throw new RevisionAccessException(
200 'Page {name} not found',
201 [ 'name' => $name ]
202 );
203 }
204 }
205
206 if ( $revision === null ) {
207 $revision = $page->getLatest();
208 }
209
210 if ( is_int( $revision ) ) {
211 $revId = $revision;
212 $revision = $this->revisionLookup->getRevisionById( $revId );
213
214 if ( !$revision ) {
215 throw new RevisionAccessException(
216 'Revision {revId} not found',
217 [ 'revId' => $revId ]
218 );
219 }
220 }
221
222 if ( $page->getId() !== $revision->getPageId() ) {
223 if ( $lenientRevHandling ) {
224 $page = $this->pageLookup->getPageById( $revision->getPageId() );
225 if ( !$page ) {
226 // This should ideally never trigger!
227 throw new \RuntimeException(
228 "Unexpected NULL page for pageid " . $revision->getPageId() .
229 " from revision " . $revision->getId()
230 );
231 }
232 // Don't cache this!
233 $uncacheable = true;
234 } else {
235 throw new RevisionAccessException(
236 'Revision {revId} does not belong to page {name}',
237 [ 'name' => $page->getDBkey(), 'revId' => $revision->getId() ]
238 );
239 }
240 }
241
242 return [ $page, $revision, $uncacheable ];
243 }
244
245 private function adjustParserOptions( RevisionRecord $revision, ParserOptions $parserOpts ): void {
246 $mainSlot = $revision->getSlot( SlotRecord::MAIN );
247 $contentModel = $mainSlot->getModel();
248 if ( $this->siteConfig->supportsContentModel( $contentModel ) ) {
249 // Since we know Parsoid supports this content model, explicitly
250 // call ParserOptions::setUseParsoid. This ensures that when
251 // we query the parser-cache, the right cache key is called.
252 // This is an optional transition step to using ParserOutputAccess.
253 $parserOpts->setUseParsoid();
254 }
255 }
256}
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
Service for getting rendered output of a given page.
ParserOutput is a rendering of a Content object or a message.
Site-level configuration for Parsoid.
MediaWiki service for getting rendered page content.
getCachedParserOutput(PageIdentity $page, ParserOptions $parserOpts, $revision=null, bool $lenientRevHandling=false)
parseUncacheable(PageIdentity $page, ParserOptions $parserOpts, $revision, bool $lenientRevHandling=false)
This is to be called only for parsing posted wikitext that is actually not part of any real revision.
getParserOutput(PageIdentity $page, ParserOptions $parserOpts, $revision=null, int $options=0, bool $lenientRevHandling=false)
__construct(ParsoidParserFactory $parsoidParserFactory, ParserOutputAccess $parserOutputAccess, PageLookup $pageLookup, RevisionLookup $revisionLookup, SiteConfig $siteConfig, IContentHandlerFactory $contentHandlerFactory)
Exception representing a failure to look up a revision.
Page revision base class.
Value object representing a content slot associated with a page revision.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
Set options of the Parser.
setUseParsoid()
Request Parsoid-format HTML output.
Interface for objects (potentially) representing an editable wiki page.
Service for looking up information about wiki pages.
Data record representing a page that is (or used to be, or could be) an editable page on a wiki.
Service for looking up page revisions.
Copyright (C) 2011-2022 Wikimedia Foundation and others.