Skip to content

Commit

Permalink
feat: autowire any ContainerAwareInterface instances
Browse files Browse the repository at this point in the history
Signed-off-by: Fery Wardiyanto <ferywardiyanto@gmail.com>
  • Loading branch information
feryardiant committed Jul 7, 2020
1 parent 94b30be commit da3669e
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 26 deletions.
10 changes: 0 additions & 10 deletions src/Container/ArrayContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 0 additions & 10 deletions src/Container/PropertyContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 23 additions & 4 deletions src/Container/Resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ class Resolver implements ContainerAwareInterface
{
use ContainerAware;

/**
* @var array<string, string[]>
*/
private $traitsMap;

/**
* Create new instance.
*
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

/**
Expand Down
30 changes: 28 additions & 2 deletions test/spec/Resolver.spec.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
<?php

use Projek\Container;
use Projek\Container\ContainerAware;
use Projek\Container\ContainerAwareInterface;
use Projek\Container\ContainerInterface;
use Projek\Container\Resolver;
use Stubs\ { Dummy, AbstractFoo, ConcreteBar };
use Stubs\ { Dummy, AbstractFoo, CloneContainer, ConcreteBar };
use function Kahlan\describe;
use function Kahlan\expect;
use function Kahlan\given;
use function Stubs\dummyLorem;

describe(Resolver::class, function () {
given('dummy', function () {
Expand Down Expand Up @@ -100,4 +102,28 @@
$this->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();
});
});
21 changes: 21 additions & 0 deletions test/stub/CloneContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Stubs;

use Projek\Container\{ContainerAware, ContainerAwareInterface, ContainerInterface};

class CloneContainer implements ContainerAwareInterface
{
use ContainerAware;

public function __construct(ContainerInterface $container)
{
$clone = clone $container;

$clone->set('foobar', function () {
return 'value';
});

$this->setContainer($clone);
}
}

0 comments on commit da3669e

Please sign in to comment.