Skip to content

Commit

Permalink
Add ability to use container as a factory
Browse files Browse the repository at this point in the history
  • Loading branch information
xepozz committed Feb 13, 2024
1 parent d6ab9e7 commit 897f257
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 3 deletions.
30 changes: 27 additions & 3 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ final class Container implements ContainerInterface
{
private const META_TAGS = 'tags';
private const META_RESET = 'reset';
private const ALLOWED_META = [self::META_TAGS, self::META_RESET];
private const META_AFTER_BUILT = 'afterBuilt';
private const ALLOWED_META = [self::META_TAGS, self::META_RESET, self::META_AFTER_BUILT];

/**
* @var DefinitionStorage Storage of object definitions.
Expand Down Expand Up @@ -67,6 +68,12 @@ final class Container implements ContainerInterface
* @var Closure[]
*/
private array $resetters = [];

/**
* @var Closure[]
*/
public array $afterBuiltHooks = [];

private bool $useResettersFromMeta = true;

/**
Expand Down Expand Up @@ -134,10 +141,11 @@ public function has(string $id): bool
*/
public function get(string $id)
{
$result = null;
if (!array_key_exists($id, $this->instances)) {
try {
try {
$this->instances[$id] = $this->build($id);
$result = $this->instances[$id] = $this->build($id);

Check failure on line 148 in src/Container.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.0-ubuntu-latest

MixedAssignment

src/Container.php:148:21: MixedAssignment: Unable to determine the type that $result is being assigned to (see https://psalm.dev/032)
} catch (NotFoundExceptionInterface $e) {
if (!$this->delegates->has($id)) {
throw $e;
Expand All @@ -153,6 +161,7 @@ public function get(string $id)
throw new BuildingException($id, $e, $this->definitions->getBuildStack(), $e);
}
}
$this->callHookAfterBuilt($id);

if ($id === StateResetter::class) {
$delegatesResetter = null;
Expand Down Expand Up @@ -184,7 +193,7 @@ public function get(string $id)
}

/** @psalm-suppress MixedReturnStatement */
return $this->instances[$id];
return $result ?? $this->instances[$id];
}

/**
Expand Down Expand Up @@ -215,6 +224,9 @@ private function addDefinition(string $id, mixed $definition): void
if (isset($meta[self::META_RESET])) {
$this->setDefinitionResetter($id, $meta[self::META_RESET]);
}
if (isset($meta[self::META_AFTER_BUILT])) {
$this->setAfterBuiltHook($id, $meta[self::META_AFTER_BUILT]);

Check failure on line 228 in src/Container.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.0-ubuntu-latest

MixedArgument

src/Container.php:228:43: MixedArgument: Argument 2 of Yiisoft\Di\Container::setAfterBuiltHook cannot be mixed, expecting Closure (see https://psalm.dev/030)
}

unset($this->instances[$id]);
$this->addDefinitionToStorage($id, $definition);
Expand Down Expand Up @@ -621,4 +633,16 @@ private function buildProvider(mixed $provider): ServiceProviderInterface

return $providerInstance;
}

private function callHookAfterBuilt(string $id): void
{
if (isset($this->afterBuiltHooks[$id])) {
$this->afterBuiltHooks[$id]->call($this, $this, $id);
}
}

private function setAfterBuiltHook(string $id, Closure $callback): void
{
$this->afterBuiltHooks[$id] = $callback;
}
}
21 changes: 21 additions & 0 deletions src/Hook/AfterBuiltHook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Di\Hook;

use Closure;
use Yiisoft\Di\Container;

final class AfterBuiltHook
{
public static function unsetInstance(): Closure
{
return function (Container $container, string $id) {
/**
* @var $this Container
*/
unset($this->instances[$id]);

Check failure on line 18 in src/Hook/AfterBuiltHook.php

View workflow job for this annotation

GitHub Actions / psalm / PHP 8.0-ubuntu-latest

InvalidScope

src/Hook/AfterBuiltHook.php:18:19: InvalidScope: Invalid reference to $this in a non-class context (see https://psalm.dev/013)
};
}
}
32 changes: 32 additions & 0 deletions tests/Unit/Hook/AfterBuiltHookTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Unit\Hook;

use PHPUnit\Framework\TestCase;
use Yiisoft\Di\Container;
use Yiisoft\Di\ContainerConfig;
use Yiisoft\Di\Hook\AfterBuiltHook;
use Yiisoft\Di\Tests\Support\EngineInterface;
use Yiisoft\Di\Tests\Support\EngineMarkOne;

final class AfterBuiltHookTest extends TestCase
{
public function testDifferentObjects()
{
$config = ContainerConfig::create()
->withDefinitions([
EngineInterface::class => [
'class' => EngineMarkOne::class,
'afterBuilt' => AfterBuiltHook::unsetInstance()
],
]);
$container = new Container($config);

$this->assertNotSame(
$container->get(EngineInterface::class),
$container->get(EngineInterface::class),
);
}
}

0 comments on commit 897f257

Please sign in to comment.