MediaWiki master
PageConfigFactory.php
Go to the documentation of this file.
1<?php
2declare( strict_types = 1 );
10
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
106 public function createFromParserOptions(
107 ParserOptions $parserOptions,
108 PageIdentity $pageId,
109 $revision = null,
110 ?Bcp47Code $pageLanguageOverride = null,
111 bool $ensureAccessibleContent = false,
112 bool $checkAuthority = false
113 ): \Wikimedia\Parsoid\Config\PageConfig {
114 $title = Title::newFromPageIdentity( $pageId );
115
116 if ( $revision === null ) {
117 // Fetch the 'latest' revision for the given title.
118 // Note: This initial fetch of the page context revision is
119 // *not* using Parser::fetchCurrentRevisionRecordOfTitle()
120 // (which usually invokes Parser::defaultFetchRevisionRecord
121 // and from there RevisionStore::getKnownCurrentRevision)
122 // because we don't have a Parser object to give to that callback.
123 // We could create one if needed for greater compatibility.
124 $revisionRecord = $this->revisionStore->getKnownLatestRevision(
125 $title
126 ) ?: null;
127 // Note that $revisionRecord could still be null here if no
128 // page with that $title yet exists.
129 } elseif ( !is_int( $revision ) ) {
130 $revisionRecord = $revision;
131 } else {
132 if ( $revision === 0 ) {
133 // The client may explicitly provide 0 as the revision ID to indicate that
134 // the content doesn't belong to any saved revision, and provide wikitext
135 // in some way. Calling code should handle this case and provide a (fake)
136 // RevisionRecord based on the data in the request. If we get here, the
137 // code processing the request didn't handle this case properly.
138 throw new \UnexpectedValueException(
139 "Got revision ID 0 indicating unsaved content. " .
140 "Unsaved content must be provided as a RevisionRecord object."
141 );
142 }
143
144 // Fetch the correct revision record by the supplied id.
145 // This accesses the replica DB and may (or may not) fail over to
146 // the primary DB if the revision isn't found.
147 $revisionRecord = $this->revisionStore->getRevisionById( $revision );
148 if ( $revisionRecord === null ) {
149 // This revision really ought to exist. Check the primary DB.
150 // This *could* cause two requests to the primary DB if there
151 // were pending writes, but this codepath should be very rare.
152 // [T259855]
153 $revisionRecord = $this->revisionStore->getRevisionById(
154 $revision, IDBAccessObject::READ_LATEST
155 );
156 $success = ( $revisionRecord !== null ) ? 'success' : 'failure';
157 LoggerFactory::getInstance( 'Parsoid' )->error(
158 "Retried revision fetch after failure: {$success}", [
159 'id' => $revision,
160 'title' => $title->getPrefixedText(),
161 ]
162 );
163 }
164 if ( $revisionRecord === null ) {
165 throw new RevisionAccessException( "Can't find revision {$revision}" );
166 }
167 }
168
169 // If we have a revision record, check that we are allowed to see it.
170 // Mirrors the check from RevisionRecord::getContent
171 if (
172 $checkAuthority &&
173 $revisionRecord !== null &&
174 !$revisionRecord->audienceCan(
175 RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_PUBLIC
176 )
177 ) {
178 throw new SuppressedDataException( 'Not an available content version.' );
179 }
180
181 // Parsoid parser options should always have useParsoid set
182 $parserOptions->setUseParsoid();
183
184 $slotRoleHandler = $this->slotRoleRegistry->getRoleHandler( SlotRecord::MAIN );
185
186 if ( $pageLanguageOverride ) {
187 $pageLanguage = $this->languageFactory->getLanguage( $pageLanguageOverride );
188 $parserOptions->setTargetLanguage( $pageLanguage );
189 } else {
190 $pageLanguage = $title->getPageLanguage();
191 }
192
193 $pageConfig = new PageConfig(
194 $parserOptions,
195 $slotRoleHandler,
196 $title,
197 $revisionRecord,
198 $pageLanguage,
199 $pageLanguage->getDir()
200 );
201
202 if ( $ensureAccessibleContent ) {
203 if ( $revisionRecord === null ) {
204 // T234549
205 throw new RevisionAccessException( 'The specified revision does not exist.' );
206 }
207 // Try to get the content so that we can fail early. Otherwise,
208 // a RevisionAccessException is thrown. It's expensive, but the
209 // result will be cached for later calls.
210 $pageConfig->getRevisionContent()->getContent( SlotRecord::MAIN );
211 }
212
213 return $pageConfig;
214 }
215
216}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
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.
createFromParserOptions(ParserOptions $parserOptions, PageIdentity $pageId, $revision=null, ?Bcp47Code $pageLanguageOverride=null, bool $ensureAccessibleContent=false, bool $checkAuthority=false)
Create a new PageConfig.
create(PageIdentity $pageId, ?UserIdentity $user=null, $revision=null, ?string $unused=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