diff --git a/src/Rules/Symfony/ContainerInterfaceUnknownServiceRule.php b/src/Rules/Symfony/ContainerInterfaceUnknownServiceRule.php
index 417f51f5..9cb851ff 100644
--- a/src/Rules/Symfony/ContainerInterfaceUnknownServiceRule.php
+++ b/src/Rules/Symfony/ContainerInterfaceUnknownServiceRule.php
@@ -9,6 +9,7 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Symfony\ServiceMap;
+use PHPStan\TrinaryLogic;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Symfony\Helper;
use function sprintf;
@@ -72,7 +73,11 @@ public function processNode(Node $node, Scope $scope): array
if ($serviceId !== null) {
$service = $this->serviceMap->getService($serviceId);
$serviceIdType = $scope->getType($node->getArgs()[0]->value);
- if ($service === null && !$scope->getType(Helper::createMarkerNode($node->var, $serviceIdType, $this->printer))->equals($serviceIdType)) {
+ if (
+ $service === null &&
+ !$this->isContainerCallInServiceSubscriber($isContainerType, $isPsrContainerType, $scope) &&
+ !$scope->getType(Helper::createMarkerNode($node->var, $serviceIdType, $this->printer))->equals($serviceIdType)
+ ) {
return [sprintf('Service "%s" is not registered in the container.', $serviceId)];
}
}
@@ -80,4 +85,18 @@ public function processNode(Node $node, Scope $scope): array
return [];
}
+ private function isContainerCallInServiceSubscriber(TrinaryLogic $isContainerType, TrinaryLogic $isPsrContainerType, Scope $scope): bool
+ {
+ $scopeClassReflection = $scope->getClassReflection();
+ return $scopeClassReflection !== null &&
+ (
+ $scopeClassReflection->implementsInterface('Symfony\Contracts\Service\ServiceSubscriberInterface') ||
+ $scopeClassReflection->implementsInterface('Symfony\Component\DependencyInjection\ServiceSubscriberInterface')
+ ) &&
+ (
+ $isContainerType->yes() ||
+ $isPsrContainerType->yes()
+ );
+ }
+
}
diff --git a/tests/Rules/Symfony/ContainerInterfaceUnknownServiceRuleTest.php b/tests/Rules/Symfony/ContainerInterfaceUnknownServiceRuleTest.php
index 4bd233e9..b0e22922 100644
--- a/tests/Rules/Symfony/ContainerInterfaceUnknownServiceRuleTest.php
+++ b/tests/Rules/Symfony/ContainerInterfaceUnknownServiceRuleTest.php
@@ -41,8 +41,8 @@ public function testGetPrivateService(): void
public function testGetPrivateServiceInAbstractController(): void
{
- if (!class_exists('Symfony\Bundle\FrameworkBundle\Controller\Controller')) {
- self::markTestSkipped();
+ if (!class_exists('Symfony\Bundle\FrameworkBundle\Controller\AbstractController')) {
+ self::markTestSkipped('The test needs Symfony\Bundle\FrameworkBundle\Controller\AbstractController class.');
}
$this->analyse(
@@ -58,7 +58,7 @@ public function testGetPrivateServiceInAbstractController(): void
);
}
- public function testGetPrivateServiceInLegacyServiceSubscriber(): void
+ public function testGetPrivateServiceInServiceSubscriber(): void
{
if (!interface_exists('Symfony\Contracts\Service\ServiceSubscriberInterface')) {
self::markTestSkipped('The test needs Symfony\Contracts\Service\ServiceSubscriberInterface class.');
@@ -72,6 +72,34 @@ public function testGetPrivateServiceInLegacyServiceSubscriber(): void
);
}
+ public function testGetPrivateServiceInServiceSubscriberWithAnotherKey(): void
+ {
+ if (!interface_exists('Symfony\Contracts\Service\ServiceSubscriberInterface')) {
+ self::markTestSkipped('The test needs Symfony\Contracts\Service\ServiceSubscriberInterface class.');
+ }
+
+ $this->analyse(
+ [
+ __DIR__ . '/ExampleServiceSubscriberWithLocatorKey.php',
+ ],
+ []
+ );
+ }
+
+ public function testGetPrivateServiceInLegacyServiceSubscriberWithAnotherKey(): void
+ {
+ if (!interface_exists('Symfony\Component\DependencyInjection\ServiceSubscriberInterface')) {
+ self::markTestSkipped('The test needs Symfony\Component\DependencyInjection\ServiceSubscriberInterface class.');
+ }
+
+ $this->analyse(
+ [
+ __DIR__ . '/ExampleLegacyServiceSubscriberWithLocatorKey.php',
+ ],
+ []
+ );
+ }
+
public static function getAdditionalConfigFiles(): array
{
return [
diff --git a/tests/Rules/Symfony/ExampleLegacyServiceSubscriberWithLocatorKey.php b/tests/Rules/Symfony/ExampleLegacyServiceSubscriberWithLocatorKey.php
new file mode 100644
index 00000000..f4fb5b40
--- /dev/null
+++ b/tests/Rules/Symfony/ExampleLegacyServiceSubscriberWithLocatorKey.php
@@ -0,0 +1,37 @@
+locator = $locator;
+ }
+
+ public function privateAliasService(): void
+ {
+ $this->locator->get('private_alias');
+ }
+
+ public function publicAliasService(): void
+ {
+ $this->locator->get('public_alias');
+ }
+
+ /**
+ * @return string[]
+ */
+ public static function getSubscribedServices(): array
+ {
+ return [];
+ }
+
+}
diff --git a/tests/Rules/Symfony/ExampleServiceSubscriberWithLocatorKey.php b/tests/Rules/Symfony/ExampleServiceSubscriberWithLocatorKey.php
new file mode 100644
index 00000000..2fc4517e
--- /dev/null
+++ b/tests/Rules/Symfony/ExampleServiceSubscriberWithLocatorKey.php
@@ -0,0 +1,37 @@
+locator = $locator;
+ }
+
+ public function privateAliasService(): void
+ {
+ $this->locator->get('private_alias');
+ }
+
+ public function publicAliasService(): void
+ {
+ $this->locator->get('public_alias');
+ }
+
+ /**
+ * @return string[]
+ */
+ public static function getSubscribedServices(): array
+ {
+ return [];
+ }
+
+}
diff --git a/tests/Rules/Symfony/container.xml b/tests/Rules/Symfony/container.xml
index f3261e0a..63aa2d87 100644
--- a/tests/Rules/Symfony/container.xml
+++ b/tests/Rules/Symfony/container.xml
@@ -8,5 +8,11 @@
+
+
+
+
+
+