Localisation updates from https://translatewiki.net.
[mediawiki.git] / includes / content / ContentHandlerFactory.php
blobb132d8f2d1523a4ae641b360eab2f28937fd99fb
1 <?php
3 /**
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 * http://www.gnu.org/copyleft/gpl.html
19 * @file
20 * @ingroup Content
22 * @author Art Baltai
25 namespace MediaWiki\Content;
27 use InvalidArgumentException;
28 use MediaWiki\HookContainer\HookContainer;
29 use MediaWiki\HookContainer\HookRunner;
30 use MWUnknownContentModelException;
31 use Psr\Log\LoggerInterface;
32 use Wikimedia\ObjectFactory\ObjectFactory;
34 /**
35 * Class ContentHandlerFactory
36 * @package MediaWiki\Content
37 * @ingroup Content
38 * @since 1.35
40 final class ContentHandlerFactory implements IContentHandlerFactory {
42 /**
43 * @var string[]|callable[]
45 private $handlerSpecs;
47 /**
48 * @var ContentHandler[] Registry of ContentHandler instances by model id
50 private $handlersByModel = [];
52 /** @var ObjectFactory */
53 private $objectFactory;
55 /** @var HookRunner */
56 private $hookRunner;
58 /** @var LoggerInterface */
59 private $logger;
61 /**
62 * @since 1.35
63 * @internal Use @see MediaWikiServices::getContentHandlerFactory
65 * @param string[]|callable[] $handlerSpecs An associative array mapping each known
66 * content model to the ObjectFactory spec used to construct its ContentHandler.
67 * This array typically comes from $wgContentHandlers.
68 * @param ObjectFactory $objectFactory
69 * @param HookContainer $hookContainer
70 * @param LoggerInterface $logger
72 public function __construct(
73 array $handlerSpecs,
74 ObjectFactory $objectFactory,
75 HookContainer $hookContainer,
76 LoggerInterface $logger
77 ) {
78 $this->handlerSpecs = $handlerSpecs;
79 $this->objectFactory = $objectFactory;
80 $this->hookRunner = new HookRunner( $hookContainer );
81 $this->logger = $logger;
84 /**
85 * @param string $modelID
87 * @return ContentHandler
88 * @throws MWUnknownContentModelException If no handler is known for the model ID.
90 public function getContentHandler( string $modelID ): ContentHandler {
91 if ( empty( $this->handlersByModel[$modelID] ) ) {
92 $contentHandler = $this->createForModelID( $modelID );
94 $this->logger->info(
95 "Registered handler for {$modelID}: " . get_class( $contentHandler )
97 $this->handlersByModel[$modelID] = $contentHandler;
100 return $this->handlersByModel[$modelID];
104 * Define HandlerSpec for ModelID.
105 * @param string $modelID
106 * @param callable|string $handlerSpec
108 * @internal
111 public function defineContentHandler( string $modelID, $handlerSpec ): void {
112 if ( !is_callable( $handlerSpec ) && !is_string( $handlerSpec ) ) {
113 throw new InvalidArgumentException(
114 "ContentHandler Spec for modelID '{$modelID}' must be callable or class name"
117 unset( $this->handlersByModel[$modelID] );
118 $this->handlerSpecs[$modelID] = $handlerSpec;
122 * Get defined ModelIDs
124 * @return string[]
126 public function getContentModels(): array {
127 $modelsFromHook = [];
128 $this->hookRunner->onGetContentModels( $modelsFromHook );
129 $models = array_merge( // auto-registered from config and MediaWikiServices or manual
130 array_keys( $this->handlerSpecs ),
132 // incorrect registered and called: without HOOK_NAME_GET_CONTENT_MODELS
133 array_keys( $this->handlersByModel ),
135 // correct registered: as HOOK_NAME_GET_CONTENT_MODELS
136 $modelsFromHook );
138 return array_unique( $models );
142 * @return string[]
144 public function getAllContentFormats(): array {
145 $formats = [];
146 foreach ( $this->handlerSpecs as $model => $class ) {
147 $formats += array_fill_keys(
148 $this->getContentHandler( $model )->getSupportedFormats(),
149 true );
152 return array_keys( $formats );
156 * @param string $modelID
158 * @return bool
160 public function isDefinedModel( string $modelID ): bool {
161 return in_array( $modelID, $this->getContentModels(), true );
165 * Create ContentHandler for ModelID
167 * @param string $modelID The ID of the content model for which to get a handler.
168 * Use CONTENT_MODEL_XXX constants.
170 * @return ContentHandler The ContentHandler singleton for handling the model given by the ID.
172 * @throws MWUnknownContentModelException If no handler is known for the model ID.
174 private function createForModelID( string $modelID ): ContentHandler {
175 $handlerSpec = $this->handlerSpecs[$modelID] ?? null;
176 if ( $handlerSpec !== null ) {
177 return $this->createContentHandlerFromHandlerSpec( $modelID, $handlerSpec );
180 return $this->createContentHandlerFromHook( $modelID );
184 * @param string $modelID
185 * @param ContentHandler $contentHandler
187 * @throws MWUnknownContentModelException
189 private function validateContentHandler( string $modelID, $contentHandler ): void {
190 if ( $contentHandler === null ) {
191 throw new MWUnknownContentModelException( $modelID );
194 if ( !is_object( $contentHandler ) ) {
195 throw new InvalidArgumentException(
196 "ContentHandler for model {$modelID} wrong: non-object given."
200 if ( !$contentHandler instanceof ContentHandler ) {
201 throw new InvalidArgumentException(
202 "ContentHandler for model {$modelID} must supply a ContentHandler instance, "
203 . get_class( $contentHandler ) . ' given.'
209 * @param string $modelID
210 * @param callable|string $handlerSpec
212 * @return ContentHandler
213 * @throws MWUnknownContentModelException
215 private function createContentHandlerFromHandlerSpec(
216 string $modelID, $handlerSpec
217 ): ContentHandler {
219 * @var ContentHandler $contentHandler
221 $contentHandler = $this->objectFactory->createObject(
222 $handlerSpec,
224 'assertClass' => ContentHandler::class,
225 'allowCallable' => true,
226 'allowClassName' => true,
227 'extraArgs' => [ $modelID ],
231 $this->validateContentHandler( $modelID, $contentHandler );
233 return $contentHandler;
237 * @param string $modelID
239 * @return ContentHandler
240 * @throws MWUnknownContentModelException
242 private function createContentHandlerFromHook( string $modelID ): ContentHandler {
243 $contentHandler = null;
244 // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args
245 $this->hookRunner->onContentHandlerForModelID( $modelID, $contentHandler );
246 $this->validateContentHandler( $modelID, $contentHandler );
248 '@phan-var ContentHandler $contentHandler';
250 return $contentHandler;