diff --git a/src/TwigHooks/config/services.php b/src/TwigHooks/config/services.php index 00874a30..6de29b4c 100644 --- a/src/TwigHooks/config/services.php +++ b/src/TwigHooks/config/services.php @@ -2,7 +2,9 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; -use Sylius\TwigHooks\Hook\NameGenerator\TemplateNameGenerator; +use Sylius\TwigHooks\Hook\Normalizer\CompositeNameNormalizer; +use Sylius\TwigHooks\Hook\Normalizer\NameNormalizerInterface; +use Sylius\TwigHooks\Hook\Normalizer\RemoveSectionPartNormalizer; use Sylius\TwigHooks\Provider\ComponentPropsProvider; use Sylius\TwigHooks\Provider\DefaultConfigurationProvider; use Sylius\TwigHooks\Provider\DefaultContextProvider; @@ -33,7 +35,22 @@ ]) ; - $services->set('twig_hooks.hook.name_generator.template', TemplateNameGenerator::class); + $services + ->set('twig_hooks.hook.normalizer.composite', CompositeNameNormalizer::class) + ->args([ + tagged_iterator('twig_hooks.hook_normalizer'), + ]) + ->alias(NameNormalizerInterface::class, 'twig_hooks.hook.normalizer.composite') + ; + + $services + ->set('twig_hooks.hook.normalizer.remove_section_part', RemoveSectionPartNormalizer::class) + ->args([ + param('twig_hooks.hook_name_section_separator'), + ]) + ->tag('twig_hooks.hook_normalizer') + ->alias(sprintf('%s $removeSectionPartNormalizer', NameNormalizerInterface::class), 'twig_hooks.hook.normalizer.remove_section_part') + ; $services->set(HooksExtension::class) ->args([ @@ -49,7 +66,7 @@ $services->set(HooksRuntime::class) ->args([ service('twig_hooks.renderer.hook'), - service('twig_hooks.hook.name_generator.template'), + service('twig_hooks.hook.normalizer.composite'), param('twig_hooks.enable_autoprefixing'), ]) ->tag('twig.runtime') diff --git a/src/TwigHooks/src/DependencyInjection/Configuration.php b/src/TwigHooks/src/DependencyInjection/Configuration.php index b531247f..5d91b7b6 100644 --- a/src/TwigHooks/src/DependencyInjection/Configuration.php +++ b/src/TwigHooks/src/DependencyInjection/Configuration.php @@ -22,6 +22,7 @@ public function getConfigTreeBuilder(): TreeBuilder $rootNode ->children() ->booleanNode('enable_autoprefixing')->defaultFalse()->end() + ->scalarNode('hook_name_section_separator')->defaultFalse()->end() ->end() ->end(); diff --git a/src/TwigHooks/src/DependencyInjection/TwigHooksExtension.php b/src/TwigHooks/src/DependencyInjection/TwigHooksExtension.php index 7e8aa60a..4888aa03 100644 --- a/src/TwigHooks/src/DependencyInjection/TwigHooksExtension.php +++ b/src/TwigHooks/src/DependencyInjection/TwigHooksExtension.php @@ -28,6 +28,7 @@ public function load(array $configs, ContainerBuilder $container): void $this->registerHooks($container, $config['hooks'], $config['supported_hookable_types']); $container->setParameter('twig_hooks.enable_autoprefixing', $config['enable_autoprefixing']); + $container->setParameter('twig_hooks.hook_name_section_separator', $config['hook_name_section_separator']); } /** diff --git a/src/TwigHooks/src/Hook/NameGenerator/NameGeneratorInterface.php b/src/TwigHooks/src/Hook/NameGenerator/NameGeneratorInterface.php deleted file mode 100644 index 3f9a8bbf..00000000 --- a/src/TwigHooks/src/Hook/NameGenerator/NameGeneratorInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -normalizeTemplatePath($input); - $normalizedParts = array_map($this->normalizeString(...), $parts); - - return implode('.', array_merge([$templatePath], $normalizedParts)); - } - - private function normalizeTemplatePath(string $templatePath): string - { - $parts = explode('/', str_replace('\\', '/', $templatePath)); - $resultParts = []; - - foreach ($parts as $part) { - $resultPart = str_replace(['@', '.html.twig'], '', $part); - $resultPart = $this->normalizeString($resultPart); - $resultParts[] = $resultPart; - } - - return implode('.', $resultParts); - } - - private function normalizeString(string $string): string - { - $result = trim($string, '_'); - /** @var string $result */ - $result = preg_replace('/(? */ + private readonly array $nameNormalizers; + + /** + * @param iterable $nameNormalizers + */ + public function __construct(iterable $nameNormalizers) + { + $this->nameNormalizers = $nameNormalizers instanceof \Traversable ? iterator_to_array($nameNormalizers) : $nameNormalizers; + } + + public function normalize(string $name): string + { + $normalizedHookName = $name; + + foreach ($this->nameNormalizers as $nameNormalizer) { + $normalizedHookName = $nameNormalizer->normalize($normalizedHookName); + } + + return $normalizedHookName; + } +} diff --git a/src/TwigHooks/src/Hook/Normalizer/NameNormalizerInterface.php b/src/TwigHooks/src/Hook/Normalizer/NameNormalizerInterface.php new file mode 100644 index 00000000..8397fdbf --- /dev/null +++ b/src/TwigHooks/src/Hook/Normalizer/NameNormalizerInterface.php @@ -0,0 +1,10 @@ +separator) { + return $name; + } + + $parts = explode('.', $name); + $result = []; + + foreach ($parts as $part) { + $hookNameExplodedBySectionSeparator = explode($this->separator, $part); + + $result[] = current($hookNameExplodedBySectionSeparator); + } + + return implode('.', $result); + } +} diff --git a/src/TwigHooks/src/Twig/HooksExtension.php b/src/TwigHooks/src/Twig/HooksExtension.php index ab7612c1..0f7cf82d 100644 --- a/src/TwigHooks/src/Twig/HooksExtension.php +++ b/src/TwigHooks/src/Twig/HooksExtension.php @@ -15,8 +15,6 @@ final class HooksExtension extends AbstractExtension public function getFunctions(): array { return [ - new TwigFunction('hook_name', [HooksRuntime::class, 'createHookName']), - new TwigFunction('create_hook_name', [HooksRuntime::class, 'createHookName']), new TwigFunction('get_hookable_metadata', [HooksRuntime::class, 'getHookableMetadata'], ['needs_context' => true]), new TwigFunction('get_hookable_context', [HooksRuntime::class, 'getHookableContext'], ['needs_context' => true]), new TwigFunction('get_hookable_configuration', [HooksRuntime::class, 'getHookableConfiguration'], ['needs_context' => true]), diff --git a/src/TwigHooks/src/Twig/Runtime/HooksRuntime.php b/src/TwigHooks/src/Twig/Runtime/HooksRuntime.php index 6e31c4fb..d6393b56 100644 --- a/src/TwigHooks/src/Twig/Runtime/HooksRuntime.php +++ b/src/TwigHooks/src/Twig/Runtime/HooksRuntime.php @@ -5,7 +5,7 @@ namespace Sylius\TwigHooks\Twig\Runtime; use Sylius\TwigHooks\Bag\DataBagInterface; -use Sylius\TwigHooks\Hook\NameGenerator\NameGeneratorInterface; +use Sylius\TwigHooks\Hook\Normalizer\NameNormalizerInterface; use Sylius\TwigHooks\Hook\Renderer\HookRendererInterface; use Sylius\TwigHooks\Hookable\Metadata\HookableMetadata; use Twig\Error\RuntimeError; @@ -17,16 +17,11 @@ final class HooksRuntime implements RuntimeExtensionInterface public function __construct ( private readonly HookRendererInterface $hookRenderer, - private readonly NameGeneratorInterface $nameGenerator, + private readonly NameNormalizerInterface $nameNormalizer, private readonly bool $enableAutoprefixing, ) { } - public function createHookName(string $base, string ...$parts): string - { - return $this->nameGenerator->generate($base, ...$parts); - } - /** * @param array $context * @throws RuntimeError @@ -72,6 +67,7 @@ public function renderHook( ): string { $hookNames = is_string($hookNames) ? [$hookNames] : $hookNames; + $hookNames = array_map([$this->nameNormalizer, 'normalize'], $hookNames); $context = $this->getContext($hookContext, $hookableMetadata, $only); $prefixes = $this->getPrefixes($hookContext, $hookableMetadata); @@ -84,7 +80,8 @@ public function renderHook( foreach ($hookNames as $hookName) { foreach ($prefixes as $prefix) { - $prefixedHookNames[] = $this->nameGenerator->generate($prefix, $hookName); + $normalizedPrefix = $this->nameNormalizer->normalize($prefix); + $prefixedHookNames[] = implode('.', [$normalizedPrefix, $hookName]); } } diff --git a/src/TwigHooks/tests/Integration/DependencyInjection/ConfigurationTest.php b/src/TwigHooks/tests/Integration/DependencyInjection/ConfigurationTest.php index abddf77c..40377007 100644 --- a/src/TwigHooks/tests/Integration/DependencyInjection/ConfigurationTest.php +++ b/src/TwigHooks/tests/Integration/DependencyInjection/ConfigurationTest.php @@ -27,6 +27,7 @@ public function testItReturnsDefaultConfiguration(): void 'component' => HookableComponent::class, 'disabled' => DisabledHookable::class, ], + 'hook_name_section_separator' => '#', ], ); } diff --git a/src/TwigHooks/tests/Unit/Hook/NameGenerator/TemplateNameGeneratorTest.php b/src/TwigHooks/tests/Unit/Hook/NameGenerator/TemplateNameGeneratorTest.php deleted file mode 100644 index 250e81ad..00000000 --- a/src/TwigHooks/tests/Unit/Hook/NameGenerator/TemplateNameGeneratorTest.php +++ /dev/null @@ -1,40 +0,0 @@ -createTestSubject(); - - self::assertSame($expectedResult, $subject->generate($input, ...$extraParts)); - } - - public function itGeneratesNameDataProvider(): array - { - return [ - ['@SyliusShop/layout.html.twig', ['header'], 'sylius_shop.layout.header'], - ['@SyliusShop/layout.html.twig', ['header', 'menu'], 'sylius_shop.layout.header.menu'], - ['@SyliusShop/layout.html.twig', ['header', 'menu', 'footer'], 'sylius_shop.layout.header.menu.footer'], - ['@SyliusShop/_template.html.twig', [], 'sylius_shop.template'], - ['@SyliusShop/_template.html.twig', ['header'], 'sylius_shop.template.header'], - ['@SyliusShop/_template.html.twig', ['header', 'hamburger_menu'], 'sylius_shop.template.header.hamburger_menu'], - ['@SyliusShop/_template.html.twig', ['header', 'hamburgerMenu'], 'sylius_shop.template.header.hamburger_menu'], - ['@SyliusAdmin\Shared\Crud/update.html.twig', [], 'sylius_admin.shared.crud.update'] - ]; - } - - private function createTestSubject(): TemplateNameGenerator - { - return new TemplateNameGenerator(); - } -} diff --git a/src/TwigHooks/tests/Unit/Hook/Normalizer/CompositeNameNormalizerTest.php b/src/TwigHooks/tests/Unit/Hook/Normalizer/CompositeNameNormalizerTest.php new file mode 100644 index 00000000..e31bb4b0 --- /dev/null +++ b/src/TwigHooks/tests/Unit/Hook/Normalizer/CompositeNameNormalizerTest.php @@ -0,0 +1,25 @@ +createMock(NameNormalizerInterface::class); + $dummyNormalizer->expects($this->once())->method('normalize')->with('hook_name')->willReturn('hook_name_normalized'); + $zummyNormalizer = $this->createMock(NameNormalizerInterface::class); + $zummyNormalizer->expects($this->once())->method('normalize')->with('hook_name_normalized')->willReturn('hook_name_normalized_normalized'); + + $compositeNameNormalizer = new CompositeNameNormalizer([$dummyNormalizer, $zummyNormalizer]); + $normalizedHookName = $compositeNameNormalizer->normalize('hook_name'); + + $this->assertSame('hook_name_normalized_normalized', $normalizedHookName); + } +} diff --git a/src/TwigHooks/tests/Unit/Hook/Normalizer/RemoveSectionPartNormalizerTest.php b/src/TwigHooks/tests/Unit/Hook/Normalizer/RemoveSectionPartNormalizerTest.php new file mode 100644 index 00000000..2d08bbdd --- /dev/null +++ b/src/TwigHooks/tests/Unit/Hook/Normalizer/RemoveSectionPartNormalizerTest.php @@ -0,0 +1,38 @@ +assertSame('hook_name_section', $removeSectionPartNormalizer->normalize('hook_name_section')); + $this->assertSame('hook_name', $removeSectionPartNormalizer->normalize('hook_name#section')); + $this->assertSame('hook_name.section', $removeSectionPartNormalizer->normalize('hook_name.section')); + } + + public function testItRemovesSectionPartFromNameWithUsingOtherSeparatorThanHash(): void + { + $removeSectionPartNormalizer = new RemoveSectionPartNormalizer(separator: '|'); + + $this->assertSame('hook_name_section', $removeSectionPartNormalizer->normalize('hook_name_section')); + $this->assertSame('hook_name', $removeSectionPartNormalizer->normalize('hook_name|section')); + $this->assertSame('hook_name.section', $removeSectionPartNormalizer->normalize('hook_name.section')); + } + + public function testItSkipsRemovingSectionPartIfSeparatorIsFalse(): void + { + $removeSectionPartNormalizer = new RemoveSectionPartNormalizer(separator: false); + + $this->assertSame('hook_name_section', $removeSectionPartNormalizer->normalize('hook_name_section')); + $this->assertSame('hook_name#section', $removeSectionPartNormalizer->normalize('hook_name#section')); + $this->assertSame('hook_name.section', $removeSectionPartNormalizer->normalize('hook_name.section')); + } +}