tao-test/app/generis/common/oatbox/service/ServiceManager.php

288 lines
8.3 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2015-2021 (original work) Open Assessment Technologies SA;
*
*/
namespace oat\oatbox\service;
use oat\generis\model\DependencyInjection\ContainerBuilder;
use oat\generis\model\DependencyInjection\ContainerStarter;
use oat\oatbox\Configurable;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Psr\Container\ContainerInterface;
/**
* The simple placeholder ServiceManager
* @author Joel Bout <joel@taotesting.com>
*/
class ServiceManager implements ServiceLocatorInterface, ContainerInterface
{
private static $instance;
/** @var ContainerStarter */
private $containerStarter;
/**
* @return \oat\oatbox\service\ServiceManager
* @deprecated Pass service locator instead of relying on static function
*/
public static function getServiceManager()
{
if (is_null(self::$instance)) {
self::$instance = new ServiceManager(\common_ext_ConfigDriver::singleton());
}
return self::$instance;
}
public static function setServiceManager(ServiceManager $serviceManager)
{
self::$instance = $serviceManager;
}
private $services = [];
/**
* @var \common_persistence_KeyValuePersistence
*/
private $configService;
public function __construct($configService)
{
$this->configService = $configService;
}
/**
* Returns the service configured for the serviceKey
* or throws a ServiceNotFoundException
*
* @param string $serviceKey
* @return ConfigurableService
* @throws ServiceNotFoundException
* @see ContainerInterface::get()
* @deprecated Use $this->getContainer()->get()
*/
public function get($serviceKey)
{
$serviceId = $this->getServiceId($serviceKey);
if (!isset($this->services[$serviceId])) {
$this->services[$serviceId] = $this->load($serviceId, $serviceKey);
}
return $this->services[$serviceId];
}
/**
* Extract the service id from the provided parameter
* @param string $serviceKey
* @return string
*/
private function getServiceId($serviceKey)
{
return ((interface_exists($serviceKey) || class_exists($serviceKey)) && defined($serviceKey . '::SERVICE_ID'))
? $serviceKey::SERVICE_ID
: (string)$serviceKey
;
}
/**
* Loads the service referenced by id
*
* @param string $serviceId
* @param string $serviceKey
* @throws ServiceNotFoundException
* @return ConfigurableService
*/
private function load($serviceId, $serviceKey)
{
$service = $this->getConfig()->get($serviceId);
if ($service === false) {
$service = $this->tryAutowiring($serviceId, $serviceKey);
}
if ($service instanceof ServiceFactoryInterface) {
$service = $service($this);
}
if (is_object($service) && ($service instanceof ServiceLocatorAwareInterface)) {
$service->setServiceLocator($this);
}
return $service;
}
/**
* Try to initialize the class without parameters
*
* @param string $serviceId
* @param string $serviceKey
* @throws ServiceNotFoundException
* @return ConfigurableService
*/
private function tryAutowiring($serviceId, $serviceKey)
{
if (!class_exists($serviceKey) || !is_subclass_of($serviceKey, ConfigurableService::class)) {
throw new ServiceNotFoundException($serviceId);
}
return new $serviceKey();
}
/**
* (non-PHPdoc)
* @see ContainerInterface::has()
* @deprecated Use $this->getContainer()->has()
*/
public function has($serviceKey)
{
if (isset($this->services[$serviceKey])) {
return true;
}
$parts = explode('/', $serviceKey, 2);
if (count($parts) < 2) {
return false;
}
return $this->getConfig()->exists($serviceKey);
}
/**
* Registers a service, overwritting a potentially already
* existing service.
*3
* @param string $serviceKey
* @param ConfigurableService $service
* @throws \common_Exception
* @deprecated New services must be registered using Dependency Injection Container
*/
public function register($serviceKey, ConfigurableService $service)
{
$parts = explode('/', $serviceKey, 2);
if (count($parts) < 2) {
throw new \common_Exception('Invalid servicekey ' . $serviceKey);
}
$this->propagate($service);
$this->services[$serviceKey] = $service;
$success = $this->getConfig()->set($serviceKey, $service);
if (!$success) {
throw new \common_exception_Error('Unable to write ' . $serviceKey);
}
}
/**
* @deprecated New services must be registered using Dependency Injection Container
*/
public function unregister($serviceKey)
{
unset($this->services[$serviceKey]);
return $this->getConfig()->del($serviceKey);
}
/**
* @return \common_persistence_KeyValuePersistence
*/
protected function getConfig()
{
return $this->configService;
}
/**
* Propagate service dependencies
*
* @param $service
* @return mixed
*
* @deprecated - If class uses ServiceManagerAwareTrait use $this->propagate($service)
* @deprecated New services must be registered using Dependency Injection Container
*/
public function propagate($service)
{
if (is_object($service) && ($service instanceof ServiceLocatorAwareInterface)) {
$service->setServiceLocator($this);
}
return $service;
}
/**
* Service or sub-service factory
*
* @param $className
* @param array $options
* @return mixed
* @deprecated New services must be registered using Dependency Injection Container
*/
public function build($className, array $options = [])
{
if (is_a($className, Configurable::class, true)) {
$service = new $className($options);
$this->propagate($service);
return $service;
}
throw new ServiceNotFoundException($className);
}
/**
* Prevents accidental serialisation of the services
* @return array
*/
public function __sleep()
{
return [];
}
/**
* Dynamically overload a service without persisting it
*
* @param $serviceKey
* @param ConfigurableService $service
* @deprecated New services must be registered using Dependency Injection Container
*/
public function overload($serviceKey, ConfigurableService $service)
{
$this->services[$serviceKey] = $service;
}
/**
* @TODO Container will be removed from here as soon as we do not need ServiceManager anymore.
*/
public function getContainer(): ContainerInterface
{
return $this->getContainerStarter()->getContainer();
}
/**
* @TODO ContainerBuilder will be removed from here as soon as we do not need ServiceManager anymore.
*/
public function getContainerBuilder(): ContainerBuilder
{
return $this->getContainerStarter()->getContainerBuilder();
}
/**
* @TODO ContainerStarter will be removed from here as soon as we do not need ServiceManager anymore.
*/
private function getContainerStarter(): ContainerStarter
{
if (!$this->containerStarter) {
$this->containerStarter = new ContainerStarter($this);
}
return $this->containerStarter;
}
}