MediaWiki master
PageConfigFactory.php
Go to the documentation of this file.
1<?php
2declare( strict_types = 1 );
10
11use MediaWiki\Languages\LanguageFactory;
23use Wikimedia\Bcp47Code\Bcp47Code;
25
32class PageConfigFactory extends \Wikimedia\Parsoid\Config\PageConfigFactory {
33 public function __construct(
34 private readonly RevisionStore $revisionStore,
35 private readonly SlotRoleRegistry $slotRoleRegistry,
36 private readonly LanguageFactory $languageFactory,
37 ) {
38 }
39
61 public function create(
62 PageIdentity $pageId,
63 ?UserIdentity $user = null,
64 $revision = null,
65 ?string $unused = null, /* Added to mollify CI with cross-repo uses */
66 ?Bcp47Code $pageLanguageOverride = null,
67 bool $ensureAccessibleContent = false
68 ): \Wikimedia\Parsoid\Config\PageConfig {
69 wfDeprecated( __METHOD__, '1.45' );
70 if ( $unused !== null ) {
71 wfDeprecated( __METHOD__ . ' with non-null 4th arg', '1.40' );
72 }
73
74 $parserOptions =
75 $user
77 : ParserOptions::newFromAnon();
78
79 return $this->createFromParserOptions(
80 $parserOptions, $pageId, $revision,
81 $pageLanguageOverride, $ensureAccessibleContent
82 );
83 }
84
105 public function createFromParserOptions(
106 ParserOptions $parserOptions,
107 PageIdentity $pageId,
108 $revision = null,
109 ?Bcp47Code $pageLanguageOverride = null,
110 bool $ensureAccessibleContent = false
111 ): \Wikimedia\Parsoid\Config\PageConfig {
112 $title = Title::newFromPageIdentity( $pageId );
113
114 if ( $revision === null ) {
115 // Fetch the 'latest' revision for the given title.
116 // Note: This initial fetch of the page context revision is
117 // *not* using Parser::fetchCurrentRevisionRecordOfTitle()
118 // (which usually invokes Parser::statelessFetchRevisionRecord
119 // and from there RevisionStore::getKnownCurrentRevision)
120 // because we don't have a Parser object to give to that callback.
121 // We could create one if needed for greater compatibility.
122 $revisionRecord = $this->revisionStore->getKnownCurrentRevision(
123 $title
124 ) ?: null;
125 // Note that $revisionRecord could still be null here if no
126 // page with that $title yet exists.
127 } elseif ( !is_int( $revision ) ) {
128 $revisionRecord = $revision;
129 } else {
130 if ( $revision === 0 ) {
131 // The client may explicitly provide 0 as the revision ID to indicate that
132 // the content doesn't belong to any saved revision, and provide wikitext
133 // in some way. Calling code should handle this case and provide a (fake)
134 // RevisionRecord based on the data in the request. If we get here, the
135 // code processing the request didn't handle this case properly.
136 throw new \UnexpectedValueException(
137 "Got revision ID 0 indicating unsaved content. " .
138 "Unsaved content must be provided as a RevisionRecord object."
139 );
140 }
141
142 // Fetch the correct revision record by the supplied id.
143 // This accesses the replica DB and may (or may not) fail over to
144 // the primary DB if the revision isn't found.
145 $revisionRecord = $this->revisionStore->getRevisionById( $revision );
146 if ( $revisionRecord === null ) {
147 // This revision really ought to exist. Check the primary DB.
148 // This *could* cause two requests to the primary DB if there
149 // were pending writes, but this codepath should be very rare.
150 // [T259855]
151 $revisionRecord = $this->revisionStore->getRevisionById(
152 $revision, IDBAccessObject::READ_LATEST
153 );
154 $success = ( $revisionRecord !== null ) ? 'success' : 'failure';
155 LoggerFactory::getInstance( 'Parsoid' )->error(
156 "Retried revision fetch after failure: {$success}", [
157 'id' => $revision,
158 'title' => $title->getPrefixedText(),
159 ]
160 );
161 }
162 if ( $revisionRecord === null ) {
163 throw new RevisionAccessException( "Can't find revision {$revision}" );
164 }
165 }
166
167 // If we have a revision record, check that we are allowed to see it.
168 // Mirrors the check from RevisionRecord::getContent
169 if (
170 $revisionRecord !== null &&
171 !$revisionRecord->audienceCan(
172 RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_PUBLIC
173 )
174 ) {
175 throw new SuppressedDataException( 'Not an available content version.' );
176 }
177
178 // Parsoid parser options should always have useParsoid set
179 $parserOptions->setUseParsoid();
180
181 $slotRoleHandler = $this->slotRoleRegistry->getRoleHandler( SlotRecord::MAIN );
182
183 if ( $pageLanguageOverride ) {
184 $pageLanguage = $this->languageFactory->getLanguage( $pageLanguageOverride );
185 $parserOptions->setTargetLanguage( $pageLanguage );
186 } else {
187 $pageLanguage = $title->getPageLanguage();
188 }
189
190 $pageConfig = new PageConfig(
191 $parserOptions,
192 $slotRoleHandler,
193 $title,
194 $revisionRecord,
195 $pageLanguage,
196 $pageLanguage->getDir()
197 );
198
199 if ( $ensureAccessibleContent ) {
200 if ( $revisionRecord === null ) {
201 // T234549
202 throw new RevisionAccessException( 'The specified revision does not exist.' );
203 }
204 // Try to get the content so that we can fail early. Otherwise,
205 // a RevisionAccessException is thrown. It's expensive, but the
206 // result will be cached for later calls.
207 $pageConfig->getRevisionContent()->getContent( SlotRecord::MAIN );
208 }
209
210 return $pageConfig;
211 }
212
213}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Create PSR-3 logger objects.
Set options of the Parser.
setUseParsoid(bool $value=true)
Request Parsoid-format HTML output.
setTargetLanguage( $x)
Target language for the parse.
static newFromUser( $user)
Get a ParserOptions object from a given user.
Helper class used by MediaWiki to create Parsoid PageConfig objects.
create(PageIdentity $pageId, ?UserIdentity $user=null, $revision=null, ?string $unused=null, ?Bcp47Code $pageLanguageOverride=null, bool $ensureAccessibleContent=false)
Create a new PageConfig.
createFromParserOptions(ParserOptions $parserOptions, PageIdentity $pageId, $revision=null, ?Bcp47Code $pageLanguageOverride=null, bool $ensureAccessibleContent=false)
Create a new PageConfig.
__construct(private readonly RevisionStore $revisionStore, private readonly SlotRoleRegistry $slotRoleRegistry, private readonly LanguageFactory $languageFactory,)
Page-level configuration interface for Parsoid.
Exception representing a failure to look up a revision.
Page revision base class.
Service for looking up page revisions.
Value object representing a content slot associated with a page revision.
A registry service for SlotRoleHandlers, used to define which slot roles are available on which page.
Exception raised in response to an audience check when attempting to access suppressed information wi...
Represents a title within MediaWiki.
Definition Title.php:69
Interface for configuration instances.
Definition Config.php:18
Interface for objects (potentially) representing an editable wiki page.
Interface for objects representing user identity.
Interface for database access objects.
Copyright (C) 2011-2022 Wikimedia Foundation and others.
Definition DataAccess.php:9