Skip to content

Commit 964a313

Browse files
committed
Change how data is passed to the component hookables
1 parent f2dd5d5 commit 964a313

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"php": "^8.1",
1919
"symfony/config": "^5.4 || ^6.0",
2020
"symfony/dependency-injection": "^5.4 || ^6.0",
21+
"symfony/expression-language": "^5.4 || ^6.0",
2122
"symfony/http-kernel": "^5.4 || ^6.0",
2223
"symfony/stopwatch": "^5.4 || ^6.0",
2324
"symfony/ux-twig-component": "^2.12",

src/TwigHooks/config/services.php

+8
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
44

55
use Sylius\TwigHooks\Hook\NameGenerator\TemplateNameGenerator;
6+
use Sylius\TwigHooks\Provider\ComponentDataProvider;
67
use Sylius\TwigHooks\Provider\DefaultConfigurationProvider;
78
use Sylius\TwigHooks\Provider\DefaultDataProvider;
89
use Sylius\TwigHooks\Registry\HookablesRegistry;
910
use Sylius\TwigHooks\Twig\HooksExtension;
1011
use Sylius\TwigHooks\Twig\Runtime\HooksRuntime;
12+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
1113

1214
return static function (ContainerConfigurator $configurator): void {
1315
$configurator->import(__DIR__ . '/services/*.php');
@@ -16,6 +18,12 @@
1618

1719
$services->set('twig_hooks.provider.default_data', DefaultDataProvider::class);
1820

21+
$services->set('twig_hooks.provider.component_data', ComponentDataProvider::class)
22+
->args([
23+
inline_service(ExpressionLanguage::class),
24+
])
25+
;
26+
1927
$services->set('twig_hooks.provider.default_configuration', DefaultConfigurationProvider::class);
2028

2129
$services->set('twig_hooks.registry.hookables', HookablesRegistry::class)

src/TwigHooks/config/services/hookable_renderer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
$services->set('twig_hooks.renderer.hookable.component', HookableComponentRenderer::class)
2222
->args([
2323
service('ux.twig_component.component_renderer'),
24-
service('twig_hooks.provider.default_data'),
24+
service('twig_hooks.provider.component_data'),
2525
service('twig_hooks.provider.default_configuration'),
2626
])
2727
->tag('twig_hooks.hookable_renderer')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sylius\TwigHooks\Provider;
6+
7+
use Sylius\TwigHooks\Hookable\AbstractHookable;
8+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
9+
10+
final class ComponentDataProvider implements DataProviderInterface
11+
{
12+
public function __construct (
13+
private ExpressionLanguage $expressionLanguage,
14+
) {
15+
}
16+
17+
public function provide(AbstractHookable $hookable, array $hookData): array
18+
{
19+
return $this->mapArrayRecursively(function (mixed $value) use ($hookData): mixed {
20+
if (is_string($value) && str_starts_with($value, '@=')) {
21+
return $this->expressionLanguage->evaluate(substr($value, 2), ['data' => $hookData]);
22+
}
23+
24+
return $value;
25+
}, $hookable->getData());
26+
}
27+
28+
/**
29+
* @param array<array-key, mixed> $array
30+
* @return array<array-key, mixed>
31+
*/
32+
private function mapArrayRecursively(callable $callback, array $array): array
33+
{
34+
$result = [];
35+
foreach ($array as $key => $value) {
36+
$result[$key] = is_array($value)
37+
? $this->mapArrayRecursively($callback, $value)
38+
: $callback($value);
39+
}
40+
41+
return $result;
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Sylius\TwigHooks\Unit\Provider;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Sylius\TwigHooks\Provider\ComponentDataProvider;
9+
use Sylius\TwigHooks\Provider\DataProviderInterface;
10+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
11+
use Tests\Sylius\TwigHooks\Utils\MotherObject\BaseHookableMotherObject;
12+
13+
final class ComponentDataProviderTest extends TestCase
14+
{
15+
public function testItReturnsEmptyArrayWhenNoDataIsProvidedOnHookable(): void
16+
{
17+
$hookable = BaseHookableMotherObject::some();
18+
19+
$dataProvider = $this->createTestSubject();
20+
21+
$this->assertSame([], $dataProvider->provide($hookable, []));
22+
$this->assertSame([], $dataProvider->provide($hookable, ['some' => 'data']));
23+
}
24+
25+
public function testItReturnsDataFromHookable(): void
26+
{
27+
$hookable = BaseHookableMotherObject::withData(['some' => 'data']);
28+
29+
$dataProvider = $this->createTestSubject();
30+
31+
$this->assertSame(['some' => 'data'], $dataProvider->provide($hookable, []));
32+
$this->assertSame(['some' => 'data'], $dataProvider->provide($hookable, ['more' => 'data']));
33+
}
34+
35+
public function testItPassesTemplateLevelDataToExpressionLanguage(): void
36+
{
37+
$hookable = BaseHookableMotherObject::withData(['some_key' => '@=data["some"]']);
38+
39+
$dataProvider = $this->createTestSubject();
40+
41+
$this->assertSame(['some_key' => 'data'], $dataProvider->provide($hookable, ['some' => 'data']));
42+
}
43+
44+
private function createTestSubject(): DataProviderInterface
45+
{
46+
return new ComponentDataProvider(
47+
new ExpressionLanguage(),
48+
);
49+
}
50+
}

0 commit comments

Comments
 (0)