-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4d655cb
commit cec90ce
Showing
5 changed files
with
331 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
namespace yii1tech\di\external; | ||
|
||
use Psr\Container\ContainerInterface; | ||
use yii1tech\di\InjectorContract; | ||
|
||
/** | ||
* ContainerBasedInjector forwards dependency injection resolution to the container. | ||
* | ||
* It expects passing container to implement methods `make()` and `call()`, since it is widely used notation. | ||
* This injection can be used with some external (3rd party) containers. | ||
* | ||
* @author Paul Klimov <[email protected]> | ||
* @since 1.0 | ||
*/ | ||
class ContainerBasedInjector implements InjectorContract | ||
{ | ||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function invoke(ContainerInterface $container, callable $callable, array $arguments = []) | ||
{ | ||
return $container->call($callable, $arguments); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function make(ContainerInterface $container, string $class, array $arguments = []) | ||
{ | ||
return $container->make($class, $arguments); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
<?php | ||
|
||
namespace yii1tech\di\external; | ||
|
||
use Psr\Container\ContainerInterface; | ||
|
||
/** | ||
* ContainerProxy wraps another container and forwards all method calls to it. | ||
* | ||
* This class can be used to resolve inconsistencies in particular container implementation. | ||
* Usually to fix behavior of `has()` method. | ||
* | ||
* For example: | ||
* | ||
* ```php | ||
* class PhpDiContainerProxy extends ContainerProxy | ||
* { | ||
* public function has(string $id): bool | ||
* { | ||
* return in_array($id, $this->container->getKnownEntryNames(), true); | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* @author Paul Klimov <[email protected]> | ||
* @since 1.0 | ||
*/ | ||
class ContainerProxy implements ContainerInterface | ||
{ | ||
/** | ||
* @var \Psr\Container\ContainerInterface wrapped container instance. | ||
*/ | ||
protected $container; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param \Psr\Container\ContainerInterface $container container instance to be wrapped. | ||
*/ | ||
public function __construct(ContainerInterface $container) | ||
{ | ||
$this->container = $container; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function get(string $id) | ||
{ | ||
return $this->container->get($id); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function has(string $id): bool | ||
{ | ||
return $this->container->has($id); | ||
} | ||
|
||
/** | ||
* Calls the named method which is not a class method. | ||
* Do not call this method. This is a PHP magic method that forwards calls to the wrapped container. | ||
* | ||
* @param string $name the method name. | ||
* @param array $parameters method parameters. | ||
* @return mixed the method return value. | ||
*/ | ||
public function __call($name, $parameters) | ||
{ | ||
return call_user_func_array([$this->container, $name], $parameters); | ||
} | ||
|
||
/** | ||
* Returns a property value. | ||
* Do not call this method. This is a PHP magic method that forwards property resolution to the wrapped container. | ||
* | ||
* @param string $name the property name. | ||
* @return mixed the property value. | ||
*/ | ||
public function __get($name) | ||
{ | ||
return $this->container->$name; | ||
} | ||
|
||
/** | ||
* Sets a property value. | ||
* Do not call this method. This is a PHP magic method that forwards property resolution to the wrapped container. | ||
* | ||
* @param string $name the property name. | ||
* @param mixed $value the property value. | ||
*/ | ||
public function __set($name, $value) | ||
{ | ||
$this->container->$name = $value; | ||
} | ||
|
||
/** | ||
* Checks if a property value is null. | ||
* Do not call this method. This is a PHP magic method that forwards property resolution to the wrapped container. | ||
* | ||
* @param string $name the property name. | ||
* @return bool whether property it `null`. | ||
*/ | ||
public function __isset($name) | ||
{ | ||
return isset($this->container->$name); | ||
} | ||
|
||
/** | ||
* Sets a component property to be null. | ||
* Do not call this method. This is a PHP magic method that forwards property resolution to the wrapped container. | ||
* | ||
* @param string $name the property name. | ||
*/ | ||
public function __unset($name) | ||
{ | ||
unset($this->container->$name); | ||
} | ||
|
||
/** | ||
* Creates new self instance. | ||
* This method can be useful when writing chain methods calls. | ||
* | ||
* @param mixed ...$args constructor arguments. | ||
* @return static new self instance. | ||
*/ | ||
public static function new(...$args): self | ||
{ | ||
return new static(...$args); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<?php | ||
|
||
namespace yii1tech\di\test\external; | ||
|
||
use CDbConnection; | ||
use CDummyCache; | ||
use ICache; | ||
use yii1tech\di\external\ContainerBasedInjector; | ||
use yii1tech\di\test\support\DummyWithDependency; | ||
use yii1tech\di\test\support\SelfInjectingContainer; | ||
use yii1tech\di\test\TestCase; | ||
|
||
class ContainerBasedInjectorTest extends TestCase | ||
{ | ||
public function testMake(): void | ||
{ | ||
$container = new SelfInjectingContainer(); | ||
$container->instance(CDbConnection::class, new CDbConnection()); | ||
$container->instance(ICache::class, new CDummyCache()); | ||
|
||
$injector = new ContainerBasedInjector(); | ||
|
||
/** @var DummyWithDependency $object */ | ||
$object = $injector->make($container, DummyWithDependency::class); | ||
|
||
$this->assertTrue($object instanceof DummyWithDependency); | ||
$this->assertSame($container->get(CDbConnection::class), $object->constructorArgs[0]); | ||
$this->assertSame($container->get(ICache::class), $object->constructorArgs[1]); | ||
$this->assertSame(null, $object->constructorArgs[2]); | ||
$this->assertSame('tail', $object->constructorArgs[3]); | ||
} | ||
|
||
/** | ||
* @depends testMake | ||
*/ | ||
public function testMakeWithArguments(): void | ||
{ | ||
$container = new SelfInjectingContainer(); | ||
$container->instance(CDbConnection::class, new CDbConnection()); | ||
|
||
$injector = new ContainerBasedInjector(); | ||
|
||
$cache = new CDummyCache(); | ||
$tail = 'explicit-set-tail'; | ||
|
||
/** @var DummyWithDependency $object */ | ||
$object = $injector->make($container, DummyWithDependency::class, ['cache' => $cache, 'tail' => $tail]); | ||
|
||
$this->assertTrue($object instanceof DummyWithDependency); | ||
$this->assertSame($cache, $object->constructorArgs[1]); | ||
$this->assertSame($tail, $object->constructorArgs[3]); | ||
} | ||
|
||
public function testInvoke(): void | ||
{ | ||
$container = new SelfInjectingContainer(); | ||
$container->instance(CDbConnection::class, new CDbConnection()); | ||
$container->instance(ICache::class, new CDummyCache()); | ||
|
||
$injector = new ContainerBasedInjector(); | ||
|
||
$result = $injector->invoke($container, [DummyWithDependency::class, 'returnArguments']); | ||
|
||
$this->assertSame($container->get(CDbConnection::class), $result[0]); | ||
$this->assertSame($container->get(ICache::class), $result[1]); | ||
$this->assertSame(null, $result[2]); | ||
$this->assertSame('tail', $result[3]); | ||
} | ||
|
||
/** | ||
* @depends testInvoke | ||
*/ | ||
public function testInvokeWithArguments(): void | ||
{ | ||
$container = new SelfInjectingContainer(); | ||
$container->instance(CDbConnection::class, new CDbConnection()); | ||
|
||
$injector = new ContainerBasedInjector(); | ||
|
||
$cache = new CDummyCache(); | ||
$tail = 'explicit-set-tail'; | ||
|
||
$result = $injector->invoke($container, [DummyWithDependency::class, 'returnArguments'], ['cache' => $cache, 'tail' => $tail]); | ||
|
||
$this->assertSame($cache, $result[1]); | ||
$this->assertSame($tail, $result[3]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
namespace yii1tech\di\test\external; | ||
|
||
use ArrayObject; | ||
use yii1tech\di\Container; | ||
use yii1tech\di\external\ContainerProxy; | ||
use yii1tech\di\test\TestCase; | ||
|
||
class ContainerProxyTest extends TestCase | ||
{ | ||
public function testHas(): void | ||
{ | ||
$container = new Container(); | ||
|
||
$container->instance(ArrayObject::class, new ArrayObject()); | ||
|
||
$proxy = new ContainerProxy($container); | ||
|
||
$this->assertTrue($proxy->has(ArrayObject::class)); | ||
$this->assertFalse($proxy->has('unexistint-id')); | ||
} | ||
|
||
public function testGet(): void | ||
{ | ||
$container = new Container(); | ||
|
||
$object = new ArrayObject(); | ||
$container->instance(ArrayObject::class, $object); | ||
|
||
$proxy = new ContainerProxy($container); | ||
|
||
$this->assertSame($object, $proxy->get(ArrayObject::class)); | ||
} | ||
|
||
/** | ||
* @depends testHas | ||
*/ | ||
public function testForwardCall(): void | ||
{ | ||
$container = new Container(); | ||
|
||
$proxy = new ContainerProxy($container); | ||
|
||
$proxy->instance(ArrayObject::class, new ArrayObject()); | ||
|
||
$this->assertTrue($proxy->has(ArrayObject::class)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
namespace yii1tech\di\test\support; | ||
|
||
use yii1tech\di\Container; | ||
use yii1tech\di\external\ContainerProxy; | ||
use yii1tech\di\Injector; | ||
|
||
/** | ||
* @method instance(string $id, mixed $object) | ||
*/ | ||
class SelfInjectingContainer extends ContainerProxy | ||
{ | ||
public function __construct() | ||
{ | ||
parent::__construct(new Container()); | ||
} | ||
|
||
public function call(callable $callable, array $arguments = []) | ||
{ | ||
return (new Injector())->invoke($this, $callable, $arguments); | ||
} | ||
|
||
public function make(string $class, array $arguments = []) | ||
{ | ||
return (new Injector())->make($this, $class, $arguments); | ||
} | ||
} |