From b08f3cddc9f7537072ba6ef5b86b1a53cc493f58 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 19 Jun 2023 17:55:45 +0200 Subject: [PATCH] [FrameworkBundle] Fix setting decorated services during tests --- .../TestServiceContainerRealRefPass.php | 3 + .../TestServiceContainer/PrivateService.php | 1 + .../Tests/Functional/KernelTestCaseTest.php | 61 ------------------- .../Functional/TestServiceContainerTest.php | 28 +++++++++ .../app/TestServiceContainer/services.yml | 10 +++ .../Bundle/FrameworkBundle/composer.json | 2 +- .../Compiler/DecoratorServicePass.php | 4 +- .../Compiler/DecoratorServicePassTest.php | 14 ++--- .../Fixtures/config/anonymous.expected.yml | 2 +- .../Tests/Fixtures/config/child.expected.yml | 2 +- 10 files changed, 55 insertions(+), 72 deletions(-) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/KernelTestCaseTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php index 09f272daa940e..aed3b13404bd5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php @@ -41,6 +41,9 @@ public function process(ContainerBuilder $container) if ($id !== $target) { $renamedIds[$id] = $target; } + if ($inner = $definitions[$target]->getTag('container.decorator')[0]['inner'] ?? null) { + $renamedIds[$id] = $inner; + } } else { unset($privateServices[$id]); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestServiceContainer/PrivateService.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestServiceContainer/PrivateService.php index 6a244cb40ce54..51168b7ea6c24 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestServiceContainer/PrivateService.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestServiceContainer/PrivateService.php @@ -13,4 +13,5 @@ class PrivateService { + public $inner; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/KernelTestCaseTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/KernelTestCaseTest.php deleted file mode 100644 index aa12467829ed1..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/KernelTestCaseTest.php +++ /dev/null @@ -1,61 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; - -use Symfony\Bundle\FrameworkBundle\Test\TestContainer; -use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\NonPublicService; -use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService; -use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PublicService; -use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\UnusedPrivateService; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; - -class KernelTestCaseTest extends AbstractWebTestCase -{ - public function testThatPrivateServicesAreUnavailableIfTestConfigIsDisabled() - { - static::bootKernel(['test_case' => 'TestServiceContainer', 'root_config' => 'test_disabled.yml', 'environment' => 'test_disabled']); - - $this->expectException(\LogicException::class); - static::getContainer(); - } - - public function testThatPrivateServicesAreAvailableIfTestConfigIsEnabled() - { - static::bootKernel(['test_case' => 'TestServiceContainer']); - - $container = static::getContainer(); - $this->assertInstanceOf(ContainerInterface::class, $container); - $this->assertInstanceOf(TestContainer::class, $container); - $this->assertTrue($container->has(PublicService::class)); - $this->assertTrue($container->has(NonPublicService::class)); - $this->assertTrue($container->has(PrivateService::class)); - $this->assertTrue($container->has('private_service')); - $this->assertFalse($container->has(UnusedPrivateService::class)); - } - - public function testThatPrivateServicesCanBeSetIfTestConfigIsEnabled() - { - static::bootKernel(['test_case' => 'TestServiceContainer']); - - $container = static::getContainer(); - - $service = new \stdClass(); - - $container->set('private_service', $service); - $this->assertSame($service, $container->get('private_service')); - - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The "private_service" service is already initialized, you cannot replace it.'); - $container->set('private_service', new \stdClass()); - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TestServiceContainerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TestServiceContainerTest.php index 76a373c0c05a9..fe7093081509f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TestServiceContainerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TestServiceContainerTest.php @@ -16,6 +16,7 @@ use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService; use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PublicService; use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\UnusedPrivateService; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; class TestServiceContainerTest extends AbstractWebTestCase { @@ -40,6 +41,33 @@ public function testThatPrivateServicesAreAvailableIfTestConfigIsEnabled() $this->assertFalse(static::getContainer()->has(UnusedPrivateService::class)); } + public function testThatPrivateServicesCanBeSetIfTestConfigIsEnabled() + { + static::bootKernel(['test_case' => 'TestServiceContainer']); + + $container = static::getContainer(); + + $service = new \stdClass(); + + $container->set('private_service', $service); + $this->assertSame($service, $container->get('private_service')); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "private_service" service is already initialized, you cannot replace it.'); + $container->set('private_service', new \stdClass()); + } + + public function testSetDecoratedService() + { + static::bootKernel(['test_case' => 'TestServiceContainer']); + + $container = static::getContainer(); + + $service = new PrivateService(); + $container->set('decorated', $service); + $this->assertSame($service, $container->get('decorated')->inner); + } + /** * @doesNotPerformAssertions */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TestServiceContainer/services.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TestServiceContainer/services.yml index 523cca58d0b63..46cb7be6a8f6f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TestServiceContainer/services.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TestServiceContainer/services.yml @@ -8,8 +8,18 @@ services: private_service: '@Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService' + decorated: + class: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PublicService: public: true arguments: - '@Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\NonPublicService' - '@Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService' + - '@decorated' + + decorator: + class: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService + decorates: decorated + properties: + inner: '@.inner' diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 9f594f254f035..0fcc602c3975d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -21,7 +21,7 @@ "ext-xml": "*", "symfony/cache": "^5.4|^6.0", "symfony/config": "^6.1", - "symfony/dependency-injection": "^6.3", + "symfony/dependency-injection": "^6.3.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.1", "symfony/event-dispatcher": "^5.4|^6.0", diff --git a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php index c38bfa7744502..d05878fe85611 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php @@ -42,6 +42,7 @@ public function process(ContainerBuilder $container) $definitions->insert([$id, $definition], [$decorated[2], --$order]); } $decoratingDefinitions = []; + $decoratedIds = []; $tagsToKeep = $container->hasParameter('container.behavior_describing_tags') ? $container->getParameter('container.behavior_describing_tags') @@ -58,6 +59,7 @@ public function process(ContainerBuilder $container) $renamedId = $id.'.inner'; } + $decoratedIds[$inner] ??= $renamedId; $this->currentId = $renamedId; $this->processValue($definition); @@ -114,7 +116,7 @@ public function process(ContainerBuilder $container) } foreach ($decoratingDefinitions as $inner => $definition) { - $definition->addTag('container.decorator', ['id' => $inner]); + $definition->addTag('container.decorator', ['id' => $inner, 'inner' => $decoratedIds[$inner]]); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php index 8c8a158a76327..48ed32df6d63d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php @@ -161,7 +161,7 @@ public function testProcessWithInvalidDecorated() public function testProcessNoInnerAliasWithInvalidDecorated() { $container = new ContainerBuilder(); - $decoratorDefinition = $container + $container ->register('decorator') ->setDecoratedService('unknown_decorated', null, 0, ContainerInterface::NULL_ON_INVALID_REFERENCE) ; @@ -173,7 +173,7 @@ public function testProcessNoInnerAliasWithInvalidDecorated() public function testProcessWithInvalidDecoratedAndWrongBehavior() { $container = new ContainerBuilder(); - $decoratorDefinition = $container + $container ->register('decorator') ->setDecoratedService('unknown_decorated', null, 0, 12) ; @@ -198,7 +198,7 @@ public function testProcessMovesTagsFromDecoratedDefinitionToDecoratingDefinitio $this->process($container); $this->assertEmpty($container->getDefinition('baz.inner')->getTags()); - $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar'], 'container.decorator' => [['id' => 'foo']]], $container->getDefinition('baz')->getTags()); + $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar'], 'container.decorator' => [['id' => 'foo', 'inner' => 'baz.inner']]], $container->getDefinition('baz')->getTags()); } public function testProcessMovesTagsFromDecoratedDefinitionToDecoratingDefinitionMultipleTimes() @@ -221,7 +221,7 @@ public function testProcessMovesTagsFromDecoratedDefinitionToDecoratingDefinitio $this->process($container); $this->assertEmpty($container->getDefinition('deco1')->getTags()); - $this->assertEquals(['bar' => ['attr' => 'baz'], 'container.decorator' => [['id' => 'foo']]], $container->getDefinition('deco2')->getTags()); + $this->assertEquals(['bar' => ['attr' => 'baz'], 'container.decorator' => [['id' => 'foo', 'inner' => 'deco1.inner']]], $container->getDefinition('deco2')->getTags()); } public function testProcessLeavesServiceLocatorTagOnOriginalDefinition() @@ -240,7 +240,7 @@ public function testProcessLeavesServiceLocatorTagOnOriginalDefinition() $this->process($container); $this->assertEquals(['container.service_locator' => [0 => []]], $container->getDefinition('baz.inner')->getTags()); - $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar'], 'container.decorator' => [['id' => 'foo']]], $container->getDefinition('baz')->getTags()); + $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar'], 'container.decorator' => [['id' => 'foo', 'inner' => 'baz.inner']]], $container->getDefinition('baz')->getTags()); } public function testProcessLeavesServiceSubscriberTagOnOriginalDefinition() @@ -259,7 +259,7 @@ public function testProcessLeavesServiceSubscriberTagOnOriginalDefinition() $this->process($container); $this->assertEquals(['container.service_subscriber' => [], 'container.service_subscriber.locator' => []], $container->getDefinition('baz.inner')->getTags()); - $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar'], 'container.decorator' => [['id' => 'foo']]], $container->getDefinition('baz')->getTags()); + $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar'], 'container.decorator' => [['id' => 'foo', 'inner' => 'baz.inner']]], $container->getDefinition('baz')->getTags()); } public function testProcessLeavesProxyTagOnOriginalDefinition() @@ -278,7 +278,7 @@ public function testProcessLeavesProxyTagOnOriginalDefinition() $this->process($container); $this->assertEquals(['proxy' => 'foo'], $container->getDefinition('baz.inner')->getTags()); - $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar'], 'container.decorator' => [['id' => 'foo']]], $container->getDefinition('baz')->getTags()); + $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar'], 'container.decorator' => [['id' => 'foo', 'inner' => 'baz.inner']]], $container->getDefinition('baz')->getTags()); } public function testCannotDecorateSyntheticService() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/anonymous.expected.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/anonymous.expected.yml index 9b1213fbcab8e..7f36de38b0015 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/anonymous.expected.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/anonymous.expected.yml @@ -16,5 +16,5 @@ services: class: Symfony\Component\DependencyInjection\Tests\Fixtures\StdClassDecorator public: true tags: - - container.decorator: { id: decorated } + - container.decorator: { id: decorated, inner: decorator42 } arguments: [!service { class: stdClass }] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/child.expected.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/child.expected.yml index a4e4eb995c4be..44dbbd571b788 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/child.expected.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/child.expected.yml @@ -8,7 +8,7 @@ services: class: Class2 public: true tags: - - container.decorator: { id: bar } + - container.decorator: { id: bar, inner: b } file: file.php lazy: true arguments: [!service { class: Class1 }]