Skip to content

Commit 9210738

Browse files
committed
Introduce stimulus_controller to ease Stimulus Values API usage
1 parent 4dc8ecb commit 9210738

File tree

5 files changed

+135
-0
lines changed

5 files changed

+135
-0
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"require-dev": {
3232
"symfony/framework-bundle": "^4.4 || ^5.0",
3333
"symfony/phpunit-bridge": "^4.4 || ^5.0",
34+
"symfony/string": "^5.0",
3435
"symfony/twig-bundle": "^4.4 || ^5.0",
3536
"symfony/web-link": "^4.4 || ^5.0"
3637
},
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony WebpackEncoreBundle package.
5+
* (c) Fabien Potencier <[email protected]>
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace Symfony\WebpackEncoreBundle\Exception;
11+
12+
class MissingPackageException extends \LogicException
13+
{
14+
}

src/Resources/config/services.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
</argument>
3737
</service>
3838

39+
<service id="webpack_encore.twig_stimulus_extension" class="Symfony\WebpackEncoreBundle\Twig\StimulusTwigExtension">
40+
<tag name="twig.extension" />
41+
</service>
42+
3943
<service id="webpack_encore.entrypoint_lookup.cache_warmer" class="Symfony\WebpackEncoreBundle\CacheWarmer\EntrypointCacheWarmer">
4044
<tag name="kernel.cache_warmer" />
4145
<argument /> <!-- build list of entrypoint paths -->

src/Twig/StimulusTwigExtension.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony WebpackEncoreBundle package.
5+
* (c) Fabien Potencier <[email protected]>
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace Symfony\WebpackEncoreBundle\Twig;
11+
12+
use Symfony\Component\String\UnicodeString;
13+
use Symfony\WebpackEncoreBundle\Exception\MissingPackageException;
14+
use Twig\Environment;
15+
use Twig\Extension\AbstractExtension;
16+
use Twig\TwigFunction;
17+
18+
final class StimulusTwigExtension extends AbstractExtension
19+
{
20+
public function getFunctions()
21+
{
22+
return [
23+
new TwigFunction('stimulus_controller', [$this, 'renderStimulusController'], ['needs_environment' => true, 'is_safe' => ['all']]),
24+
];
25+
}
26+
27+
public function renderStimulusController(Environment $env, array $data): string
28+
{
29+
if (!class_exists(UnicodeString::class)) {
30+
throw new MissingPackageException("Missing package, to use the \"stimulus_controller\" function, run:\n\ncomposer require symfony/string");
31+
}
32+
33+
if (!$data) {
34+
return '';
35+
}
36+
37+
$controllers = [];
38+
$values = [];
39+
40+
foreach ($data as $controllerName => $controllerValues) {
41+
$controllers[] = $controllerName;
42+
43+
foreach ($controllerValues as $key => $value) {
44+
$key = (new UnicodeString($key))->snake()->replace('_', '-')->lower();
45+
46+
if (!is_scalar($value)) {
47+
$value = json_encode($value);
48+
}
49+
50+
$value = twig_escape_filter($env, $value, 'html_attr');
51+
$values[] = 'data-'.$controllerName.'-'.$key.'-value="'.$value.'"';
52+
}
53+
}
54+
55+
return rtrim('data-controller="'.implode(' ', $controllers).'" '.implode(' ', $values));
56+
}
57+
}

tests/IntegrationTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface;
2929
use Symfony\WebpackEncoreBundle\Asset\TagRenderer;
3030
use Symfony\WebpackEncoreBundle\CacheWarmer\EntrypointCacheWarmer;
31+
use Symfony\WebpackEncoreBundle\Twig\StimulusTwigExtension;
3132
use Symfony\WebpackEncoreBundle\WebpackEncoreBundle;
3233

3334
class IntegrationTest extends TestCase
@@ -178,6 +179,64 @@ public function testAutowireDefaultBuildArgument()
178179
$this->assertTrue(true);
179180
}
180181

182+
public function provideRenderStimulusController()
183+
{
184+
yield 'empty' => [
185+
'data' => [],
186+
'expected' => '',
187+
];
188+
189+
yield 'single-controller-no-data' => [
190+
'data' => [
191+
'my-controller' => [],
192+
],
193+
'expected' => 'data-controller="my-controller"',
194+
];
195+
196+
yield 'single-controller-scalar-data' => [
197+
'data' => [
198+
'my-controller' => [
199+
'myValue' => 'scalar-value',
200+
],
201+
],
202+
'expected' => 'data-controller="my-controller" data-my-controller-my-value-value="scalar-value"',
203+
];
204+
205+
yield 'single-controller-nested-data' => [
206+
'data' => [
207+
'my-controller' => [
208+
'myValue' => ['nested' => 'array'],
209+
],
210+
],
211+
'expected' => 'data-controller="my-controller" data-my-controller-my-value-value="&#x7B;&quot;nested&quot;&#x3A;&quot;array&quot;&#x7D;"',
212+
];
213+
214+
yield 'multiple-controllers-scalar-data' => [
215+
'data' => [
216+
'my-controller' => [
217+
'myValue' => 'scalar-value',
218+
],
219+
'another-controller' => [
220+
'anotherValue' => 'scalar-value 2',
221+
],
222+
],
223+
'expected' => 'data-controller="my-controller another-controller" data-my-controller-my-value-value="scalar-value" data-another-controller-another-value-value="scalar-value&#x20;2"',
224+
];
225+
}
226+
227+
/**
228+
* @dataProvider provideRenderStimulusController
229+
*/
230+
public function testRenderStimulusController(array $data, string $expected)
231+
{
232+
$kernel = new WebpackEncoreIntegrationTestKernel(true);
233+
$kernel->boot();
234+
$twig = $this->getTwigEnvironmentFromBootedKernel($kernel);
235+
236+
$extension = new StimulusTwigExtension();
237+
$this->assertSame($expected, $extension->renderStimulusController($twig, $data));
238+
}
239+
181240
private function getContainerFromBootedKernel(WebpackEncoreIntegrationTestKernel $kernel)
182241
{
183242
if ($kernel::VERSION_ID >= 40100) {

0 commit comments

Comments
 (0)