OpenXE/classes/Core/DependencyInjection/ServiceRegistry.php
2021-05-21 08:49:41 +02:00

155 lines
4.0 KiB
PHP

<?php
namespace Xentral\Core\DependencyInjection;
use Xentral\Components\Logger\LoggerAwareTrait;
use Xentral\Core\DependencyInjection\Definition\FactoryMethodDefinition;
use Xentral\Core\DependencyInjection\Exception\InvalidArgumentException;
use Xentral\Core\DependencyInjection\Exception\ServiceNotFoundException;
final class ServiceRegistry extends AbstractBaseContainer
{
/** @var array $services Storage for service instances */
private $services = [];
/** @var FactoryMethodDefinition[] $factories Storage for factory methods */
private $factories = [];
/**
* @param array $factoryMethods
*/
public function __construct(array $factoryMethods = [])
{
$this->addFactories($factoryMethods);
}
/**
* @param string $name
*
* @return bool
*/
public function has($name)
{
return $this->hasService($name) || $this->hasFactory($name);
}
/**
* @param string $name
*
* @throws ServiceNotFoundException
*
* @return object|mixed
*/
public function get($name)
{
if ($this->hasService($name)) {
return $this->services[$name];
}
if ($this->hasFactory($name)) {
$definition = $this->factories[$name];
$factoryMethod = $definition->getCallable();
$serviceInstance = $factoryMethod($this->get('ServiceContainer'));
//inject Logger if required
if (
$this->has('Logger')
&& in_array(LoggerAwareTrait::class, class_uses($serviceInstance), true)
) {
/** @var LoggerAwareTrait $serviceInstance */
$serviceInstance->setLogger($this->get('Logger'));
}
// Don't save non-shared services
if (!$definition->isShared()) {
return $serviceInstance;
}
// Save shared services
$this->add($name, $serviceInstance);
return $this->services[$name];
}
throw new ServiceNotFoundException(sprintf(
'Service "%s" was not found.', $name
));
}
/**
* @param string $name
* @param object $instance
*
* @throws InvalidArgumentException
*/
public function add($name, $instance)
{
if (!is_object($instance)) {
throw new InvalidArgumentException(sprintf(
'%s could not be added. Only objects can be added to container.', $name
));
}
$this->services[$name] = $instance;
}
/**
* @param string $name
*
* @return bool
*/
public function hasFactory($name)
{
return isset($this->factories[$name]);
}
/**
* @param string $name
* @param callable $callable
* @param bool $shared
*
* @throws InvalidArgumentException
*/
public function addFactory($name, $callable, $shared = true)
{
if (!is_callable($callable, true)) {
throw new InvalidArgumentException(sprintf(
'Factory "%s" can not be added. Second argument must be a callable.', $name
));
}
if (!is_string($name)) {
throw new InvalidArgumentException(sprintf(
'Factory "%s" can not be added. Factory name must be a string.', $name
));
}
if ($this->hasFactory($name)) {
throw new InvalidArgumentException(sprintf(
'Factory "%s" can not be added. Factory is already present.', $name
));
}
$this->factories[$name] = new FactoryMethodDefinition($callable, $shared);
}
/**
* @param array|\Iterator $factories
*/
public function addFactories($factories)
{
foreach ($factories as $name => $callable) {
$this->addFactory($name, $callable, true);
}
}
/**
* @param string $name
*
* @return bool
*/
private function hasService($name)
{
return isset($this->services[$name]);
}
}