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 MediaServiceWiki 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_flip( $this->getContentHandler( $model )->getSupportedFormats() );
157  }
158 
159  return array_keys( $formats );
160  }
161 
168  public function isDefinedModel( string $modelID ): bool {
169  return in_array( $modelID, $this->getContentModels(), true );
170  }
171 
183  private function createForModelID( string $modelID ): ContentHandler {
184  $handlerSpec = $this->handlerSpecs[$modelID] ?? null;
185  if ( $handlerSpec !== null ) {
186  return $this->createContentHandlerFromHandlerSpec( $modelID, $handlerSpec );
187  }
188 
189  return $this->createContentHandlerFromHook( $modelID );
190  }
191 
199  private function validateContentHandler( string $modelID, $contentHandler ): void {
200  if ( $contentHandler === null ) {
201  throw new MWUnknownContentModelException( $modelID );
202  }
203 
204  if ( !is_object( $contentHandler ) ) {
205  throw new MWException(
206  "ContentHandler for model {$modelID} wrong: non-object given."
207  );
208  }
209 
210  if ( !$contentHandler instanceof ContentHandler ) {
211  throw new MWException(
212  "ContentHandler for model {$modelID} must supply a ContentHandler instance, "
213  . get_class( $contentHandler ) . 'given.'
214  );
215  }
216  }
217 
227  string $modelID, $handlerSpec
228  ): ContentHandler {
229  try {
233  $contentHandler = $this->objectFactory->createObject( $handlerSpec,
234  [
235  'assertClass' => ContentHandler::class,
236  'allowCallable' => true,
237  'allowClassName' => true,
238  'extraArgs' => [ $modelID ],
239  ] );
240  }
241  catch ( InvalidArgumentException $e ) {
242  // legacy support
243  throw new MWException( "Wrong Argument HandlerSpec for ModelID: {$modelID}. " .
244  "Error: {$e->getMessage()}" );
245  }
246  catch ( UnexpectedValueException $e ) {
247  // legacy support
248  throw new MWException( "Wrong HandlerSpec class for ModelID: {$modelID}. " .
249  "Error: {$e->getMessage()}" );
250  }
251  $this->validateContentHandler( $modelID, $contentHandler );
252 
253  return $contentHandler;
254  }
255 
263  private function createContentHandlerFromHook( string $modelID ): ContentHandler {
264  $contentHandler = null;
265  $this->hookRunner->onContentHandlerForModelID( $modelID, $contentHandler );
266  $this->validateContentHandler( $modelID, $contentHandler );
267 
268  '@phan-var ContentHandler $contentHandler';
269 
270  return $contentHandler;
271  }
272 }
ContentHandler
A content handler knows how do deal with a specific type of content on a wiki page.
Definition: ContentHandler.php:59
MediaWiki\Content\ContentHandlerFactory\createContentHandlerFromHook
createContentHandlerFromHook(string $modelID)
Definition: ContentHandlerFactory.php:263
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:183
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:199
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:226
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:44
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:570
MediaWiki\Content\ContentHandlerFactory\isDefinedModel
isDefinedModel(string $modelID)
Definition: ContentHandlerFactory.php:168