From fbdade2891e73ea81628050f34f33ae292e9a206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rokas=20Mikalk=C4=97nas?= Date: Tue, 9 Nov 2021 15:00:12 +0200 Subject: [PATCH] [HttpKernel] Make sure that decorated service works with kernel.reset tag --- .../Compiler/DecoratorServicePass.php | 5 +- .../Compiler/DecoratorServicePassTest.php | 19 ++++ .../ResettableServicePassTest.php | 101 ++++++++++++++++++ .../Tests/Fixtures/ClearableInterface.php | 8 ++ .../Tests/Fixtures/ClearableService.php | 14 ++- .../Fixtures/ClearableServiceDecorator.php | 29 +++++ 6 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/ClearableInterface.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/ClearableServiceDecorator.php diff --git a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php index af7c957a308a2..c67c02991e10a 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php @@ -89,8 +89,9 @@ public function process(ContainerBuilder $container) $decoratingTags = $decoratingDefinition->getTags(); $resetTags = []; - // container.service_locator and container.service_subscriber have special logic and they must not be transferred out to decorators - foreach (['container.service_locator', 'container.service_subscriber'] as $containerTag) { + // container.service_locator, container.service_subscriber and kernel.reset + // have special logic and they must not be transferred out to decorators + foreach (['container.service_locator', 'container.service_subscriber', 'kernel.reset'] as $containerTag) { if (isset($decoratingTags[$containerTag])) { $resetTags[$containerTag] = $decoratingTags[$containerTag]; unset($decoratingTags[$containerTag]); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php index 9a456335569d4..c1c292e29b60f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php @@ -263,6 +263,25 @@ public function testProcessLeavesServiceSubscriberTagOnOriginalDefinition() $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags()); } + public function testProcessLeavesKernelResetTagOnOriginalDefinition() + { + $container = new ContainerBuilder(); + $container + ->register('foo') + ->setTags(['kernel.reset' => [], 'bar' => ['attr' => 'baz']]) + ; + $container + ->register('baz') + ->setTags(['foobar' => ['attr' => 'bar']]) + ->setDecoratedService('foo') + ; + + $this->process($container); + + $this->assertEquals(['kernel.reset' => []], $container->getDefinition('baz.inner')->getTags()); + $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags()); + } + public function testCannotDecorateSyntheticService() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ResettableServicePassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ResettableServicePassTest.php index 4c110e3a26800..0947f378a75de 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ResettableServicePassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ResettableServicePassTest.php @@ -3,6 +3,7 @@ namespace Symfony\Component\HttpKernel\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -10,7 +11,9 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass; use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; +use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableInterface; use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService; +use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableServiceDecorator; use Symfony\Component\HttpKernel\Tests\Fixtures\MultiResettableService; use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService; @@ -81,4 +84,102 @@ public function testCompilerPassWithoutResetters() $this->assertFalse($container->has('services_resetter')); } + + public function testDecoratedLastResettableService() + { + $container = new ContainerBuilder(); + $container->register('services_resetter', ServicesResetter::class) + ->setPublic(true) + ->setArguments([null, []]); + $container->addCompilerPass(new ResettableServicePass()); + + $container->register('clearable_service', ClearableService::class) + ->setFactory([ClearableService::class, 'create']) + ->addTag('kernel.reset', ['method' => 'reset']); + + $container->setAlias(ClearableInterface::class, new Alias('clearable_service', true)); + + $container->register('clearable_service_decorator', ClearableServiceDecorator::class) + ->setDecoratedService(ClearableInterface::class) + ->setArgument(0, new Reference('.inner')); + + $container->register('clearable_service_decorator_2', ClearableServiceDecorator::class) + ->setDecoratedService(ClearableInterface::class) + ->setArgument(0, new Reference('.inner')); + + $container->compile(); + + $container->get(ClearableInterface::class)->clear(); + + self::assertSame(1, ClearableService::$counter); + self::assertSame(2, ClearableServiceDecorator::$counter); + + $container->get('services_resetter')->reset(); + self::assertSame(0, ClearableService::$counter); + self::assertSame(2, ClearableServiceDecorator::$counter); + } + + public function testDecoratedMiddleResettableService() + { + $container = new ContainerBuilder(); + $container->register('services_resetter', ServicesResetter::class) + ->setPublic(true) + ->setArguments([null, []]); + $container->addCompilerPass(new ResettableServicePass()); + + $container->register('clearable_service', ClearableService::class) + ->setFactory([ClearableService::class, 'create']); + + $container->setAlias(ClearableInterface::class, new Alias('clearable_service', true)); + + $container->register('clearable_service_decorator', ClearableServiceDecorator::class) + ->setDecoratedService(ClearableInterface::class) + ->setArgument(0, new Reference('.inner')) + ->addTag('kernel.reset', ['method' => 'reset']); + + $container->register('clearable_service_decorator_2', ClearableServiceDecorator::class) + ->setDecoratedService(ClearableInterface::class) + ->setArgument(0, new Reference('.inner')); + + $container->compile(); + + $container->get(ClearableInterface::class)->clear(); + + self::assertSame(1, ClearableService::$counter); + self::assertSame(2, ClearableServiceDecorator::$counter); + + $container->get('services_resetter')->reset(); + self::assertSame(1, ClearableService::$counter); + self::assertSame(0, ClearableServiceDecorator::$counter); + } + + public function testDecoratedFirstResettableService() + { + $container = new ContainerBuilder(); + $container->register('services_resetter', ServicesResetter::class) + ->setPublic(true) + ->setArguments([null, []]); + $container->addCompilerPass(new ResettableServicePass()); + + $container->register('clearable_service', ClearableService::class) + ->setFactory([ClearableService::class, 'create']); + + $container->setAlias(ClearableInterface::class, new Alias('clearable_service', true)); + + $container->register('clearable_service_decorator', ClearableServiceDecorator::class) + ->setDecoratedService(ClearableInterface::class) + ->setArgument(0, new Reference('.inner')) + ->addTag('kernel.reset', ['method' => 'reset']); + + $container->compile(); + + $container->get(ClearableInterface::class)->clear(); + + self::assertSame(1, ClearableService::$counter); + self::assertSame(1, ClearableServiceDecorator::$counter); + + $container->get('services_resetter')->reset(); + self::assertSame(1, ClearableService::$counter); + self::assertSame(0, ClearableServiceDecorator::$counter); + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/ClearableInterface.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/ClearableInterface.php new file mode 100644 index 0000000000000..ed2d43f54e008 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/ClearableInterface.php @@ -0,0 +1,8 @@ +clearableService = $clearableService; + } + + public function clear() + { + ++self::$counter; + + $this->clearableService->clear(); + } + + public function reset() + { + self::$counter = 0; + } +}