MediaWiki  1.30.0
ServiceContainer.php
Go to the documentation of this file.
1 <?php
2 namespace MediaWiki\Services;
3 
4 use InvalidArgumentException;
5 use RuntimeException;
6 use Wikimedia\Assert\Assert;
7 
47 
51  private $services = [];
52 
56  private $serviceInstantiators = [];
57 
61  private $disabled = [];
62 
67 
71  private $destroyed = false;
72 
78  public function __construct( array $extraInstantiationParams = [] ) {
79  $this->extraInstantiationParams = $extraInstantiationParams;
80  }
81 
90  public function destroy() {
91  foreach ( $this->getServiceNames() as $name ) {
92  $service = $this->peekService( $name );
93  if ( $service !== null && $service instanceof DestructibleService ) {
94  $service->destroy();
95  }
96  }
97 
98  $this->destroyed = true;
99  }
100 
106  public function loadWiringFiles( array $wiringFiles ) {
107  foreach ( $wiringFiles as $file ) {
108  // the wiring file is required to return an array of instantiators.
109  $wiring = require $file;
110 
111  Assert::postcondition(
112  is_array( $wiring ),
113  "Wiring file $file is expected to return an array!"
114  );
115 
116  $this->applyWiring( $wiring );
117  }
118  }
119 
127  Assert::parameterElementType( 'callable', $serviceInstantiators, '$serviceInstantiators' );
128 
129  foreach ( $serviceInstantiators as $name => $instantiator ) {
130  $this->defineService( $name, $instantiator );
131  }
132  }
133 
144  public function importWiring( ServiceContainer $container, $skip = [] ) {
145  $newInstantiators = array_diff_key(
146  $container->serviceInstantiators,
147  array_flip( $skip )
148  );
149 
150  $this->serviceInstantiators = array_merge(
151  $this->serviceInstantiators,
152  $newInstantiators
153  );
154  }
155 
164  public function hasService( $name ) {
165  return isset( $this->serviceInstantiators[$name] );
166  }
167 
183  public function peekService( $name ) {
184  if ( !$this->hasService( $name ) ) {
185  throw new NoSuchServiceException( $name );
186  }
187 
188  return isset( $this->services[$name] ) ? $this->services[$name] : null;
189  }
190 
194  public function getServiceNames() {
195  return array_keys( $this->serviceInstantiators );
196  }
197 
212  public function defineService( $name, callable $instantiator ) {
213  Assert::parameterType( 'string', $name, '$name' );
214 
215  if ( $this->hasService( $name ) ) {
217  }
218 
219  $this->serviceInstantiators[$name] = $instantiator;
220  }
221 
238  public function redefineService( $name, callable $instantiator ) {
239  Assert::parameterType( 'string', $name, '$name' );
240 
241  if ( !$this->hasService( $name ) ) {
242  throw new NoSuchServiceException( $name );
243  }
244 
245  if ( isset( $this->services[$name] ) ) {
247  }
248 
249  $this->serviceInstantiators[$name] = $instantiator;
250  unset( $this->disabled[$name] );
251  }
252 
272  public function disableService( $name ) {
273  $this->resetService( $name );
274 
275  $this->disabled[$name] = true;
276  }
277 
301  final protected function resetService( $name, $destroy = true ) {
302  Assert::parameterType( 'string', $name, '$name' );
303 
304  $instance = $this->peekService( $name );
305 
306  if ( $destroy && $instance instanceof DestructibleService ) {
307  $instance->destroy();
308  }
309 
310  unset( $this->services[$name] );
311  unset( $this->disabled[$name] );
312  }
313 
334  public function getService( $name ) {
335  if ( $this->destroyed ) {
336  throw new ContainerDisabledException();
337  }
338 
339  if ( isset( $this->disabled[$name] ) ) {
340  throw new ServiceDisabledException( $name );
341  }
342 
343  if ( !isset( $this->services[$name] ) ) {
344  $this->services[$name] = $this->createService( $name );
345  }
346 
347  return $this->services[$name];
348  }
349 
356  private function createService( $name ) {
357  if ( isset( $this->serviceInstantiators[$name] ) ) {
358  $service = call_user_func_array(
359  $this->serviceInstantiators[$name],
360  array_merge( [ $this ], $this->extraInstantiationParams )
361  );
362  // NOTE: when adding more wiring logic here, make sure copyWiring() is kept in sync!
363  } else {
364  throw new NoSuchServiceException( $name );
365  }
366 
367  return $service;
368  }
369 
375  public function isServiceDisabled( $name ) {
376  return isset( $this->disabled[$name] );
377  }
378 }
MediaWiki\Services\ServiceContainer\getService
getService( $name)
Returns a service object of the kind associated with $name.
Definition: ServiceContainer.php:334
MediaWiki\Services\DestructibleService
DestructibleService defines a standard interface for shutting down a service instance.
Definition: DestructibleService.php:35
MediaWiki\Services\ServiceContainer\disableService
disableService( $name)
Disables a service.
Definition: ServiceContainer.php:272
MediaWiki\Services\ServiceContainer\destroy
destroy()
Destroys all contained service instances that implement the DestructibleService interface.
Definition: ServiceContainer.php:90
MediaWiki\Services\ServiceContainer
ServiceContainer provides a generic service to manage named services using lazy instantiation based o...
Definition: ServiceContainer.php:46
MediaWiki\Services\ServiceContainer\isServiceDisabled
isServiceDisabled( $name)
Definition: ServiceContainer.php:375
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
MediaWiki\Services\ServiceContainer\loadWiringFiles
loadWiringFiles(array $wiringFiles)
Definition: ServiceContainer.php:106
MediaWiki\Services\NoSuchServiceException
Exception thrown when the requested service is not known.
Definition: NoSuchServiceException.php:33
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
MediaWiki\Services\ServiceContainer\__construct
__construct(array $extraInstantiationParams=[])
Definition: ServiceContainer.php:78
MediaWiki\Services\ServiceContainer\$extraInstantiationParams
array $extraInstantiationParams
Definition: ServiceContainer.php:66
MediaWiki\Services\ServiceContainer\redefineService
redefineService( $name, callable $instantiator)
Replace an already defined service.
Definition: ServiceContainer.php:238
MediaWiki\Services\ServiceContainer\hasService
hasService( $name)
Returns true if a service is defined for $name, that is, if a call to getService( $name ) would retur...
Definition: ServiceContainer.php:164
MediaWiki\Services\CannotReplaceActiveServiceException
Exception thrown when trying to replace an already active service.
Definition: CannotReplaceActiveServiceException.php:33
MediaWiki\Services\ServiceContainer\$disabled
bool[] $disabled
disabled status, per service name
Definition: ServiceContainer.php:61
MediaWiki\Services\ServiceContainer\$destroyed
bool $destroyed
Definition: ServiceContainer.php:71
MediaWiki\Services\ServiceContainer\peekService
peekService( $name)
Returns the service instance for $name only if that service has already been instantiated.
Definition: ServiceContainer.php:183
MediaWiki\Services\ServiceContainer\getServiceNames
getServiceNames()
Definition: ServiceContainer.php:194
MediaWiki\Services\ServiceContainer\createService
createService( $name)
Definition: ServiceContainer.php:356
MediaWiki\Services\ServiceAlreadyDefinedException
Exception thrown when a service was already defined, but the caller expected it to not exist.
Definition: ServiceAlreadyDefinedException.php:35
MediaWiki\Services\ServiceContainer\resetService
resetService( $name, $destroy=true)
Resets a service by dropping the service instance.
Definition: ServiceContainer.php:301
MediaWiki\Services
Definition: CannotReplaceActiveServiceException.php:2
MediaWiki\Services\ServiceContainer\defineService
defineService( $name, callable $instantiator)
Define a new service.
Definition: ServiceContainer.php:212
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
MediaWiki\Services\ServiceContainer\applyWiring
applyWiring(array $serviceInstantiators)
Registers multiple services (aka a "wiring").
Definition: ServiceContainer.php:126
MediaWiki\Services\ServiceDisabledException
Exception thrown when trying to access a disabled service.
Definition: ServiceDisabledException.php:33
MediaWiki\Services\ServiceContainer\importWiring
importWiring(ServiceContainer $container, $skip=[])
Imports all wiring defined in $container.
Definition: ServiceContainer.php:144
MediaWiki\Services\ServiceContainer\$serviceInstantiators
callable[] $serviceInstantiators
Definition: ServiceContainer.php:56
MediaWiki\Services\ServiceContainer\$services
object[] $services
Definition: ServiceContainer.php:51
MediaWiki\Services\ContainerDisabledException
Exception thrown when trying to access a service on a disabled container or factory.
Definition: ContainerDisabledException.php:33
array
the array() calling protocol came about after MediaWiki 1.4rc1.