From f870fa2a3a179030edfaa9c1f0c3c62cb0dc8f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kali=C5=84ski?= Date: Fri, 28 Nov 2025 15:59:05 +0100 Subject: [PATCH 1/3] "Improve normalization logic in `Configuration` for type handling and validation." --- .../src/DependencyInjection/Configuration.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/TwigHooks/src/DependencyInjection/Configuration.php b/src/TwigHooks/src/DependencyInjection/Configuration.php index 35e652d1..4a2f5ba9 100644 --- a/src/TwigHooks/src/DependencyInjection/Configuration.php +++ b/src/TwigHooks/src/DependencyInjection/Configuration.php @@ -69,6 +69,7 @@ private function addHooksConfiguration(ArrayNodeDefinition $rootNode): void ->arrayPrototype() ->beforeNormalization() ->always(function ($v) { + $isTypeDefined = isset($v['type']); $isComponentDefined = isset($v['component']); $isTemplateDefined = isset($v['template']); $isDisabled = isset($v['enabled']) && $v['enabled'] === false; @@ -77,6 +78,10 @@ private function addHooksConfiguration(ArrayNodeDefinition $rootNode): void return $v; } + if (true === $isTypeDefined) { + return $v; + } + $v['type'] = match (true) { $isDisabled => 'disabled', $isComponentDefined => 'component', @@ -89,6 +94,16 @@ private function addHooksConfiguration(ArrayNodeDefinition $rootNode): void ->end() ->validate() ->always(static function ($v) { + $type = $v['type'] ?? null; + if ('template' === $type) { + $v['component'] = null; + $v['props'] = []; + } + + if ('component' === $type) { + $v['template'] = null; + } + $component = $v['component'] ?? null; $template = $v['template'] ?? null; $enabled = $v['enabled'] ?? true; From 0d644cde27eb1b400b4487d0154aaded11f8816d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kali=C5=84ski?= Date: Mon, 1 Dec 2025 09:23:57 +0100 Subject: [PATCH 2/3] "Enhance `Configuration` to handle `type: disabled` in normalization logic and tests." --- src/TwigHooks/src/DependencyInjection/Configuration.php | 2 +- .../tests/Integration/DependencyInjection/ConfigurationTest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/TwigHooks/src/DependencyInjection/Configuration.php b/src/TwigHooks/src/DependencyInjection/Configuration.php index 4a2f5ba9..6aa00c2e 100644 --- a/src/TwigHooks/src/DependencyInjection/Configuration.php +++ b/src/TwigHooks/src/DependencyInjection/Configuration.php @@ -78,7 +78,7 @@ private function addHooksConfiguration(ArrayNodeDefinition $rootNode): void return $v; } - if (true === $isTypeDefined) { + if (true === $isTypeDefined && false === $isDisabled) { return $v; } diff --git a/src/TwigHooks/tests/Integration/DependencyInjection/ConfigurationTest.php b/src/TwigHooks/tests/Integration/DependencyInjection/ConfigurationTest.php index 823fbd0e..d6484198 100644 --- a/src/TwigHooks/tests/Integration/DependencyInjection/ConfigurationTest.php +++ b/src/TwigHooks/tests/Integration/DependencyInjection/ConfigurationTest.php @@ -174,6 +174,7 @@ public function testItThrowsExceptionWhenBothTemplateAndComponentShortcutsAreDef 'some_hookable' => [ 'component' => 'MyAwesomeComponent', 'template' => 'some_target.html.twig', + 'type' => 'disabled', ], ], ], @@ -193,6 +194,7 @@ public function testItThrowsExceptionWhenPropsAreDefinedForNonComponentHookable( 'some_hookable' => [ 'template' => 'some_target.html.twig', 'props' => ['key' => 'value'], + 'type' => 'disabled', ], ], ], From f08fd6a2095cbc4bb4c6c6a221f0c66b6bccc704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kali=C5=84ski?= Date: Mon, 1 Dec 2025 09:34:18 +0100 Subject: [PATCH 3/3] "Refactor `Configuration` methods to add PHPStan annotations and simplify ignore rules for NodeBuilder-related false positives." --- phpstan.neon | 10 ++++++++++ .../Symfony/DependencyInjection/Configuration.php | 11 +++++++++++ .../src/DependencyInjection/Configuration.php | 14 ++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/phpstan.neon b/phpstan.neon index b8c59c96..2e1a5d77 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -9,3 +9,13 @@ parameters: paths: - 'src/TwigExtra/src' - 'src/TwigHooks/src' + + ignoreErrors: + # Symfony Config component relies on magic methods in NodeBuilder. + # PHPStan struggles to resolve these methods on the builder class when complex generics are involved, + # resulting in false positive "unknown class" errors. + - + message: '#Call to method \w+Node\(\) on an unknown class .*NodeBuilder.*#' + paths: + - 'src/TwigHooks/src/DependencyInjection/Configuration.php' + - 'src/TwigExtra/src/Symfony/DependencyInjection/Configuration.php' diff --git a/src/TwigExtra/src/Symfony/DependencyInjection/Configuration.php b/src/TwigExtra/src/Symfony/DependencyInjection/Configuration.php index 14880ae1..406aa6e1 100644 --- a/src/TwigExtra/src/Symfony/DependencyInjection/Configuration.php +++ b/src/TwigExtra/src/Symfony/DependencyInjection/Configuration.php @@ -14,15 +14,23 @@ namespace Sylius\TwigExtra\Symfony\DependencyInjection; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; +use Symfony\Component\Config\Definition\Builder\NodeParentInterface; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; final class Configuration implements ConfigurationInterface { + /** + * @phpstan-return TreeBuilder<'array'> + */ public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('sylius_twig_extra'); + /** + * @var ArrayNodeDefinition $rootNode + * @phpstan-var ArrayNodeDefinition $rootNode + */ $rootNode = $treeBuilder->getRootNode(); $this->addTwigUxConfiguration($rootNode); @@ -30,6 +38,9 @@ public function getConfigTreeBuilder(): TreeBuilder return $treeBuilder; } + /** + * @phpstan-param ArrayNodeDefinition $rootNode + */ private function addTwigUxConfiguration(ArrayNodeDefinition $rootNode): void { $rootNode diff --git a/src/TwigHooks/src/DependencyInjection/Configuration.php b/src/TwigHooks/src/DependencyInjection/Configuration.php index 6aa00c2e..b6c29e78 100644 --- a/src/TwigHooks/src/DependencyInjection/Configuration.php +++ b/src/TwigHooks/src/DependencyInjection/Configuration.php @@ -17,15 +17,23 @@ use Sylius\TwigHooks\Hookable\HookableComponent; use Sylius\TwigHooks\Hookable\HookableTemplate; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; +use Symfony\Component\Config\Definition\Builder\NodeParentInterface; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; final class Configuration implements ConfigurationInterface { + /** + * @phpstan-return TreeBuilder<'array'> + */ public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('sylius_twig_hooks'); + /** + * @var ArrayNodeDefinition $rootNode + * @phpstan-var ArrayNodeDefinition $rootNode + */ $rootNode = $treeBuilder->getRootNode(); $rootNode @@ -41,6 +49,9 @@ public function getConfigTreeBuilder(): TreeBuilder return $treeBuilder; } + /** + * @phpstan-param ArrayNodeDefinition $rootNode + */ private function addSupportedHookableTypesConfiguration(ArrayNodeDefinition $rootNode): void { $rootNode @@ -58,6 +69,9 @@ private function addSupportedHookableTypesConfiguration(ArrayNodeDefinition $roo ; } + /** + * @phpstan-param ArrayNodeDefinition $rootNode + */ private function addHooksConfiguration(ArrayNodeDefinition $rootNode): void { $rootNode