Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add container proxy #116

Merged
merged 44 commits into from
Mar 5, 2020
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
1fc7172
Add container proxy
yiiliveext Mar 1, 2020
b75ace8
Minor fix
yiiliveext Mar 1, 2020
0b8ab53
Fix proxy container
yiiliveext Mar 1, 2020
62e9e22
Minor fixes
yiiliveext Mar 2, 2020
af5328a
Refactor names
yiiliveext Mar 2, 2020
6d400bb
Add custom array-proxy config type
yiiliveext Mar 2, 2020
933f2c3
Rename collectData method
yiiliveext Mar 2, 2020
5673e09
Add result decoration ability
yiiliveext Mar 2, 2020
575cf8f
Add method decoration from params
yiiliveext Mar 2, 2020
303ef59
Refactor proxy data log
yiiliveext Mar 2, 2020
ef844ed
Fix class caching bug
yiiliveext Mar 2, 2020
238f22f
Allow multiple methods decorators
yiiliveext Mar 2, 2020
94fcbbd
Fix isActive method
yiiliveext Mar 2, 2020
45cc386
Fix composer.json
yiiliveext Mar 2, 2020
c4eecaa
Move classes to other packages
yiiliveext Mar 2, 2020
8e4582b
Fix composer.json
yiiliveext Mar 2, 2020
bead8aa
Fix composite container
yiiliveext Mar 2, 2020
9e1b67b
Add composite container proxy support
yiiliveext Mar 3, 2020
d396b1f
Add delegate interface
yiiliveext Mar 3, 2020
c630119
Add public constructor to container
yiiliveext Mar 3, 2020
1df7c9a
Fix root container
yiiliveext Mar 3, 2020
fbe6c88
Add phpdoc
yiiliveext Mar 3, 2020
e9a6e85
Remove static builder method
yiiliveext Mar 3, 2020
4cb3044
Fix tests
yiiliveext Mar 3, 2020
c1077eb
Fix container builder
yiiliveext Mar 3, 2020
3194749
Rename add providerd method
yiiliveext Mar 3, 2020
e4365e4
Fix addProviders method call
yiiliveext Mar 3, 2020
f168809
Rename withRootContainer method
yiiliveext Mar 4, 2020
f22c04c
Remove public modificator from container setters
yiiliveext Mar 4, 2020
7227a61
Refactor service provider
yiiliveext Mar 4, 2020
6c96ac9
A bit of refactoring
yiiliveext Mar 4, 2020
abb34db
Remove unused $delegateLookup parameter
samdark Mar 4, 2020
22e00da
Adjusted docs
samdark Mar 4, 2020
9b58c5f
Make containers classes final
yiiliveext Mar 4, 2020
9c3e574
Make delegateLookup protected
yiiliveext Mar 4, 2020
34fe6f8
Add dlegate lookup tests
yiiliveext Mar 4, 2020
0673178
Update readme
yiiliveext Mar 4, 2020
3788ad8
Fix readme typo
yiiliveext Mar 4, 2020
fa39f9f
Fix tests
yiiliveext Mar 4, 2020
f35b570
Readme fixes
samdark Mar 4, 2020
7fdb599
Add delegate proxy test
yiiliveext Mar 4, 2020
e8887c4
Remove comments, fix style
yiiliveext Mar 4, 2020
69ce62d
Fix CS [skip ci]
yiiliveext Mar 4, 2020
6c9c0c1
Test name adjusted
samdark Mar 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/CompositeContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,15 @@ public function has($id)

/**
* Attaches a container to the composite container.
* When $delegateLookup set to true, dependencies will be looked for in composite container instead of
* in $container directly. When set to false, dependencies would be looked for in $container only.
* @param ContainerInterface $container
*/
public function attach(ContainerInterface $container): void
public function attach(ContainerInterface $container, bool $delegateLookup = false): void
yiiliveext marked this conversation as resolved.
Show resolved Hide resolved
{
if ($delegateLookup && $container instanceof ContainerDelegateInterface) {
$container = $container->withRootContainer($this);
yiiliveext marked this conversation as resolved.
Show resolved Hide resolved
}
array_unshift($this->containers, $container);
}

Expand Down
33 changes: 27 additions & 6 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/**
* Container implements a [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) container.
*/
class Container implements ContainerInterface
class Container implements ContainerInterface, ContainerDelegateInterface
{
/**
* @var DefinitionInterface[] object definitions indexed by their types
Expand All @@ -34,6 +34,8 @@ class Container implements ContainerInterface
*/
private $instances;

private ?ContainerInterface $rootContainer = null;

/**
* Container constructor.
*
Expand All @@ -48,9 +50,22 @@ public function __construct(
array $providers = []
) {
$this->setMultiple($definitions);
foreach ($providers as $provider) {
$this->addProvider($provider);
$this->registerServiceProviders($providers);
}

public function withRootContainer(ContainerInterface $container): ContainerInterface
yiiliveext marked this conversation as resolved.
Show resolved Hide resolved
{
$newContainer = clone $this;

if ($this->rootContainer === null) {
$newContainer->rootContainer = new CompositeContainer();
yiiliveext marked this conversation as resolved.
Show resolved Hide resolved
} else {
$rootContainer = $this->rootContainer;
$newContainer->rootContainer = clone $rootContainer;
}
$newContainer->rootContainer->attach($container);

return $newContainer;
}

/**
Expand Down Expand Up @@ -124,7 +139,7 @@ private function buildInternal(string $id, array $params = [])
}
$this->processDefinition($this->definitions[$id]);

return $this->definitions[$id]->resolve($this, $params);
return $this->definitions[$id]->resolve($this->rootContainer ?? $this, $params);
}

protected function processDefinition($definition): void
Expand All @@ -134,7 +149,6 @@ protected function processDefinition($definition): void
}
}


/**
* @param string $class
* @param array $params
Expand All @@ -148,7 +162,7 @@ private function buildPrimitive(string $class, array $params = [])
if (class_exists($class)) {
$definition = new ArrayDefinition($class);

return $definition->resolve($this, $params);
return $definition->resolve($this->rootContainer ?? $this, $params);
}

throw new NotFoundException("No definition for $class");
Expand Down Expand Up @@ -179,6 +193,13 @@ public function setMultiple(array $config): void
}
}

public function registerServiceProviders(array $providers): void
yiiliveext marked this conversation as resolved.
Show resolved Hide resolved
{
foreach ($providers as $provider) {
$this->addProvider($provider);
}
}

/**
* Returns a value indicating whether the container has the definition of the specified name.
* @param string $id class name, interface name or alias name
Expand Down
85 changes: 85 additions & 0 deletions src/ContainerBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace Yiisoft\Di;

use Psr\Container\ContainerInterface;
use Psr\Container\ContainerExceptionInterface;
use Yiisoft\Factory\Factory;

final class ContainerBuilder
yiiliveext marked this conversation as resolved.
Show resolved Hide resolved
{
private ContainerInterface $container;

private ?ContainerProxyInterface $containerProxy = null;

private array $decoratedServices = [];

public function __construct(ContainerInterface $container)
{
$this->container = $container;
}

public function setContainerProxy(ContainerProxyInterface $containerProxy): self
{
$this->containerProxy = $containerProxy;
return $this;
}

public function registerDefinitions(array $definitions): self
{
if ($this->container instanceof Container || $this->container instanceof Factory) {
$this->container->setMultiple($definitions);
return $this;
}

throw new \RuntimeException('This method is for Yiisoft\Di\Container and Yiisoft\Factory\Factory only');
}

public function registerServiceProviders(array $providers): self
{
if ($this->container instanceof Container) {
$this->container->registerServiceProviders($providers);
return $this;
}

throw new \RuntimeException('This method is for Yiisoft\Di\Container only');
}

public function addDecoratedService(string $service, $decoration = null): self
{
if ($decoration === null) {
$this->decoratedServices[] = $service;
} else {
$this->decoratedServices[$service] = $decoration;
}
return $this;
}

public function build()
{
if ($this->containerProxy !== null) {
$this->containerProxy = $this->containerProxy->withDecoratedServices($this->decoratedServices);
} elseif ($this->containerProxy === null && $this->container->has(ContainerProxyInterface::class)) {
try {
$containerProxy = $this->container->get(ContainerProxyInterface::class);
if ($containerProxy) {
$this->containerProxy = $containerProxy->withDecoratedServices($this->decoratedServices);
}
} catch (ContainerExceptionInterface $e) {
$this->containerProxy = null;
}
}

return $this->getContainer();
}

private function getContainer(): ContainerInterface
{
return $this->hasActiveProxy() ? $this->containerProxy : $this->container;
}

private function hasActiveProxy(): bool
{
return $this->containerProxy !== null && $this->containerProxy->isActive();
}
}
10 changes: 10 additions & 0 deletions src/ContainerDelegateInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Yiisoft\Di;

use Psr\Container\ContainerInterface;

interface ContainerDelegateInterface
{
public function withRootContainer(ContainerInterface $container): ContainerInterface;
}
12 changes: 12 additions & 0 deletions src/ContainerProxyInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Yiisoft\Di;

use Psr\Container\ContainerInterface;

interface ContainerProxyInterface extends ContainerInterface
yiiliveext marked this conversation as resolved.
Show resolved Hide resolved
{
public function isActive(): bool;

public function withDecoratedServices(array $decoratedServices): ContainerProxyInterface;
}