MediaWiki master
PageConfigFactory.php
Go to the documentation of this file.
1<?php
21
34use Wikimedia\Bcp47Code\Bcp47Code;
36
43class PageConfigFactory extends \Wikimedia\Parsoid\Config\PageConfigFactory {
44 private RevisionStore $revisionStore;
45 private SlotRoleRegistry $slotRoleRegistry;
46 private LanguageFactory $languageFactory;
47
53 public function __construct(
54 RevisionStore $revisionStore,
55 SlotRoleRegistry $slotRoleRegistry,
56 LanguageFactory $languageFactory
57 ) {
58 $this->revisionStore = $revisionStore;
59 $this->slotRoleRegistry = $slotRoleRegistry;
60 $this->languageFactory = $languageFactory;
61 }
62
83 public function create(
84 PageIdentity $pageId,
85 ?UserIdentity $user = null,
86 $revision = null,
87 ?string $unused = null, /* Added to mollify CI with cross-repo uses */
88 ?Bcp47Code $pageLanguageOverride = null,
89 bool $ensureAccessibleContent = false
90 ): \Wikimedia\Parsoid\Config\PageConfig {
91 $title = Title::newFromPageIdentity( $pageId );
92
93 if ( $unused !== null ) {
94 wfDeprecated( __METHOD__ . ' with non-null 4th arg', '1.40' );
95 }
96
97 if ( $revision === null ) {
98 // Fetch the 'latest' revision for the given title.
99 // Note: This initial fetch of the page context revision is
100 // *not* using Parser::fetchCurrentRevisionRecordOfTitle()
101 // (which usually invokes Parser::statelessFetchRevisionRecord
102 // and from there RevisionStore::getKnownCurrentRevision)
103 // because we don't have a Parser object to give to that callback.
104 // We could create one if needed for greater compatibility.
105 $revisionRecord = $this->revisionStore->getKnownCurrentRevision(
106 $title
107 ) ?: null;
108 // Note that $revisionRecord could still be null here if no
109 // page with that $title yet exists.
110 } elseif ( !is_int( $revision ) ) {
111 $revisionRecord = $revision;
112 } else {
113 if ( $revision === 0 ) {
114 // The client may explicitly provide 0 as the revision ID to indicate that
115 // the content doesn't belong to any saved revision, and provide wikitext
116 // in some way. Calling code should handle this case and provide a (fake)
117 // RevisionRecord based on the data in the request. If we get here, the
118 // code processing the request didn't handle this case properly.
119 throw new \UnexpectedValueException(
120 "Got revision ID 0 indicating unsaved content. " .
121 "Unsaved content must be provided as a RevisionRecord object."
122 );
123 }
124
125 // Fetch the correct revision record by the supplied id.
126 // This accesses the replica DB and may (or may not) fail over to
127 // the primary DB if the revision isn't found.
128 $revisionRecord = $this->revisionStore->getRevisionById( $revision );
129 if ( $revisionRecord === null ) {
130 // This revision really ought to exist. Check the primary DB.
131 // This *could* cause two requests to the primary DB if there
132 // were pending writes, but this codepath should be very rare.
133 // [T259855]
134 $revisionRecord = $this->revisionStore->getRevisionById(
135 $revision, IDBAccessObject::READ_LATEST
136 );
137 $success = ( $revisionRecord !== null ) ? 'success' : 'failure';
138 LoggerFactory::getInstance( 'Parsoid' )->error(
139 "Retried revision fetch after failure: {$success}", [
140 'id' => $revision,
141 'title' => $title->getPrefixedText(),
142 ]
143 );
144 }
145 if ( $revisionRecord === null ) {
146 throw new RevisionAccessException( "Can't find revision {$revision}" );
147 }
148 }
149
150 // If we have a revision record, check that we are allowed to see it.
151 // Mirrors the check from RevisionRecord::getContent
152 if (
153 $revisionRecord !== null &&
154 !$revisionRecord->audienceCan(
155 RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_PUBLIC
156 )
157 ) {
158 throw new SuppressedDataException( 'Not an available content version.' );
159 }
160
161 $parserOptions =
162 $user
164 : ParserOptions::newFromAnon();
165
166 // Turn off some options since Parsoid/JS currently doesn't
167 // do anything with this. As we proceed with closer integration,
168 // we can figure out if there is any value to these limit reports.
169 $parserOptions->setOption( 'enableLimitReport', false );
170
171 $slotRoleHandler = $this->slotRoleRegistry->getRoleHandler( SlotRecord::MAIN );
172 if ( $pageLanguageOverride ) {
173 $pageLanguage = $this->languageFactory->getLanguage( $pageLanguageOverride );
174 $parserOptions->setTargetLanguage( $pageLanguage );
175 } else {
176 $pageLanguage = $title->getPageLanguage();
177 }
178
179 $pageConfig = new PageConfig(
180 $parserOptions,
181 $slotRoleHandler,
182 $title,
183 $revisionRecord,
184 $pageLanguage,
185 $pageLanguage->getDir()
186 );
187
188 if ( $ensureAccessibleContent ) {
189 if ( $revisionRecord === null ) {
190 // T234549
191 throw new RevisionAccessException( 'The specified revision does not exist.' );
192 }
193 // Try to get the content so that we can fail early. Otherwise,
194 // a RevisionAccessException is thrown. It's expensive, but the
195 // result will be cached for later calls.
196 $pageConfig->getRevisionContent()->getContent( SlotRecord::MAIN );
197 }
198
199 return $pageConfig;
200 }
201
202}
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.
static newFromUser( $user)
Get a ParserOptions object from a given user.
Helper class used by MediaWiki to create Parsoid PageConfig objects.
__construct(RevisionStore $revisionStore, SlotRoleRegistry $slotRoleRegistry, LanguageFactory $languageFactory)
create(PageIdentity $pageId, ?UserIdentity $user=null, $revision=null, ?string $unused=null, ?Bcp47Code $pageLanguageOverride=null, bool $ensureAccessibleContent=false)
Create a new PageConfig.
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:78
Interface for configuration instances.
Definition Config.php:32
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.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...