diff --git a/src/external/ContainerBasedInjector.php b/src/external/ContainerBasedInjector.php new file mode 100644 index 0000000..ca8736f --- /dev/null +++ b/src/external/ContainerBasedInjector.php @@ -0,0 +1,34 @@ + + * @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); + } +} \ No newline at end of file diff --git a/src/external/ContainerProxy.php b/src/external/ContainerProxy.php new file mode 100644 index 0000000..684ab22 --- /dev/null +++ b/src/external/ContainerProxy.php @@ -0,0 +1,132 @@ +container->getKnownEntryNames(), true); + * } + * } + * ``` + * + * @author Paul Klimov + * @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); + } +} \ No newline at end of file diff --git a/tests/external/ContainerBasedInjectorTest.php b/tests/external/ContainerBasedInjectorTest.php new file mode 100644 index 0000000..b4730a3 --- /dev/null +++ b/tests/external/ContainerBasedInjectorTest.php @@ -0,0 +1,88 @@ +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]); + } +} \ No newline at end of file diff --git a/tests/external/ContainerProxyTest.php b/tests/external/ContainerProxyTest.php new file mode 100644 index 0000000..1b9a873 --- /dev/null +++ b/tests/external/ContainerProxyTest.php @@ -0,0 +1,49 @@ +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)); + } +} \ No newline at end of file diff --git a/tests/support/SelfInjectingContainer.php b/tests/support/SelfInjectingContainer.php new file mode 100644 index 0000000..56a6923 --- /dev/null +++ b/tests/support/SelfInjectingContainer.php @@ -0,0 +1,28 @@ +invoke($this, $callable, $arguments); + } + + public function make(string $class, array $arguments = []) + { + return (new Injector())->make($this, $class, $arguments); + } +} \ No newline at end of file