From ecefe2d70391d88017c71f7e5294b46accb47593 Mon Sep 17 00:00:00 2001 From: iamluc Date: Fri, 9 Nov 2018 17:27:47 +0100 Subject: [PATCH] Disable PrivateServiceRule when the class implements ServiceSubscriberInterface --- phpstan.neon | 1 + .../ContainerInterfacePrivateServiceRule.php | 5 ++ ...ntainerInterfacePrivateServiceRuleTest.php | 14 +++++ .../Symfony/ExampleServiceSubscriber.php | 52 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 tests/Rules/Symfony/ExampleServiceSubscriber.php diff --git a/phpstan.neon b/phpstan.neon index 45df5546..a690755c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,4 +8,5 @@ parameters: - */tests/tmp/* - */tests/*/ExampleContainer.php - */tests/*/ExampleController.php + - */tests/*/ExampleServiceSubscriber.php - */tests/*/request_get_content.php diff --git a/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php b/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php index 89aa45df..3aef9d3c 100644 --- a/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php +++ b/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php @@ -50,6 +50,11 @@ public function processNode(Node $node, Scope $scope): array return []; } + $isServiceSubscriber = (new ObjectType('Symfony\Component\DependencyInjection\ServiceSubscriberInterface'))->isSuperTypeOf($argType); + if ($isServiceSubscriber->yes()) { + return []; + } + $serviceId = ServiceMap::getServiceIdFromNode($node->args[0]->value, $scope); if ($serviceId !== null) { $service = $this->serviceMap->getService($serviceId); diff --git a/tests/Rules/Symfony/ContainerInterfacePrivateServiceRuleTest.php b/tests/Rules/Symfony/ContainerInterfacePrivateServiceRuleTest.php index 944405e7..f6329dc4 100644 --- a/tests/Rules/Symfony/ContainerInterfacePrivateServiceRuleTest.php +++ b/tests/Rules/Symfony/ContainerInterfacePrivateServiceRuleTest.php @@ -29,4 +29,18 @@ public function testGetPrivateService(): void ); } + public function testGetPrivateServiceInServiceSubscriber(): void + { + if (!interface_exists('Symfony\\Component\\DependencyInjection\\ServiceSubscriberInterface')) { + self::markTestSkipped('The test needs Symfony\Component\DependencyInjection\ServiceSubscriberInterface class.'); + } + + $this->analyse( + [ + __DIR__ . '/ExampleServiceSubscriber.php', + ], + [] + ); + } + } diff --git a/tests/Rules/Symfony/ExampleServiceSubscriber.php b/tests/Rules/Symfony/ExampleServiceSubscriber.php new file mode 100644 index 00000000..936f952e --- /dev/null +++ b/tests/Rules/Symfony/ExampleServiceSubscriber.php @@ -0,0 +1,52 @@ +get('private'); + } + + public function privateServiceInTestContainer(): void + { + /** @var \Symfony\Bundle\FrameworkBundle\Test\TestContainer $container */ + $container = doFoo(); + $container->get('private'); + } + + public function unknownService(): void + { + $this->get('unknown'); + } + + public function unknownGuardedServiceInsideContext(): void + { + if ($this->has('unknown')) { // phpcs:ignore + $this->get('unknown'); + } + } + + public function unknownGuardedServiceOutsideOfContext(): void + { + if (!$this->has('unknown')) { + return; + } + $this->get('unknown'); + } + + /** + * @return string[] + */ + public static function getSubscribedServices(): array + { + return [ + 'private' => MyService::class, + ]; + } + +}