From 2d1c684a8d3f395bf5444d22ccb22b5bbd52a7f6 Mon Sep 17 00:00:00 2001 From: Jacob Tobiasz Date: Wed, 7 Feb 2024 21:51:37 +0100 Subject: [PATCH] Change how data is passed to the component hookables --- composer.json | 1 + src/TwigHooks/config/services.php | 8 +++ .../config/services/hookable_renderer.php | 2 +- .../Renderer/HookableComponentRenderer.php | 2 +- .../src/Provider/ComponentDataProvider.php | 43 ++++++++++++++++ .../HookableComponentRendererTest.php | 2 +- .../Provider/ComponentDataProviderTest.php | 50 +++++++++++++++++++ 7 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 src/TwigHooks/src/Provider/ComponentDataProvider.php create mode 100644 src/TwigHooks/tests/Unit/Provider/ComponentDataProviderTest.php diff --git a/composer.json b/composer.json index 51b5a9de..50f74100 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "php": "^8.1", "symfony/config": "^5.4 || ^6.0", "symfony/dependency-injection": "^5.4 || ^6.0", + "symfony/expression-language": "^5.4 || ^6.0", "symfony/http-kernel": "^5.4 || ^6.0", "symfony/stopwatch": "^5.4 || ^6.0", "symfony/ux-twig-component": "^2.12", diff --git a/src/TwigHooks/config/services.php b/src/TwigHooks/config/services.php index 92a75f5a..7ac0ee07 100644 --- a/src/TwigHooks/config/services.php +++ b/src/TwigHooks/config/services.php @@ -3,11 +3,13 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Sylius\TwigHooks\Hook\NameGenerator\TemplateNameGenerator; +use Sylius\TwigHooks\Provider\ComponentDataProvider; use Sylius\TwigHooks\Provider\DefaultConfigurationProvider; use Sylius\TwigHooks\Provider\DefaultDataProvider; use Sylius\TwigHooks\Registry\HookablesRegistry; use Sylius\TwigHooks\Twig\HooksExtension; use Sylius\TwigHooks\Twig\Runtime\HooksRuntime; +use Symfony\Component\ExpressionLanguage\ExpressionLanguage; return static function (ContainerConfigurator $configurator): void { $configurator->import(__DIR__ . '/services/*.php'); @@ -16,6 +18,12 @@ $services->set('twig_hooks.provider.default_data', DefaultDataProvider::class); + $services->set('twig_hooks.provider.component_data', ComponentDataProvider::class) + ->args([ + inline_service(ExpressionLanguage::class), + ]) + ; + $services->set('twig_hooks.provider.default_configuration', DefaultConfigurationProvider::class); $services->set('twig_hooks.registry.hookables', HookablesRegistry::class) diff --git a/src/TwigHooks/config/services/hookable_renderer.php b/src/TwigHooks/config/services/hookable_renderer.php index 2d2548d4..b284fb26 100644 --- a/src/TwigHooks/config/services/hookable_renderer.php +++ b/src/TwigHooks/config/services/hookable_renderer.php @@ -21,7 +21,7 @@ $services->set('twig_hooks.renderer.hookable.component', HookableComponentRenderer::class) ->args([ service('ux.twig_component.component_renderer'), - service('twig_hooks.provider.default_data'), + service('twig_hooks.provider.component_data'), service('twig_hooks.provider.default_configuration'), ]) ->tag('twig_hooks.hookable_renderer') diff --git a/src/TwigHooks/src/Hookable/Renderer/HookableComponentRenderer.php b/src/TwigHooks/src/Hookable/Renderer/HookableComponentRenderer.php index 95807810..57797419 100644 --- a/src/TwigHooks/src/Hookable/Renderer/HookableComponentRenderer.php +++ b/src/TwigHooks/src/Hookable/Renderer/HookableComponentRenderer.php @@ -35,8 +35,8 @@ public function render(AbstractHookable $hookable, array $hookData = []): string $configuration = $this->configurationProvider->provide($hookable); return $this->componentRenderer->createAndRender($hookable->getTarget(), [ - self::HOOKABLE_DATA_PARAMETER => $data, self::HOOKABLE_CONFIGURATION_PARAMETER => $configuration, + ...$data, ]); } diff --git a/src/TwigHooks/src/Provider/ComponentDataProvider.php b/src/TwigHooks/src/Provider/ComponentDataProvider.php new file mode 100644 index 00000000..a8f0a53c --- /dev/null +++ b/src/TwigHooks/src/Provider/ComponentDataProvider.php @@ -0,0 +1,43 @@ +mapArrayRecursively(function (mixed $value) use ($hookData): mixed { + if (is_string($value) && str_starts_with($value, '@=')) { + return $this->expressionLanguage->evaluate(substr($value, 2), ['data' => $hookData]); + } + + return $value; + }, $hookable->getData()); + } + + /** + * @param array $array + * @return array + */ + private function mapArrayRecursively(callable $callback, array $array): array + { + $result = []; + foreach ($array as $key => $value) { + $result[$key] = is_array($value) + ? $this->mapArrayRecursively($callback, $value) + : $callback($value); + } + + return $result; + } +} diff --git a/src/TwigHooks/tests/Unit/Hookable/Renderer/HookableComponentRendererTest.php b/src/TwigHooks/tests/Unit/Hookable/Renderer/HookableComponentRendererTest.php index 2b1ccecb..cc8c822d 100644 --- a/src/TwigHooks/tests/Unit/Hookable/Renderer/HookableComponentRendererTest.php +++ b/src/TwigHooks/tests/Unit/Hookable/Renderer/HookableComponentRendererTest.php @@ -58,8 +58,8 @@ public function testItRendersHookableComponent(): void $this->componentRenderer->expects($this->once())->method('createAndRender')->with( 'some-component', [ - HookableComponentRenderer::HOOKABLE_DATA_PARAMETER => ['some' => 'data'], HookableComponentRenderer::HOOKABLE_CONFIGURATION_PARAMETER => ['some' => 'configuration'], + 'some' => 'data', ] )->willReturn('some-rendered-component'); diff --git a/src/TwigHooks/tests/Unit/Provider/ComponentDataProviderTest.php b/src/TwigHooks/tests/Unit/Provider/ComponentDataProviderTest.php new file mode 100644 index 00000000..0bcf5642 --- /dev/null +++ b/src/TwigHooks/tests/Unit/Provider/ComponentDataProviderTest.php @@ -0,0 +1,50 @@ +createTestSubject(); + + $this->assertSame([], $dataProvider->provide($hookable, [])); + $this->assertSame([], $dataProvider->provide($hookable, ['some' => 'data'])); + } + + public function testItReturnsDataFromHookable(): void + { + $hookable = BaseHookableMotherObject::withData(['some' => 'data']); + + $dataProvider = $this->createTestSubject(); + + $this->assertSame(['some' => 'data'], $dataProvider->provide($hookable, [])); + $this->assertSame(['some' => 'data'], $dataProvider->provide($hookable, ['more' => 'data'])); + } + + public function testItPassesTemplateLevelDataToExpressionLanguage(): void + { + $hookable = BaseHookableMotherObject::withData(['some_key' => '@=data["some"]']); + + $dataProvider = $this->createTestSubject(); + + $this->assertSame(['some_key' => 'data'], $dataProvider->provide($hookable, ['some' => 'data'])); + } + + private function createTestSubject(): DataProviderInterface + { + return new ComponentDataProvider( + new ExpressionLanguage(), + ); + } +}