diff --git a/src/Annotation/Inject.php b/src/Annotation/Inject.php index 22d76f2..78eac9d 100644 --- a/src/Annotation/Inject.php +++ b/src/Annotation/Inject.php @@ -1,6 +1,7 @@ param) { + if ($this->param) { $type = 'param'; - } - else { + } else { $type = ($this->class || !$this->service) ? 'instance' : 'service'; } - switch($type) - { + switch ($type) { case 'instance': return $this->class; @@ -63,10 +62,6 @@ public function getDependency($config = null) case 'param': return 'param.value'; - } - } - - -} \ No newline at end of file +} diff --git a/src/Builder/AbstractServiceBuilder.php b/src/Builder/AbstractServiceBuilder.php index 75e719d..52b0567 100644 --- a/src/Builder/AbstractServiceBuilder.php +++ b/src/Builder/AbstractServiceBuilder.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory\Builder; - use ObjectivePHP\Config\ConfigReference; use ObjectivePHP\Primitives\Collection\Collection; use ObjectivePHP\ServicesFactory\ServicesFactory; @@ -16,77 +15,73 @@ * * @package ObjectivePHP\ServicesFactory\Builder */ - abstract class AbstractServiceBuilder implements ServiceBuilderInterface, ServicesFactoryAwareInterface - { +abstract class AbstractServiceBuilder implements ServiceBuilderInterface, ServicesFactoryAwareInterface +{ - use ServicesFactoryAwareTrait; + use ServicesFactoryAwareTrait; - /** + /** * This property should be initialized in extended classes * * @var Collection */ - protected $handledSpecs; + protected $handledSpecs; - /** + /** * AbstractServiceBuilder constructor. */ - public function __construct() - { - $this->handledSpecs = new Collection($this->handledSpecs); - } + public function __construct() + { + $this->handledSpecs = new Collection($this->handledSpecs); + } - /** + /** * @param ServiceSpecsInterface $serviceDefinition * * @return bool */ - public function doesHandle(ServiceSpecsInterface $serviceDefinition) - { - foreach ($this->getHandledSpecs() as $handledDefinition) - { - if ($serviceDefinition instanceof $handledDefinition) - { - return true; - } + public function doesHandle(ServiceSpecsInterface $serviceDefinition) + { + foreach ($this->getHandledSpecs() as $handledDefinition) { + if ($serviceDefinition instanceof $handledDefinition) { + return true; } - - return false; } - /** + return false; + } + + /** * @return Collection */ - public function getHandledSpecs() - { - return $this->handledSpecs; - } + public function getHandledSpecs() + { + return $this->handledSpecs; + } - /** + /** * Substitute all references to services in a param set * * @param Collection $params * * @return Collection */ - protected function substituteReferences(Collection $params) - { - $params->each(function (&$value) - { - if ($value instanceof ServiceReference) - { - $value = $this->getServicesFactory()->get($value->getId()); - } else if($value instanceof ConfigReference) { - $value = $this->getServicesFactory()->get('config')->get($value->getId()); - } - }); - } + protected function substituteReferences(Collection $params) + { + $params->each(function (&$value) { + if ($value instanceof ServiceReference) { + $value = $this->getServicesFactory()->get($value->getId()); + } elseif ($value instanceof ConfigReference) { + $value = $this->getServicesFactory()->get('config')->get($value->getId()); + } + }); + } - /** + /** * @return ServicesFactory */ - public function getServicesFactory() - { - return $this->servicesFactory; - } + public function getServicesFactory() + { + return $this->servicesFactory; } +} diff --git a/src/Builder/ClassServiceBuilder.php b/src/Builder/ClassServiceBuilder.php index a0c6d03..6fdb75f 100644 --- a/src/Builder/ClassServiceBuilder.php +++ b/src/Builder/ClassServiceBuilder.php @@ -28,18 +28,28 @@ public function build(ServiceSpecsInterface $serviceSpecs, $params = [], $servic { // check compatibility with the service definition - if (!$this->doesHandle($serviceSpecs)) - { - throw new Exception(sprintf('"%s" service definition is not handled by this builder.', get_class($serviceSpecs)), Exception::INCOMPATIBLE_SERVICE_DEFINITION); + if (!$this->doesHandle($serviceSpecs)) { + throw new Exception( + sprintf( + '"%s" service definition is not handled by this builder.', + get_class($serviceSpecs) + ), + Exception::INCOMPATIBLE_SERVICE_DEFINITION + ); } $serviceClassName = $serviceSpecs->getClass(); // check class existence - if(!class_exists($serviceClassName)) - { - throw new Exception(sprintf('Unable to build service: class "%s" is unknown', $serviceClassName), Exception::INVALID_SERVICE_SPECS); + if (!class_exists($serviceClassName)) { + throw new Exception( + sprintf( + 'Unable to build service: class "%s" is unknown', + $serviceClassName + ), + Exception::INVALID_SERVICE_SPECS + ); } // merge service defined and runtime params @@ -52,10 +62,8 @@ public function build(ServiceSpecsInterface $serviceSpecs, $params = [], $servic $service = new $serviceClassName(...$constructorParams->values()); // call setters if any - if($setters = $serviceSpecs->getSetters()) - { - foreach($setters as $setter => $setterParams) - { + if ($setters = $serviceSpecs->getSetters()) { + foreach ($setters as $setter => $setterParams) { $instanceSetterParams = clone Collection::cast($setterParams); $this->substituteReferences($instanceSetterParams); @@ -66,5 +74,4 @@ public function build(ServiceSpecsInterface $serviceSpecs, $params = [], $servic return $service; } - } diff --git a/src/Builder/DelegatedFactoryBuilder.php b/src/Builder/DelegatedFactoryBuilder.php index 67686db..727b8bf 100644 --- a/src/Builder/DelegatedFactoryBuilder.php +++ b/src/Builder/DelegatedFactoryBuilder.php @@ -32,8 +32,10 @@ public function build(ServiceSpecsInterface $serviceSpecs, $params = [], $actual // check compatibility with the service definition if (!$this->doesHandle($serviceSpecs)) { - throw new Exception(sprintf('"%s" service definition is not handled by this builder.', - get_class($serviceSpecs)), Exception::INCOMPATIBLE_SERVICE_DEFINITION); + throw new Exception(sprintf( + '"%s" service definition is not handled by this builder.', + get_class($serviceSpecs) + ), Exception::INCOMPATIBLE_SERVICE_DEFINITION); } @@ -46,8 +48,11 @@ public function build(ServiceSpecsInterface $serviceSpecs, $params = [], $actual } $factory = $factory->getCallable(); } catch (InvokableException $e) { - throw new Exception(sprintf('Unable to build service: provided factory is not callable'), - Exception::INVALID_SERVICE_SPECS, $e); + throw new Exception( + sprintf('Unable to build service: provided factory is not callable'), + Exception::INVALID_SERVICE_SPECS, + $e + ); } // merge service defined and runtime params @@ -62,5 +67,4 @@ public function build(ServiceSpecsInterface $serviceSpecs, $params = [], $actual return $service; } - } diff --git a/src/Builder/PrefabServiceBuilder.php b/src/Builder/PrefabServiceBuilder.php index 3b7b437..b0d0dac 100644 --- a/src/Builder/PrefabServiceBuilder.php +++ b/src/Builder/PrefabServiceBuilder.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory\Builder; - use ObjectivePHP\ServicesFactory\Exception\Exception; use ObjectivePHP\ServicesFactory\Specs\PrefabServiceSpecs; use ObjectivePHP\ServicesFactory\Specs\ServiceSpecsInterface; @@ -28,12 +27,16 @@ class PrefabServiceBuilder extends AbstractServiceBuilder public function build(ServiceSpecsInterface $serviceSpecs, $params = [], $serviceId = null) { // check compatibility with the service definition - if (!$this->doesHandle($serviceSpecs)) - { - throw new Exception(sprintf('"%s" service spec is not handled by this builder.', get_class($serviceSpecs)), Exception::INCOMPATIBLE_SERVICE_DEFINITION); + if (!$this->doesHandle($serviceSpecs)) { + throw new Exception( + sprintf( + '"%s" service spec is not handled by this builder.', + get_class($serviceSpecs) + ), + Exception::INCOMPATIBLE_SERVICE_DEFINITION + ); } return $serviceSpecs->getInstance(); } - } diff --git a/src/Builder/ServiceBuilderInterface.php b/src/Builder/ServiceBuilderInterface.php index b70506e..6eb2d67 100644 --- a/src/Builder/ServiceBuilderInterface.php +++ b/src/Builder/ServiceBuilderInterface.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory\Builder; - use ObjectivePHP\ServicesFactory\Specs\ServiceSpecsInterface; interface ServiceBuilderInterface @@ -26,5 +25,4 @@ public function doesHandle(ServiceSpecsInterface $serviceDefinition); * @return mixed */ public function build(ServiceSpecsInterface $serviceSpecs, $params = null); - } diff --git a/src/Exception/Exception.php b/src/Exception/Exception.php index 25b6309..a18fbc1 100644 --- a/src/Exception/Exception.php +++ b/src/Exception/Exception.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory\Exception; - use Interop\Container\Exception\ContainerException; class Exception extends \Exception implements ContainerException @@ -21,5 +20,4 @@ class Exception extends \Exception implements ContainerException // dependencies handling const DEPENDENCY_NOT_FOUND = 0x31; const MISSING_DEPENDENCY_DEFINITION = 0x32; - } diff --git a/src/Exception/ServiceNotFoundException.php b/src/Exception/ServiceNotFoundException.php index cadc7af..c6888c4 100644 --- a/src/Exception/ServiceNotFoundException.php +++ b/src/Exception/ServiceNotFoundException.php @@ -2,10 +2,8 @@ namespace ObjectivePHP\ServicesFactory\Exception; - - - class ServiceNotFoundException extends Exception - { - const UNREGISTERED_SERVICE_REFERENCE = 0x20; - } \ No newline at end of file +class ServiceNotFoundException extends Exception +{ + const UNREGISTERED_SERVICE_REFERENCE = 0x20; +} diff --git a/src/ServiceReference.php b/src/ServiceReference.php index aa2d409..4287e28 100644 --- a/src/ServiceReference.php +++ b/src/ServiceReference.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory; - class ServiceReference { @@ -28,5 +27,4 @@ public function __toString() { return (string) $this->id; } - } diff --git a/src/ServicesFactory.php b/src/ServicesFactory.php index 4ffcd3c..f3c99c5 100644 --- a/src/ServicesFactory.php +++ b/src/ServicesFactory.php @@ -59,6 +59,11 @@ class ServicesFactory implements ContainerInterface */ protected $registeredAliases = []; + /** + * @var array + */ + protected $siblings = []; + /** * ServicesFactory constructor. */ @@ -102,8 +107,11 @@ public function registerService(...$servicesSpecs) try { $serviceSpecs = AbstractServiceSpecs::factory($serviceSpecs); } catch (\Exception $e) { - throw new Exception(AbstractServiceSpecs::class . '::factory() was unable to build service specifications', - Exception::INVALID_SERVICE_SPECS, $e); + throw new Exception( + AbstractServiceSpecs::class . '::factory() was unable to build service specifications', + Exception::INVALID_SERVICE_SPECS, + $e + ); } } @@ -114,8 +122,10 @@ public function registerService(...$servicesSpecs) // a service with same name already has been registered if ($previouslyRegistered->isFinal()) { // as it is marked as final, it cannot be overridden - throw new Exception(sprintf('Cannot override service "%s" as it has been registered as a final service', - $serviceId), Exception::FINAL_SERVICE_OVERRIDING_ATTEMPT); + throw new Exception(sprintf( + 'Cannot override service "%s" as it has been registered as a final service', + $serviceId + ), Exception::FINAL_SERVICE_OVERRIDING_ATTEMPT); } } @@ -123,14 +133,20 @@ public function registerService(...$servicesSpecs) $this->services[(string)$serviceId] = $serviceSpecs; $aliases = $serviceSpecs->getAliases() ?: []; - foreach($aliases as $alias) { - + foreach ($aliases as $alias) { if ($previouslyRegistered = $this->getServiceSpecs((string)$alias)) { // a service with same name already has been registered if ($previouslyRegistered->isFinal()) { // as it is marked as final, it cannot be overridden - throw new Exception(sprintf('Cannot override service "%s" using alias "%s" as it has been registered as a final service', - $serviceId, $alias), Exception::FINAL_SERVICE_OVERRIDING_ATTEMPT); + throw new Exception( + sprintf( + 'Cannot override service "%s" using alias + "%s" as it has been registered as a final service', + $serviceId, + $alias + ), + Exception::FINAL_SERVICE_OVERRIDING_ATTEMPT + ); } } @@ -148,7 +164,7 @@ public function registerService(...$servicesSpecs) */ public function getServiceSpecs($service) { - + $saved = $service; if ($service instanceof ServiceReference) { $service = $service->getId(); } @@ -162,6 +178,8 @@ public function getServiceSpecs($service) $service = $this->registeredAliases[$service]; } } + + $specs = $this->services[$service] ?? null; if (is_null($specs)) { @@ -173,7 +191,7 @@ public function getServiceSpecs($service) $specs = null; } } - + return $specs; } @@ -230,15 +248,19 @@ public function registerDelegateContainer(ContainerInterface $delegate) public function getConfig(): Config { if (!$this->has('config')) { - throw new Exception('No "config" service has been registered in this factory', - Exception::UNKNOWN_SERVICE_SPECS); + throw new Exception( + 'No "config" service has been registered in this factory', + Exception::UNKNOWN_SERVICE_SPECS + ); } $config = $this->get('config'); if (!$config instanceof Config) { - throw new Exception('Registered service "config" is not an instance of ' . Config::class, - Exception::INCOMPATIBLE_SERVICE_DEFINITION); + throw new Exception( + 'Registered service "config" is not an instance of ' . Config::class, + Exception::INCOMPATIBLE_SERVICE_DEFINITION + ); } return $config; @@ -267,11 +289,10 @@ public function has($service) */ public function get($service, $params = []) { - $service = $this->normalizeServiceId($service); - + $serviceSpecs = $this->getServiceSpecs($service); - + if (is_null($serviceSpecs)) { foreach ($this->delegateContainers as $delegate) { if ($instance = $delegate->get($service)) { @@ -281,12 +302,13 @@ public function get($service, $params = []) } } - throw new ServiceNotFoundException(sprintf('Service reference "%s" matches no registered service in this factory or its delegate containers', - $service), ServiceNotFoundException::UNREGISTERED_SERVICE_REFERENCE); + throw new ServiceNotFoundException(sprintf( + 'Service reference "%s" matches no registered service in this factory or its delegate containers', + $service + ), ServiceNotFoundException::UNREGISTERED_SERVICE_REFERENCE); } - if ( - !$serviceSpecs->isStatic() + if (!$serviceSpecs->isStatic() || $this->getInstances()->lacks($service) || $params ) { @@ -300,7 +322,8 @@ public function get($service, $params = []) $builder->setServicesFactory($this); } - $instance = $builder->build($serviceSpecs, $params, $service);; + $instance = $builder->build($serviceSpecs, $params, $service); + ; $this->injectDependencies($instance, $serviceSpecs); @@ -312,11 +335,9 @@ public function get($service, $params = []) } else { $this->instances[$service] = $instance; } - } return $this->instances[$service]; - } /** @@ -340,9 +361,8 @@ public function isServiceRegistered($service) } return $has; - } - + /** * @param $instance * @param $serviceSpecs @@ -358,66 +378,42 @@ public function injectDependencies($instance, $serviceSpecs = null) $injector($instance, $this, $serviceSpecs); }) ; - + if ($instance instanceof InjectionAnnotationProvider) { // automated injections $reflectedInstance = new \ReflectionObject($instance); $reflectedProperties = $reflectedInstance->getProperties(); - + foreach ($reflectedProperties as $reflectedProperty) { $injection = $this->getAnnotationsReader() ->getPropertyAnnotation($reflectedProperty, Annotation\Inject::class) ; if ($injection) { if ($injection->param) { - if ($this->has('config')) { - $config = $this->get('config'); - - if ($config instanceof Config) { - $params = $config->subset('ObjectivePHP\Application\Config\Param'); - - if ($params->has($injection->param)) { - $dependency = $params->get($injection->param); - } else { - if (isset($injection->default)) { - $dependency = $injection->default; - } else { - throw new Exception(sprintf('Config instance registered as "config" does not have a "%s" param, and no default value is provided', - $injection->param)); - } - } - - } else { - throw new Exception('Service registered as "config" in this factory is no a Config instance'); - } - } else { - throw new Exception('No Config is registered as "config" in this factory'); - } - } else if ($injection->class || !$injection->service) { + $dependency = $this->getConfigParamToInject($injection); + } elseif ($injection->class || !$injection->service) { $className = $injection->getDependency(); - + if (!$className) { // use phpdocumentor to get var type $docblock = DocBlockFactory::createInstance()->create($reflectedProperty); if ($docblock->hasTag('var')) { $className = (string)$docblock->getTagsByName('var')[0]->getType()->getFqsen(); } else { - throw new Exception('Undefined dependency. Use either dependency="|" or "@var $property ClassName"', - Exception::MISSING_DEPENDENCY_DEFINITION); + throw new Exception( + 'Undefined dependency. Use either dependency="|" + or "@var $property ClassName"', + Exception::MISSING_DEPENDENCY_DEFINITION + ); } } - + $dependency = new $className; $this->injectDependencies($dependency); } else { - $serviceName = $injection->getDependency(); - if (!$this->has($serviceName)) { - throw new Exception(sprintf('Dependent service "%s" is not registered', $serviceName), - Exception::DEPENDENCY_NOT_FOUND); - } - $dependency = $this->get($serviceName); + $dependency = $this->getServiceToInject($injection->getDependency()); } - + if ($injection->setter) { $setter = $injection->setter; $instance->$setter($dependency); @@ -425,9 +421,9 @@ public function injectDependencies($instance, $serviceSpecs = null) if (!$reflectedProperty->isPublic()) { $reflectedProperty->setAccessible(true); } - + $reflectedProperty->setValue($instance, $dependency); - + if (!$reflectedProperty->isPublic()) { $reflectedProperty->setAccessible(false); } @@ -439,6 +435,74 @@ public function injectDependencies($instance, $serviceSpecs = null) return $this; } + + /** + * @param $serviceName + * @return mixed|null + * @throws Exception + */ + protected function getServiceToInject($serviceName) + { + $siblings = $this->siblings; + if (count($siblings) === 0) { + $siblings = [$this]; + } + + foreach ($siblings as $sibling) { + if ($sibling->has($serviceName)) { + return $sibling->get($serviceName); + } + } + + throw new Exception( + sprintf('Dependent service "%s" is not registered', $serviceName), + Exception::DEPENDENCY_NOT_FOUND + ); + } + + /** + * @throws Exception + */ + protected function getConfigParamToInject($injection) + { + $hasConfig = false; + + $siblings = $this->siblings; + if (count($siblings) === 0) { + $siblings = [$this]; + } + + foreach ($siblings as $servicesFactory) { + if ($servicesFactory->has('config')) { + $hasConfig = true; + + $config = $servicesFactory->get('config'); + + if ($config instanceof Config) { + $params = $config->subset('ObjectivePHP\Application\Config\Param'); + + if ($params->has($injection->param)) { + return $dependency = $params->get($injection->param); + } else { + if (isset($injection->default)) { + return $dependency = $injection->default; + } + } + } else { + throw new Exception('Service registered as "config" in this factory is no a Config instance'); + } + } + } + + if (false === $hasConfig) { + throw new Exception('No Config is registered as "config" neither in this factory nor in its siblings'); + } + + throw new Exception(sprintf( + 'Config instance registered as "config" does not have a "%s" param, and no default value is provided', + $injection->param + )); + } /** * @return Collection @@ -518,5 +582,18 @@ protected function normalizeServiceId($service) // normalize service id return strtolower(($service instanceof ServiceReference) ? $service->getId() : $service); } - + + /** + * Register one or multiple sibling containers. + * + * @param ContainerInterface[] ...$containers + * + * @return $this + */ + public function registerSiblingContainer(ContainerInterface ...$containers) + { + array_push($this->siblings, ...$containers); + + return $this; + } } diff --git a/src/ServicesFactoryAwareInterface.php b/src/ServicesFactoryAwareInterface.php index eaf78c4..beee6a3 100644 --- a/src/ServicesFactoryAwareInterface.php +++ b/src/ServicesFactoryAwareInterface.php @@ -9,18 +9,17 @@ namespace ObjectivePHP\ServicesFactory; - /** * Interface ServicesFactoryAwareInterface * * @package ObjectivePHP\ServicesFactory */ - interface ServicesFactoryAwareInterface - { - /** +interface ServicesFactoryAwareInterface +{ + /** * @param ServicesFactory $servicesFactory * * @return $this */ - public function setServicesFactory(ServicesFactory $servicesFactory); - } + public function setServicesFactory(ServicesFactory $servicesFactory); +} diff --git a/src/ServicesFactoryAwareTrait.php b/src/ServicesFactoryAwareTrait.php index a1b66a8..9cad20f 100644 --- a/src/ServicesFactoryAwareTrait.php +++ b/src/ServicesFactoryAwareTrait.php @@ -9,29 +9,27 @@ namespace ObjectivePHP\ServicesFactory; - /** * Class ServicesFactoryAwareTrait * * @package ObjectivePHP\ServicesFactory */ - trait ServicesFactoryAwareTrait - { - /** +trait ServicesFactoryAwareTrait +{ + /** * @var ServicesFactory */ - protected $servicesFactory; + protected $servicesFactory; - /** + /** * @param ServicesFactory $servicesFactory * * @return $this */ - public function setServicesFactory(ServicesFactory $servicesFactory) - { - $this->servicesFactory = $servicesFactory; - - return $this; - } + public function setServicesFactory(ServicesFactory $servicesFactory) + { + $this->servicesFactory = $servicesFactory; + return $this; } +} diff --git a/src/Specs/AbstractServiceSpecs.php b/src/Specs/AbstractServiceSpecs.php index f735bae..98a0cdb 100644 --- a/src/Specs/AbstractServiceSpecs.php +++ b/src/Specs/AbstractServiceSpecs.php @@ -46,10 +46,11 @@ public function __construct($serviceId, $params = []) // assign default values $this->setId($serviceId); - foreach($params as $param => $value) - { + foreach ($params as $param => $value) { $paramParts = explode('-', strtolower($param)); - array_walk($paramParts, function(&$part) { $part = ucfirst($part);}); + array_walk($paramParts, function (&$part) { + $part = ucfirst($part); + }); $setter = implode($paramParts); $this->$setter($value); } @@ -82,8 +83,7 @@ public function getAliases() { $aliases = $this->aliases; - if($autoAlias = $this->getAutoAlias()) - { + if ($autoAlias = $this->getAutoAlias()) { $aliases[] = $autoAlias; } @@ -144,37 +144,49 @@ public function setStatic($static) return $this; } - static function factory($rawDefinition) + public static function factory($rawDefinition) { $rawDefinition = Collection::cast($rawDefinition); // first check an id has been provided - if ($rawDefinition->lacks('id')) - { - throw new Exception('Missing mandatory \'id\' parameter in service definition', Exception::INCOMPLETE_SERVICE_SPECS); + if ($rawDefinition->lacks('id')) { + throw new Exception( + 'Missing mandatory \'id\' parameter in service definition', + Exception::INCOMPLETE_SERVICE_SPECS + ); } // try to guess service type if not provided - if($rawDefinition->lacks('type')) - { + if ($rawDefinition->lacks('type')) { $matchingTypes = []; - foreach(['instance' => PrefabServiceSpecs::class, 'class' => ClassServiceSpecs::class, 'factory' => DelegatedFactorySpecs::class] as $key => $type) - { - if($rawDefinition->has($key)) $matchingTypes[] = $type; + $types = [ + 'instance' => PrefabServiceSpecs::class, + 'class' => ClassServiceSpecs::class, + 'factory' => DelegatedFactorySpecs::class + ]; + + foreach ($types as $key => $type) { + if ($rawDefinition->has($key)) { + $matchingTypes[] = $type; + } } - if(!$matchingTypes) - { - // throw new Exception('The service specs factory has not been able to guess what type of service has been passed. Please check your syntax, or explicitly define the "type" key in your service specifications', Exception::INCOMPLETE_SERVICE_SPECS); + if (!$matchingTypes) { + // throw new Exception('The service specs factory has not been able to guess what type of service + // has been passed. Please check your syntax, or explicitly define the "type" key + // in your service specifications', Exception::INCOMPLETE_SERVICE_SPECS); // default to UndefinedService $matchingTypes[] = UndefinedServiceSpecs::class; } - if(count($matchingTypes) > 1) - { - throw new Exception('Service specifications are ambiguous: they contain both "instance" and "class" key. Please remove the unneeded oneor explicitly define the "type" key in your service specifications ', Exception::AMBIGUOUS_SERVICE_SPECS); + if (count($matchingTypes) > 1) { + throw new Exception( + 'Service specifications are ambiguous: they contain both "instance" and "class" key. + Please remove the unneeded oneor explicitly define the "type" key in your service specifications ', + Exception::AMBIGUOUS_SERVICE_SPECS + ); } // only one match @@ -184,17 +196,19 @@ static function factory($rawDefinition) $serviceDefinition = call_user_func([$rawDefinition['type'], 'factory'], $rawDefinition); // static - if ($rawDefinition->has('static')) - { + if ($rawDefinition->has('static')) { $serviceDefinition->setStatic($rawDefinition['static']); } // aliases - if ($rawDefinition->has('alias') || $rawDefinition->has('aliases')) - { + if ($rawDefinition->has('alias') || $rawDefinition->has('aliases')) { $aliases = new Collection(); - if ($rawDefinition->has('alias')) $aliases[] = $rawDefinition['alias']; - if ($rawDefinition->has('aliases')) $aliases->merge($rawDefinition['aliases']); + if ($rawDefinition->has('alias')) { + $aliases[] = $rawDefinition['alias']; + } + if ($rawDefinition->has('aliases')) { + $aliases->merge($rawDefinition['aliases']); + } $serviceDefinition->setAliases($aliases); } @@ -254,5 +268,4 @@ protected function getAutoAlias() { return null; } - } diff --git a/src/Specs/ClassServiceSpecs.php b/src/Specs/ClassServiceSpecs.php index 96eeaa6..693b7e0 100644 --- a/src/Specs/ClassServiceSpecs.php +++ b/src/Specs/ClassServiceSpecs.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory\Specs; - use ObjectivePHP\Primitives\Collection\Collection; use ObjectivePHP\Primitives\String\Str; use ObjectivePHP\ServicesFactory\Exception\Exception; @@ -46,33 +45,29 @@ public function __construct($id, $class, $params = []) * @param array|Collection $rawDefinition * @throws Exception */ - static public function factory($rawDefinition) + public static function factory($rawDefinition) { $rawDefinition = Collection::cast($rawDefinition); // then check check a class has been provided - if (!$rawDefinition->has('class')) - { + if (!$rawDefinition->has('class')) { throw new Exception('Missing \'class\' parameter', Exception::INCOMPLETE_SERVICE_SPECS); } - if (!is_string($class = $rawDefinition['class'])) - { + if (!is_string($class = $rawDefinition['class'])) { throw new Exception('\'class\' parameter has to be a string', Exception::INVALID_SERVICE_SPECS); } $serviceDefinition = new ClassServiceSpecs($rawDefinition['id'], $class); // constructor params - if ($rawDefinition->has('params')) - { + if ($rawDefinition->has('params')) { $serviceDefinition->setParams($rawDefinition['params']); } // setters - if ($rawDefinition->has('setters')) - { + if ($rawDefinition->has('setters')) { $serviceDefinition->setSetters($rawDefinition['setters']); } @@ -123,12 +118,10 @@ public function setClass($class) public function getAutoAlias() { - if ($this->isAutoAliasingEnabled()) - { + if ($this->isAutoAliasingEnabled()) { return strtolower(ltrim($this->class, '\\')); + } else { + return null; } - else return null; } - - } diff --git a/src/Specs/DelegatedFactorySpecs.php b/src/Specs/DelegatedFactorySpecs.php index 23e32de..6fd95e0 100644 --- a/src/Specs/DelegatedFactorySpecs.php +++ b/src/Specs/DelegatedFactorySpecs.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory\Specs; - use ObjectivePHP\Invokable\Invokable; use ObjectivePHP\Invokable\InvokableInterface; use ObjectivePHP\Primitives\Collection\Collection; @@ -41,22 +40,20 @@ public function __construct($id, $factory, $params = []) * @param array|Collection $rawDefinition * @throws Exception */ - static public function factory($rawDefinition) + public static function factory($rawDefinition) { $rawDefinition = Collection::cast($rawDefinition); // then check check a class has been provided - if (!$rawDefinition->has('factory')) - { + if (!$rawDefinition->has('factory')) { throw new Exception('Missing \'factory\' parameter', Exception::INCOMPLETE_SERVICE_SPECS); } $serviceDefinition = new DelegatedFactorySpecs($rawDefinition['id'], $rawDefinition['factory']); // constructor params - if ($rawDefinition->has('params')) - { + if ($rawDefinition->has('params')) { $serviceDefinition->setParams($rawDefinition['params']); } @@ -92,6 +89,4 @@ public function getAutoAlias() { return null; } - - } diff --git a/src/Specs/InjectionAnnotationProvider.php b/src/Specs/InjectionAnnotationProvider.php index ef60c9e..79130dd 100644 --- a/src/Specs/InjectionAnnotationProvider.php +++ b/src/Specs/InjectionAnnotationProvider.php @@ -9,4 +9,4 @@ interface InjectionAnnotationProvider { -} \ No newline at end of file +} diff --git a/src/Specs/PrefabServiceSpecs.php b/src/Specs/PrefabServiceSpecs.php index 271a479..1e03897 100644 --- a/src/Specs/PrefabServiceSpecs.php +++ b/src/Specs/PrefabServiceSpecs.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory\Specs; - use ObjectivePHP\Primitives\Collection\Collection; use ObjectivePHP\ServicesFactory\Exception\Exception; @@ -25,12 +24,11 @@ public function __construct($id, $instance) $this->setInstance($instance); } - static public function factory($rawDefinition) + public static function factory($rawDefinition) { $rawDefinition = Collection::cast($rawDefinition); - if (!$rawDefinition->has('instance')) - { + if (!$rawDefinition->has('instance')) { throw new Exception('Missing \'instance\' parameter', Exception::INCOMPLETE_SERVICE_SPECS); } @@ -60,10 +58,10 @@ public function setInstance($instance) protected function getAutoAlias() { - if ($this->isAutoAliasingEnabled() && is_object($this->instance)) - { + if ($this->isAutoAliasingEnabled() && is_object($this->instance)) { return strtolower(ltrim(get_class($this->instance), '\\')); + } else { + return null; } - else return null; } } diff --git a/src/Specs/ServiceSpecsInterface.php b/src/Specs/ServiceSpecsInterface.php index 40974f9..8fee730 100644 --- a/src/Specs/ServiceSpecsInterface.php +++ b/src/Specs/ServiceSpecsInterface.php @@ -2,7 +2,6 @@ namespace ObjectivePHP\ServicesFactory\Specs; - interface ServiceSpecsInterface { @@ -29,4 +28,4 @@ public function isStatic(); * @return bool */ public function isFinal(); -} \ No newline at end of file +} diff --git a/src/Specs/UndefinedServiceSpecs.php b/src/Specs/UndefinedServiceSpecs.php index d1c4459..794fe33 100644 --- a/src/Specs/UndefinedServiceSpecs.php +++ b/src/Specs/UndefinedServiceSpecs.php @@ -8,34 +8,32 @@ */ namespace ObjectivePHP\ServicesFactory\Specs; - - + use ObjectivePHP\ServicesFactory\Specs\AbstractServiceSpecs; - class UndefinedServiceSpecs extends AbstractServiceSpecs - { +class UndefinedServiceSpecs extends AbstractServiceSpecs +{ - /** + /** * @param $id * @param array $params * */ - public function __construct($id, $params = []) - { - parent::__construct($id); - - $this->setParams($params); - } + public function __construct($id, $params = []) + { + parent::__construct($id); - static function factory($rawDefinition) - { - $id = $rawDefinition['id']; - unset($rawDefinition['id']); - $params = $rawDefinition; + $this->setParams($params); + } + public static function factory($rawDefinition) + { + $id = $rawDefinition['id']; + unset($rawDefinition['id']); + $params = $rawDefinition; - return new static($id, $params); - } + return new static($id, $params); } +} diff --git a/tests/ServicesFactory/ServicesFactoryTest.php b/tests/ServicesFactory/ServicesFactoryTest.php index 5055d7b..b00cfcf 100644 --- a/tests/ServicesFactory/ServicesFactoryTest.php +++ b/tests/ServicesFactory/ServicesFactoryTest.php @@ -14,9 +14,11 @@ use Fancy\Service\SimpleAnnotatedServiceReferringAnotherService; use Fancy\Service\SimpleAnnotatedServiceWitImplicitDependency; use Fancy\Service\TestService; + use Interop\Container\ContainerInterface; use ObjectivePHP\Config\Config; use ObjectivePHP\Invokable\InvokableInterface; use ObjectivePHP\PHPUnit\TestCase; + use ObjectivePHP\Primitives\Collection\Collection; use ObjectivePHP\ServicesFactory\Builder\ClassServiceBuilder; use ObjectivePHP\ServicesFactory\Builder\ServiceBuilderInterface; use ObjectivePHP\ServicesFactory\Exception\Exception; @@ -564,6 +566,71 @@ public function testAutoAliasing() $this->assertInstanceOf(TestService::class, $service); } + + public function testRegisterParentContainer() + { + $servicesFactory = new ServicesFactory(); + + $siblings = []; + $siblings[] = $this->getMockBuilder(ServicesFactory::class)->getMock(); + $siblings[] = $this->getMockBuilder(ServicesFactory::class)->getMock(); + $siblings[] = $this->getMockBuilder(ServicesFactory::class)->getMock(); + + $return = $servicesFactory->registerSiblingContainer(...$siblings); + + $expected = []; + array_push($expected, ...$siblings); + + $this->assertAttributeEquals($expected, 'siblings', $servicesFactory); + $this->assertEquals($servicesFactory, $return); + } + + /** + * @throws \ObjectivePHP\Primitives\Exception + */ + public function testGetConfigParamToInjectWhenNoConfig() + { + $servicesFactory = new ServicesFactory(); + + $instance = new class implements InjectionAnnotationProvider{ + /** + * @Inject(param="APP_MODE") + */ + protected $mode; + }; + + $this->expectException(Exception::class); + $this->expectExceptionMessage('No Config is registered as "config" neither in this factory nor in its siblings'); + $servicesFactory->injectDependencies($instance); + } + + /** + * @throws \ObjectivePHP\Primitives\Exception + * @throws Exception + */ + public function testGetConfigParamToInjectWhenNoConfigDoesNotExists() + { + $params = new Collection(); + $config = $this->getMockBuilder(Config::class)->setMethods(['subset'])->getMock(); + $config->expects($this->once())->method('subset')->with('ObjectivePHP\Application\Config\Param')->willReturn($params); + + $servicesFactory = new ServicesFactory(); + $servicesFactory->registerService([ + 'id' => 'config', + 'instance' => $config + ]); + + $instance = new class implements InjectionAnnotationProvider{ + /** + * @Inject(param="APP_MODE") + */ + protected $mode; + }; + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Config instance registered as "config" does not have a "APP_MODE" param, and no default value is provided'); + $servicesFactory->injectDependencies($instance); + } } }