Skip to content

Commit

Permalink
refactor: extract container auto-injection from resolver class
Browse files Browse the repository at this point in the history
Signed-off-by: Fery Wardiyanto <ferywardiyanto@gmail.com>
  • Loading branch information
feryardiant committed Dec 20, 2023
1 parent 32c70fc commit a146445
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 17 deletions.
15 changes: 12 additions & 3 deletions src/Container.php
Expand Up @@ -115,11 +115,20 @@ public function set(string $id, $factory): self
return $this;
}

$this->entries[$id] = $this->resolver->resolve($factory);
$this->factories[$id] = \is_object($factory) && ! ($factory instanceof \Closure)
? \get_class($factory)
: $factory;

$entry = $this->resolver->resolve($this->factories[$id]);

if (\is_object($entry) &&
($entry instanceof Container\ContainerAware && null === $entry->getContainer())
) {
$entry->setContainer($this);
}

$this->entries[$id] = $entry;

if (isset($this->handledEntries[$id])) {
unset($this->handledEntries[$id]);
}
Expand Down Expand Up @@ -201,8 +210,8 @@ public function extend(string $id, \Closure $callback): object
{
$entry = $this->get($id);

// We tread any callable like a factory which could returns different instance
// when it invoked. So we should only extend object instance.
// We treat any callable as a factory function which is might be returns
// a different instance when it get invoked. So we should only extend an object.
if (! \is_object($entry) || \method_exists($entry, '__invoke')) {
throw new Container\Exception(
\sprintf('Cannot extending a non-object or a callable entry of "%s"', $id)
Expand Down
27 changes: 14 additions & 13 deletions src/Container/Resolver.php
Expand Up @@ -5,6 +5,7 @@
namespace Projek\Container;

use Projek\Container;
use Psr\Container\ContainerInterface;

/**
* Container factory resolver class.
Expand All @@ -14,16 +15,21 @@
* @package Projek\Container
* @internal
*/
final class Resolver extends AbstractContainerAware
final class Resolver
{
/**
* @var ContainerInterface Container instance.
*/
private $container;

/**
* Create instance.
*
* @param Container $container
*/
public function __construct(Container $container)
public function __construct(ContainerInterface $container)
{
$this->setContainer($container);
$this->container = $container;
}

/**
Expand All @@ -45,23 +51,17 @@ public function resolve($entry, array $args = [])
: \explode('::', $entry);
}

if (\is_object($entry)) {
if ($entry instanceof ContainerAware && null === $entry->getContainer()) {
$entry->setContainer($this->getContainer());
}

return $entry;
}

if (\is_array($entry) && \is_string($entry[0])) {
$entry[0] = $this->resolve($entry[0], $args);
}

if (\is_callable($entry)) {
if (\is_object($entry) || \is_callable($entry)) {
return $entry;
}

throw new InvalidArgumentException(\sprintf('Cannot resolve invalid entry of %s', \gettype($entry)));
throw new InvalidArgumentException(
\sprintf('Cannot resolve invalid entry of "%s"', \gettype($entry))
);
}

/**
Expand Down Expand Up @@ -155,6 +155,7 @@ private function createInstance(string $className, array $args = []): object
private function createCallableReflection($callable)
{
if (\is_string($callable) && false !== \strpos($callable, '::')) {
/** @var array<string> */
$callable = \explode('::', $callable);
}

Expand Down
12 changes: 11 additions & 1 deletion tests/spec/Container.spec.php
Expand Up @@ -159,6 +159,16 @@
expect($this->c->get('void'))->toBeEmpty();
});

it('shoud able to auto-inject container', function () {
$this->c->set('injectable', Stubs\HasContainerClass::class);

/** @var Stubs\HasContainerClass */
$injected = $this->c->get('injectable');

expect($injected)->toBeAnInstanceOf(Container\ContainerAware::class);
expect($injected->getContainer())->toBe($this->c);
});

it('shoud able to register callable service', function () {
// dependency of Stubs\CallableClass::__invoke method
$this->c->set(Stubs\AbstractFoo::class, Stubs\ConcreteBar::class);
Expand Down Expand Up @@ -208,7 +218,7 @@

expect(function () {
$this->c->set('foo', null);
})->toThrow(new Container\InvalidArgumentException('Cannot resolve invalid entry of NULL'));
})->toThrow(new Container\InvalidArgumentException('Cannot resolve invalid entry of "NULL"'));
});
});

Expand Down
10 changes: 10 additions & 0 deletions tests/stub/HasContainerClass.php
@@ -0,0 +1,10 @@
<?php

namespace Stubs;

use Projek\Container\AbstractContainerAware;

class HasContainerClass extends AbstractContainerAware
{
// .
}

0 comments on commit a146445

Please sign in to comment.