MediaWiki  master
ContentHandlerFactory.php
Go to the documentation of this file.
1 <?php
2 
26 
27 use ContentHandler;
28 use FatalError;
29 use InvalidArgumentException;
32 use MWException;
34 use Psr\Log\LoggerInterface;
35 use UnexpectedValueException;
36 use Wikimedia\ObjectFactory;
37 
45 
49  private $handlerSpecs;
50 
54  private $handlersByModel = [];
55 
57  private $objectFactory;
58 
60  private $hookRunner;
61 
63  private $logger;
64 
76  public function __construct(
77  array $handlerSpecs,
78  ObjectFactory $objectFactory,
79  HookContainer $hookContainer,
80  LoggerInterface $logger
81  ) {
82  $this->handlerSpecs = $handlerSpecs;
83  $this->objectFactory = $objectFactory;
84  $this->hookRunner = new HookRunner( $hookContainer );
85  $this->logger = $logger;
86  }
87 
95  public function getContentHandler( string $modelID ): ContentHandler {
96  if ( empty( $this->handlersByModel[$modelID] ) ) {
97  $contentHandler = $this->createForModelID( $modelID );
98 
99  $this->logger->info(
100  "Registered handler for {$modelID}: " . get_class( $contentHandler )
101  );
102  $this->handlersByModel[$modelID] = $contentHandler;
103  }
104 
105  return $this->handlersByModel[$modelID];
106  }
107 
117  public function defineContentHandler( string $modelID, $handlerSpec ): void {
118  if ( !is_callable( $handlerSpec ) && !is_string( $handlerSpec ) ) {
119  throw new MWException(
120  "ContentHandler Spec for modelID '{$modelID}' must be callable or class name"
121  );
122  }
123  unset( $this->handlersByModel[$modelID] );
124  $this->handlerSpecs[$modelID] = $handlerSpec;
125  }
126 
134  public function getContentModels(): array {
135  $modelsFromHook = [];
136  $this->hookRunner->onGetContentModels( $modelsFromHook );
137  $models = array_merge( // auto-registered from config and MediaWikiServices or manual
138  array_keys( $this->handlerSpecs ),
139 
140  // incorrect registered and called: without HOOK_NAME_GET_CONTENT_MODELS
141  array_keys( $this->handlersByModel ),
142 
143  // correct registered: as HOOK_NAME_GET_CONTENT_MODELS
144  $modelsFromHook );
145 
146  return array_unique( $models );
147  }
148 
153  public function getAllContentFormats(): array {
154  $formats = [];
155  foreach ( $this->handlerSpecs as $model => $class ) {
156  $formats += array_fill_keys(
157  $this->getContentHandler( $model )->getSupportedFormats(),
158  true );
159  }
160 
161  return array_keys( $formats );
162  }
163 
170  public function isDefinedModel( string $modelID ): bool {
171  return in_array( $modelID, $this->getContentModels(), true );
172  }
173 
185  private function createForModelID( string $modelID ): ContentHandler {
186  $handlerSpec = $this->handlerSpecs[$modelID] ?? null;
187  if ( $handlerSpec !== null ) {
188  return $this->createContentHandlerFromHandlerSpec( $modelID, $handlerSpec );
189  }
190 
191  return $this->createContentHandlerFromHook( $modelID );
192  }
193 
201  private function validateContentHandler( string $modelID, $contentHandler ): void {
202  if ( $contentHandler === null ) {
203  throw new MWUnknownContentModelException( $modelID );
204  }
205 
206  if ( !is_object( $contentHandler ) ) {
207  throw new MWException(
208  "ContentHandler for model {$modelID} wrong: non-object given."
209  );
210  }
211 
212  if ( !$contentHandler instanceof ContentHandler ) {
213  throw new MWException(
214  "ContentHandler for model {$modelID} must supply a ContentHandler instance, "
215  . get_class( $contentHandler ) . 'given.'
216  );
217  }
218  }
219 
229  string $modelID, $handlerSpec
230  ): ContentHandler {
231  try {
235  $contentHandler = $this->objectFactory->createObject(
236  $handlerSpec,
237  [
238  'assertClass' => ContentHandler::class,
239  'allowCallable' => true,
240  'allowClassName' => true,
241  'extraArgs' => [ $modelID ],
242  ]
243  );
244  } catch ( InvalidArgumentException $e ) {
245  // legacy support
246  throw new MWException(
247  "Wrong Argument HandlerSpec for ModelID: {$modelID}. " .
248  "Error: {$e->getMessage()}"
249  );
250  } catch ( UnexpectedValueException $e ) {
251  // legacy support
252  throw new MWException(
253  "Wrong HandlerSpec class for ModelID: {$modelID}. " .
254  "Error: {$e->getMessage()}"
255  );
256  }
257  $this->validateContentHandler( $modelID, $contentHandler );
258 
259  return $contentHandler;
260  }
261 
269  private function createContentHandlerFromHook( string $modelID ): ContentHandler {
270  $contentHandler = null;
271  $this->hookRunner->onContentHandlerForModelID( $modelID, $contentHandler );
272  $this->validateContentHandler( $modelID, $contentHandler );
273 
274  '@phan-var ContentHandler $contentHandler';
275 
276  return $contentHandler;
277  }
278 }
ContentHandler
A content handler knows how do deal with a specific type of content on a wiki page.
Definition: ContentHandler.php:61
MediaWiki\Content\ContentHandlerFactory\createContentHandlerFromHook
createContentHandlerFromHook(string $modelID)
Definition: ContentHandlerFactory.php:269
MediaWiki\Content
Definition: ContentHandlerFactory.php:25
MediaWiki\Content\ContentHandlerFactory\$logger
LoggerInterface $logger
Definition: ContentHandlerFactory.php:63
MWException
MediaWiki exception.
Definition: MWException.php:29
MediaWiki\Content\ContentHandlerFactory\__construct
__construct(array $handlerSpecs, ObjectFactory $objectFactory, HookContainer $hookContainer, LoggerInterface $logger)
Definition: ContentHandlerFactory.php:76
MediaWiki\Content\ContentHandlerFactory
Definition: ContentHandlerFactory.php:44
MediaWiki\Content\ContentHandlerFactory\getContentHandler
getContentHandler(string $modelID)
Definition: ContentHandlerFactory.php:95
MediaWiki\Content\ContentHandlerFactory\createForModelID
createForModelID(string $modelID)
Create ContentHandler for ModelID.
Definition: ContentHandlerFactory.php:185
MediaWiki\Content\ContentHandlerFactory\$hookRunner
HookRunner $hookRunner
Definition: ContentHandlerFactory.php:60
MediaWiki\Content\IContentHandlerFactory
Definition: IContentHandlerFactory.php:10
MediaWiki\Content\ContentHandlerFactory\$handlersByModel
ContentHandler[] $handlersByModel
Registry of ContentHandler instances by model id.
Definition: ContentHandlerFactory.php:54
MediaWiki\Content\ContentHandlerFactory\validateContentHandler
validateContentHandler(string $modelID, $contentHandler)
Definition: ContentHandlerFactory.php:201
MediaWiki\Content\ContentHandlerFactory\$handlerSpecs
string[] callable[] $handlerSpecs
Definition: ContentHandlerFactory.php:49
MediaWiki\Content\ContentHandlerFactory\getContentModels
getContentModels()
Get defined ModelIDs.
Definition: ContentHandlerFactory.php:134
MediaWiki\Content\ContentHandlerFactory\defineContentHandler
defineContentHandler(string $modelID, $handlerSpec)
Define HandlerSpec for ModelID.
Definition: ContentHandlerFactory.php:117
FatalError
Abort the web request with a custom HTML string that will represent the entire response.
Definition: FatalError.php:37
MediaWiki\Content\ContentHandlerFactory\createContentHandlerFromHandlerSpec
createContentHandlerFromHandlerSpec(string $modelID, $handlerSpec)
Definition: ContentHandlerFactory.php:228
MediaWiki\Content\ContentHandlerFactory\getAllContentFormats
getAllContentFormats()
Definition: ContentHandlerFactory.php:153
MWUnknownContentModelException
Exception thrown when an unregistered content model is requested.
Definition: MWUnknownContentModelException.php:11
MediaWiki\HookContainer\HookContainer
HookContainer class.
Definition: HookContainer.php:45
MediaWiki\Content\ContentHandlerFactory\$objectFactory
ObjectFactory $objectFactory
Definition: ContentHandlerFactory.php:57
MediaWiki\HookContainer\HookRunner
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:557
MediaWiki\Content\ContentHandlerFactory\isDefinedModel
isDefinedModel(string $modelID)
Definition: ContentHandlerFactory.php:170