diff --git a/src/DependencyInjection/ConditionalTagsExtension.php b/src/DependencyInjection/ConditionalTagsExtension.php index 04272124a1..ada630a2e5 100644 --- a/src/DependencyInjection/ConditionalTagsExtension.php +++ b/src/DependencyInjection/ConditionalTagsExtension.php @@ -2,8 +2,10 @@ namespace PHPStan\DependencyInjection; +use InvalidArgumentException; use Nette; use Nette\DI\CompilerExtension; +use Nette\DI\Definitions\Statement; use Nette\Schema\Expect; use Override; use PHPStan\ShouldNotHappenException; @@ -23,7 +25,11 @@ public function getConfigSchema(): Nette\Schema\Schema $tags = array_values(ValidateServiceTagsExtension::INTERFACE_TAG_MAPPING); return Expect::arrayOf(Expect::structure( - array_fill_keys($tags, Expect::anyOf(Expect::bool(), Expect::listOf(Expect::bool()))), + array_fill_keys($tags, Expect::anyOf( + Expect::bool(), + Expect::type(Statement::class), + Expect::listOf(Expect::anyOf(Expect::bool(), Expect::type(Statement::class))), + )), )->min(1)); } @@ -41,10 +47,11 @@ public function beforeCompile(): void } foreach ($services as $service) { foreach ($tags as $tag => $parameter) { - if (is_array($parameter)) { - $parameter = array_reduce($parameter, static fn ($carry, $item) => $carry && (bool) $item, true); - } - if ((bool) $parameter) { + $parameter = is_array($parameter) + ? array_reduce($parameter, fn ($carry, $item) => $carry && $this->resolveValue($item), true) + : $this->resolveValue($parameter); + + if ($parameter) { $service->addTag($tag); continue; } @@ -53,4 +60,17 @@ public function beforeCompile(): void } } + public function resolveValue(mixed $parameter): bool + { + if (!$parameter instanceof Statement) { + return (bool) $parameter; + } + + if ($parameter->getEntity() === 'not') { + return ! (bool) $parameter->arguments[0]; + } + + throw new InvalidArgumentException('Unsupported Statement.'); + } + } diff --git a/tests/PHPStan/DependencyInjection/ConditionalTagsExtensionTest.php b/tests/PHPStan/DependencyInjection/ConditionalTagsExtensionTest.php index 5c2b2e28d5..c512a1720e 100644 --- a/tests/PHPStan/DependencyInjection/ConditionalTagsExtensionTest.php +++ b/tests/PHPStan/DependencyInjection/ConditionalTagsExtensionTest.php @@ -16,10 +16,14 @@ public function testConditionalTags(): void $enabledServices = array_map(static fn ($service) => get_class($service), $enabledServices); $this->assertNotContains(TestedConditionalServiceDisabled::class, $enabledServices); $this->assertContains(TestedConditionalServiceEnabled::class, $enabledServices); + $this->assertContains(TestedConditionalServiceNotDisabled::class, $enabledServices); + $this->assertNotContains(TestedConditionalServiceNotEnabled::class, $enabledServices); $this->assertNotContains(TestedConditionalServiceDisabledDisabled::class, $enabledServices); $this->assertNotContains(TestedConditionalServiceDisabledEnabled::class, $enabledServices); $this->assertNotContains(TestedConditionalServiceEnabledDisabled::class, $enabledServices); $this->assertContains(TestedConditionalServiceEnabledEnabled::class, $enabledServices); + $this->assertContains(TestedConditionalServiceEnabledNotDisabled::class, $enabledServices); + $this->assertNotContains(TestedConditionalServiceEnabledNotEnabled::class, $enabledServices); } /** diff --git a/tests/PHPStan/DependencyInjection/TestedConditionalServiceEnabledNotDisabled.php b/tests/PHPStan/DependencyInjection/TestedConditionalServiceEnabledNotDisabled.php new file mode 100644 index 0000000000..1b309251a6 --- /dev/null +++ b/tests/PHPStan/DependencyInjection/TestedConditionalServiceEnabledNotDisabled.php @@ -0,0 +1,25 @@ + + */ +class TestedConditionalServiceEnabledNotDisabled implements Rule +{ + + public function getNodeType(): string + { + return Node::class; + } + + public function processNode(Node $node, Scope $scope): array + { + return []; + } + +} diff --git a/tests/PHPStan/DependencyInjection/TestedConditionalServiceEnabledNotEnabled.php b/tests/PHPStan/DependencyInjection/TestedConditionalServiceEnabledNotEnabled.php new file mode 100644 index 0000000000..e194593549 --- /dev/null +++ b/tests/PHPStan/DependencyInjection/TestedConditionalServiceEnabledNotEnabled.php @@ -0,0 +1,25 @@ + + */ +class TestedConditionalServiceEnabledNotEnabled implements Rule +{ + + public function getNodeType(): string + { + return Node::class; + } + + public function processNode(Node $node, Scope $scope): array + { + return []; + } + +} diff --git a/tests/PHPStan/DependencyInjection/TestedConditionalServiceNotDisabled.php b/tests/PHPStan/DependencyInjection/TestedConditionalServiceNotDisabled.php new file mode 100644 index 0000000000..764e96a5d0 --- /dev/null +++ b/tests/PHPStan/DependencyInjection/TestedConditionalServiceNotDisabled.php @@ -0,0 +1,25 @@ + + */ +class TestedConditionalServiceNotDisabled implements Rule +{ + + public function getNodeType(): string + { + return Node::class; + } + + public function processNode(Node $node, Scope $scope): array + { + return []; + } + +} diff --git a/tests/PHPStan/DependencyInjection/TestedConditionalServiceNotEnabled.php b/tests/PHPStan/DependencyInjection/TestedConditionalServiceNotEnabled.php new file mode 100644 index 0000000000..9491bdad36 --- /dev/null +++ b/tests/PHPStan/DependencyInjection/TestedConditionalServiceNotEnabled.php @@ -0,0 +1,25 @@ + + */ +class TestedConditionalServiceNotEnabled implements Rule +{ + + public function getNodeType(): string + { + return Node::class; + } + + public function processNode(Node $node, Scope $scope): array + { + return []; + } + +} diff --git a/tests/PHPStan/DependencyInjection/conditionalTags.neon b/tests/PHPStan/DependencyInjection/conditionalTags.neon index 1804297a13..73d7673d02 100644 --- a/tests/PHPStan/DependencyInjection/conditionalTags.neon +++ b/tests/PHPStan/DependencyInjection/conditionalTags.neon @@ -11,6 +11,10 @@ conditionalTags: phpstan.rules.rule: %disabled% PHPStan\DependencyInjection\TestedConditionalServiceEnabled: phpstan.rules.rule: %enabled% + PHPStan\DependencyInjection\TestedConditionalServiceNotDisabled: + phpstan.rules.rule: not(%disabled%) + PHPStan\DependencyInjection\TestedConditionalServiceNotEnabled: + phpstan.rules.rule: not(%enabled%) PHPStan\DependencyInjection\TestedConditionalServiceDisabledDisabled: phpstan.rules.rule: [%disabled%, %disabled%] PHPStan\DependencyInjection\TestedConditionalServiceDisabledEnabled: @@ -19,11 +23,19 @@ conditionalTags: phpstan.rules.rule: [%enabled%, %disabled%] PHPStan\DependencyInjection\TestedConditionalServiceEnabledEnabled: phpstan.rules.rule: [%enabled%, %enabled%] + PHPStan\DependencyInjection\TestedConditionalServiceEnabledNotEnabled: + phpstan.rules.rule: [%enabled%, not(%enabled%)] + PHPStan\DependencyInjection\TestedConditionalServiceEnabledNotDisabled: + phpstan.rules.rule: [%enabled%, not(%disabled%)] services: - PHPStan\DependencyInjection\TestedConditionalServiceDisabled - PHPStan\DependencyInjection\TestedConditionalServiceEnabled + - PHPStan\DependencyInjection\TestedConditionalServiceNotDisabled + - PHPStan\DependencyInjection\TestedConditionalServiceNotEnabled - PHPStan\DependencyInjection\TestedConditionalServiceDisabledDisabled - PHPStan\DependencyInjection\TestedConditionalServiceDisabledEnabled - PHPStan\DependencyInjection\TestedConditionalServiceEnabledDisabled - PHPStan\DependencyInjection\TestedConditionalServiceEnabledEnabled + - PHPStan\DependencyInjection\TestedConditionalServiceEnabledNotEnabled + - PHPStan\DependencyInjection\TestedConditionalServiceEnabledNotDisabled