diff --git a/src/Container/ArrayContainer.php b/src/Container/ArrayContainer.php index 347f47e..8900acd 100644 --- a/src/Container/ArrayContainer.php +++ b/src/Container/ArrayContainer.php @@ -8,16 +8,6 @@ final class ArrayContainer implements \ArrayAccess, ContainerAwareInterface { use ContainerAware; - /** - * Create new instance. - * - * @param ContainerInterface $container - */ - public function __construct(ContainerInterface $container) - { - $this->setContainer($container); - } - /** * @param string $name * @param mixed $instance diff --git a/src/Container/PropertyContainer.php b/src/Container/PropertyContainer.php index db3aad6..b817ced 100644 --- a/src/Container/PropertyContainer.php +++ b/src/Container/PropertyContainer.php @@ -8,16 +8,6 @@ final class PropertyContainer implements ContainerAwareInterface { use ContainerAware; - /** - * Create new instance. - * - * @param ContainerInterface $container - */ - public function __construct(ContainerInterface $container) - { - $this->setContainer($container); - } - /** * @param string $name * @param mixed $instance diff --git a/src/Container/Resolver.php b/src/Container/Resolver.php index 818b8a7..11d71db 100644 --- a/src/Container/Resolver.php +++ b/src/Container/Resolver.php @@ -10,6 +10,11 @@ class Resolver implements ContainerAwareInterface { use ContainerAware; + /** + * @var array + */ + private $traitsMap; + /** * Create new instance. * @@ -79,7 +84,15 @@ public function resolve($concrete) return $concrete; } - if ($concrete instanceof \Closure || is_object($concrete) || is_callable($concrete)) { + if ($concrete instanceof \Closure || is_callable($concrete)) { + return $concrete; + } + + if (is_object($concrete)) { + if ($concrete instanceof ContainerAwareInterface && null === $concrete->getContainer()) { + $concrete->setContainer($this->getContainer()); + } + return $concrete; } @@ -108,11 +121,17 @@ protected function createInstance(string $className) throw new Exception(sprintf('Target "%s" is not instantiable.', $className)); } - if ($constructor = $reflector->getConstructor()) { - return $reflector->newInstanceArgs($this->resolveArgs($constructor)); + $args = ($constructor = $reflector->getConstructor()) ? $this->resolveArgs($constructor) : []; + $instance = $reflector->newInstanceArgs($args); + + if ( + $reflector->implementsInterface(ContainerAwareInterface::class) + && null === $reflector->getMethod('getContainer')->invoke($instance) + ) { + $reflector->getMethod('setContainer')->invoke($instance, $this->getContainer()); } - return $reflector->newInstance(); + return $instance; } /** diff --git a/test/spec/Resolver.spec.php b/test/spec/Resolver.spec.php index a88dd4a..e282fa6 100644 --- a/test/spec/Resolver.spec.php +++ b/test/spec/Resolver.spec.php @@ -1,12 +1,14 @@ r->resolve($this->dummy) )->toBeAnInstanceOf(Dummy::class); }); + + it('should autowire '.ContainerAwareInterface::class.' instance', function () { + $class = new class implements ContainerAwareInterface { + use ContainerAware; + }; + + // Assign the original container. + + /** @var ContainerInterface $container */ + $container = $this->r->resolve($class)->getContainer(); + expect($container)->toBeAnInstanceOf(ContainerInterface::class); + expect($container->has('foobar'))->toBeFalsy(); + + $container = $this->r->resolve(get_class($class))->getContainer(); + expect($container)->toBeAnInstanceOf(ContainerInterface::class); + expect($container->has('foobar'))->toBeFalsy(); + + // Modify container stack interally + + $clone = $this->r->resolve(CloneContainer::class)->getContainer(); + expect($clone)->toBeAnInstanceOf(ContainerInterface::class); + expect($clone->has('foobar'))->toBeTruthy(); + expect($container->has('foobar'))->toBeFalsy(); + }); }); diff --git a/test/stub/CloneContainer.php b/test/stub/CloneContainer.php new file mode 100644 index 0000000..75f8c45 --- /dev/null +++ b/test/stub/CloneContainer.php @@ -0,0 +1,21 @@ +set('foobar', function () { + return 'value'; + }); + + $this->setContainer($clone); + } +}