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
53 private ParsoidParserFactory $parsoidParserFactory;
54 private PageLookup $pageLookup;
55 private RevisionLookup $revisionLookup;
56 private ParserOutputAccess $parserOutputAccess;
57 private SiteConfig $siteConfig;
58 private IContentHandlerFactory $contentHandlerFactory;
59
68 public function __construct(
69 ParsoidParserFactory $parsoidParserFactory,
70 ParserOutputAccess $parserOutputAccess,
71 PageLookup $pageLookup,
72 RevisionLookup $revisionLookup,
73 SiteConfig $siteConfig,
74 IContentHandlerFactory $contentHandlerFactory
75 ) {
76 $this->parsoidParserFactory = $parsoidParserFactory;
77 $this->parserOutputAccess = $parserOutputAccess;
78 $this->pageLookup = $pageLookup;
79 $this->revisionLookup = $revisionLookup;
80 $this->siteConfig = $siteConfig;
81 $this->contentHandlerFactory = $contentHandlerFactory;
82 }
83
94 public function getParserOutput(
95 PageIdentity $page,
96 ParserOptions $parserOpts,
97 $revision = null,
98 int $options = 0,
99 bool $lenientRevHandling = false
100 ): Status {
101 wfDeprecated( __METHOD__, '1.43' );
102 [ $page, $revision, $uncacheable ] = $this->resolveRevision( $page, $revision, $lenientRevHandling );
103
104 try {
105 if ( $uncacheable ) {
106 $options |= ParserOutputAccess::OPT_NO_UPDATE_CACHE;
107 }
108
109 $this->adjustParserOptions( $revision, $parserOpts );
110 $status = $this->parserOutputAccess->getParserOutput(
111 $page, $parserOpts, $revision, $options
112 );
113 } catch ( ClientError $e ) {
114 $status = Status::newFatal( 'parsoid-client-error', $e->getMessage() );
115 } catch ( ResourceLimitExceededException $e ) {
116 $status = Status::newFatal( 'parsoid-resource-limit-exceeded', $e->getMessage() );
117 }
118 return $status;
119 }
120
130 public function getCachedParserOutput(
131 PageIdentity $page,
132 ParserOptions $parserOpts,
133 $revision = null,
134 bool $lenientRevHandling = false
135 ): ?ParserOutput {
136 wfDeprecated( __METHOD__, '1.43' );
137 [ $page, $revision, $ignored ] = $this->resolveRevision( $page, $revision, $lenientRevHandling );
138
139 $this->adjustParserOptions( $revision, $parserOpts );
140 return $this->parserOutputAccess->getCachedParserOutput( $page, $parserOpts, $revision );
141 }
142
155 public function parseUncacheable(
156 PageIdentity $page,
157 ParserOptions $parserOpts,
158 $revision,
159 bool $lenientRevHandling = false
160 ): Status {
161 wfDeprecated( __METHOD__, '1.43' );
162 // NOTE: If we have a RevisionRecord already, just use it, there is no need to resolve $page to
163 // a PageRecord (and it may not be possible if the page doesn't exist).
164 if ( !$revision instanceof RevisionRecord ) {
165 [ $page, $revision, $ignored ] = $this->resolveRevision( $page, $revision, $lenientRevHandling );
166 }
167
168 // Enforce caller expectation
169 $revId = $revision->getId();
170 if ( $revId !== 0 && $revId !== null ) {
171 return Status::newFatal( 'parsoid-revision-access',
172 "parseUncacheable should not be called for a real revision" );
173 }
174
175 try {
176 // Since we aren't caching this output, there is no need to
177 // call setUseParsoid() here.
178 $parser = $this->parsoidParserFactory->create();
179 $parserOutput = $this->parsoidParserFactory->create()->parseFakeRevision(
180 $revision, $page, $parserOpts );
181 $parserOutput->updateCacheExpiry( 0 ); // Ensure this isn't accidentally cached
182 $status = Status::newGood( $parserOutput );
183 } catch ( RevisionAccessException $e ) {
184 return Status::newFatal( 'parsoid-revision-access', $e->getMessage() );
185 } catch ( ClientError $e ) {
186 $status = Status::newFatal( 'parsoid-client-error', $e->getMessage() );
187 } catch ( ResourceLimitExceededException $e ) {
188 $status = Status::newFatal( 'parsoid-resource-limit-exceeded', $e->getMessage() );
189 }
190 return $status;
191 }
192
200 private function resolveRevision( PageIdentity $page, $revision, bool $lenientRevHandling = false ): array {
201 $uncacheable = false;
202 if ( !$page instanceof PageRecord ) {
203 $name = "$page";
204 $page = $this->pageLookup->getPageByReference( $page );
205 if ( !$page ) {
206 throw new RevisionAccessException(
207 'Page {name} not found',
208 [ 'name' => $name ]
209 );
210 }
211 }
212
213 if ( $revision === null ) {
214 $revision = $page->getLatest();
215 }
216
217 if ( is_int( $revision ) ) {
218 $revId = $revision;
219 $revision = $this->revisionLookup->getRevisionById( $revId );
220
221 if ( !$revision ) {
222 throw new RevisionAccessException(
223 'Revision {revId} not found',
224 [ 'revId' => $revId ]
225 );
226 }
227 }
228
229 if ( $page->getId() !== $revision->getPageId() ) {
230 if ( $lenientRevHandling ) {
231 $page = $this->pageLookup->getPageById( $revision->getPageId() );
232 if ( !$page ) {
233 // This should ideally never trigger!
234 throw new \RuntimeException(
235 "Unexpected NULL page for pageid " . $revision->getPageId() .
236 " from revision " . $revision->getId()
237 );
238 }
239 // Don't cache this!
240 $uncacheable = true;
241 } else {
242 throw new RevisionAccessException(
243 'Revision {revId} does not belong to page {name}',
244 [ 'name' => $page->getDBkey(), 'revId' => $revision->getId() ]
245 );
246 }
247 }
248
249 return [ $page, $revision, $uncacheable ];
250 }
251
252 private function adjustParserOptions( RevisionRecord $revision, ParserOptions $parserOpts ): void {
253 $mainSlot = $revision->getSlot( SlotRecord::MAIN );
254 $contentModel = $mainSlot->getModel();
255 if ( $this->siteConfig->supportsContentModel( $contentModel ) ) {
256 // Since we know Parsoid supports this content model, explicitly
257 // call ParserOptions::setUseParsoid. This ensures that when
258 // we query the parser-cache, the right cache key is called.
259 // This is an optional transition step to using ParserOutputAccess.
260 $parserOpts->setUseParsoid();
261 }
262 }
263}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
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.