diff --git a/src/AggregateContainer.php b/src/AggregateContainer.php index ad73061..a9e8595 100644 --- a/src/AggregateContainer.php +++ b/src/AggregateContainer.php @@ -12,8 +12,6 @@ final class AggregateContainer implements ContainerInterface, DelegateContainerA private array $containers = []; /** @var string[] */ private array $ids = []; - /** @var array */ - private array $cache = []; /** @var array */ private array $factoryCache = []; /** @var float[] */ @@ -58,17 +56,13 @@ public function haveContainer(ContainerInterface $container): bool */ public function get(string $id) { - if (isset($this->cache[$id])) { - return $this->cache[$id]; - } - if (!$this->has($id)) { throw NotFoundException::withIdentifier($id); } $factory = $this->factoryCache[$id]; unset($this->factoryCache[$id]); - return $this->cache[$id] = $factory(); + return $factory(); } /** @@ -76,9 +70,6 @@ public function get(string $id) */ public function has(string $id): bool { - if (isset($this->cache[$id])) { - return true; - } if (isset($this->factoryCache[$id])) { return true; } diff --git a/src/Attributes/NoCache.php b/src/Attributes/NoCache.php new file mode 100644 index 0000000..8dcf845 --- /dev/null +++ b/src/Attributes/NoCache.php @@ -0,0 +1,8 @@ +cache[$id])) { $factory = $this->definition->getDefinition($id); + $reflection = null; + if ($factory instanceof \Closure) { + $reflection = new \ReflectionFunction($factory); + } + elseif (is_object($factory)) { + $reflection = new \ReflectionClass($factory); + } + if ($reflection?->getAttributes(NoCache::class) && $factory) { + return $factory($this->rootContainer, $id); + } $this->cache[$id] = $factory ? $factory($this->rootContainer, $id) : null; } return $this->cache[$id]; diff --git a/tests/AggregateContainerTest.php b/tests/AggregateContainerTest.php index 9243678..f528e7b 100644 --- a/tests/AggregateContainerTest.php +++ b/tests/AggregateContainerTest.php @@ -4,7 +4,9 @@ use Psr\Container\ContainerInterface; use Stefna\DependencyInjection\AggregateContainer; +use Stefna\DependencyInjection\Attributes\NoCache; use Stefna\DependencyInjection\Container; +use Stefna\DependencyInjection\ContainerBuilder; use Stefna\DependencyInjection\Definition\DefinitionArray; use Stefna\DependencyInjection\Exception\DuplicateEntryException; use PHPUnit\Framework\TestCase; @@ -114,4 +116,55 @@ public function testNested2AggregateContainerGetUsedAsRootContainerWhenCallingFa $entity = $rootAggregateContainer->get(TestWithArgs::class); $this->assertSame($time, $entity->date); } + + public function testDefaultCacheService(): void + { + $time = new \DateTimeImmutable(); + $rootAggregateContainer = new AggregateContainer('1'); + $aggregateContainer1 = new AggregateContainer('2'); + $aggregateContainer2 = new AggregateContainer('3'); + + $aggregateContainer1->addContainer(new Container(new DefinitionArray([ + \DateTimeImmutable::class => fn () => $time, + ]))); + $aggregateContainer2->addContainer(new Container(new DefinitionArray([ + TestWithArgs::class => function (ContainerInterface $c) use ($rootAggregateContainer) { + $this->assertSame($rootAggregateContainer, $c); + return new TestWithArgs($c->get(\DateTimeImmutable::class)); + }, + ]))); + + $rootAggregateContainer->addContainer($aggregateContainer2); + $rootAggregateContainer->addContainer($aggregateContainer1); + + $this->assertSame( + $rootAggregateContainer->get(\DateTimeImmutable::class), + $rootAggregateContainer->get(TestWithArgs::class)->date, + ); + } + + public function testDisableServiceCache(): void + { + $rootAggregateContainer = new AggregateContainer('1'); + $aggregateContainer1 = new AggregateContainer('2'); + $aggregateContainer2 = new AggregateContainer('3'); + + $aggregateContainer1->addContainer(new Container(new DefinitionArray([ + \DateTimeImmutable::class => #[NoCache] fn () => new \DateTimeImmutable(), + ]))); + $aggregateContainer2->addContainer(new Container(new DefinitionArray([ + TestWithArgs::class => function (ContainerInterface $c) use ($rootAggregateContainer) { + $this->assertSame($rootAggregateContainer, $c); + return new TestWithArgs($c->get(\DateTimeImmutable::class)); + }, + ]))); + + $rootAggregateContainer->addContainer($aggregateContainer2); + $rootAggregateContainer->addContainer($aggregateContainer1); + + $this->assertNotSame( + $rootAggregateContainer->get(\DateTimeImmutable::class), + $rootAggregateContainer->get(TestWithArgs::class)->date, + ); + } } diff --git a/tests/ContainerBuilderTest.php b/tests/ContainerBuilderTest.php index a2143e9..27b4301 100644 --- a/tests/ContainerBuilderTest.php +++ b/tests/ContainerBuilderTest.php @@ -3,6 +3,7 @@ namespace Stefna\DependencyInjection\Tests; use Stefna\DependencyInjection\AggregateContainer; +use Stefna\DependencyInjection\Attributes\NoCache; use Stefna\DependencyInjection\Container; use Stefna\DependencyInjection\ContainerBuilder; use Stefna\DependencyInjection\Definition\DefinitionArray; @@ -119,4 +120,42 @@ public function testDefinitionOrder(): void $this->assertSame(4, $container->get('test3')); $this->assertSame(12, $container->get('test4')); } + + public function testDefaultCacheService(): void + { + $builder = new ContainerBuilder(); + $builder->addDefinition([ + \DateTimeInterface::class => fn () => new \DateTimeImmutable(), + ]); + + $container = $builder->build(); + + $this->assertInstanceOf(Container::class, $container); + + $this->assertTrue($container->has(\DateTimeInterface::class)); + + $this->assertSame( + $container->get(\DateTimeInterface::class), + $container->get(\DateTimeInterface::class) + ); + } + + public function testDisableServiceCache(): void + { + $builder = new ContainerBuilder(); + $builder->addDefinition([ + \DateTimeInterface::class => #[NoCache] fn () => new \DateTimeImmutable(), + ]); + + $container = $builder->build(); + + $this->assertInstanceOf(Container::class, $container); + + $this->assertTrue($container->has(\DateTimeInterface::class)); + + $this->assertNotSame( + $container->get(\DateTimeInterface::class), + $container->get(\DateTimeInterface::class) + ); + } }