Skip to content

Commit e53a8f8

Browse files
committed
feature #110 Adding a simpler syntax for single stimulus controller elements (weaverryan)
This PR was merged into the main branch. Discussion ---------- Adding a simpler syntax for single stimulus controller elements Having 1 controller per element is the main use-case. This makes that a bit nicer to do :). ```twig <div {{ stimulus_controller('chart', { 'name': 'Likes', 'data': [1, 2, 3, 4] }) }}> Hello </div> ``` Also, this makes working with controllers that don't have any values (yet) MUCH nicer: ```twig <!-- before --> {{ stimulus_controller({ 'chart': {} }) }} <!-- now --> {{ stimulus_controller('chart') }} ``` Cheers! Commits ------- 773ead9 adding a simpler syntax for single stimulus controller elements
2 parents ad290c5 + 773ead9 commit e53a8f8

File tree

3 files changed

+64
-14
lines changed

3 files changed

+64
-14
lines changed

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ See [stimulus-bridge](https://github.com/symfony/stimulus-bridge) for more detai
207207
For example:
208208

209209
```twig
210-
<div {{ stimulus_controller({ 'chart': { 'name': 'Likes', 'data': [1, 2, 3, 4] } }) }}>
210+
<div {{ stimulus_controller('chart', { 'name': 'Likes', 'data': [1, 2, 3, 4] }) }}>
211211
Hello
212212
</div>
213213
@@ -223,6 +223,18 @@ For example:
223223

224224
Any non-scalar values (like `data: [1, 2, 3, 4]`) are JSON-encoded. And all
225225
values are properly escaped (the string `&#x5B;` is an escaped
226-
`[` character, so the attribute is really `[1,2,3,4]`).
226+
`[` character, so the attribute is really `[1,2,3,4]`).
227+
228+
If you have multiple controllers on the same element, pass them all as an
229+
associative array in the first argument:
230+
231+
```twig
232+
<div {{ stimulus_controller({
233+
'chart': { 'name': 'Likes' },
234+
'other-controller': { },
235+
) }}>
236+
Hello
237+
</div>
238+
```
227239

228240
Ok, have fun!

src/Twig/StimulusTwigExtension.php

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,29 @@ public function getFunctions()
2222
];
2323
}
2424

25-
public function renderStimulusController(Environment $env, array $data): string
25+
/**
26+
* @param string|array $dataOrControllerName This can either be a map of controller names
27+
* as keys set to their "values". Or this
28+
* can be a string controller name and data
29+
* is passed as the 2nd argument.
30+
* @param array $controllerValues Array of data if a string is passed to the first argument.
31+
* @return string
32+
* @throws \Twig\Error\RuntimeError
33+
*/
34+
public function renderStimulusController(Environment $env, $dataOrControllerName, array $controllerValues = []): string
2635
{
27-
if (!$data) {
28-
return '';
36+
if (is_string($dataOrControllerName)) {
37+
$data = [$dataOrControllerName => $controllerValues];
38+
} else {
39+
if ($controllerValues) {
40+
throw new \InvalidArgumentException('You cannot pass an array to the first and second argument of stimulus_controller(): check the documentation.');
41+
}
42+
43+
$data = $dataOrControllerName;
44+
45+
if (!$data) {
46+
return '';
47+
}
2948
}
3049

3150
$controllers = [];

tests/IntegrationTest.php

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -182,79 +182,98 @@ public function testAutowireDefaultBuildArgument()
182182
public function provideRenderStimulusController()
183183
{
184184
yield 'empty' => [
185-
'data' => [],
185+
'dataOrControllerName' => [],
186+
'controllerValues' => [],
186187
'expected' => '',
187188
];
188189

189190
yield 'single-controller-no-data' => [
190-
'data' => [
191+
'dataOrControllerName' => [
191192
'my-controller' => [],
192193
],
194+
'controllerValues' => [],
193195
'expected' => 'data-controller="my-controller"',
194196
];
195197

196198
yield 'single-controller-scalar-data' => [
197-
'data' => [
199+
'dataOrControllerName' => [
198200
'my-controller' => [
199201
'myValue' => 'scalar-value',
200202
],
201203
],
204+
'controllerValues' => [],
202205
'expected' => 'data-controller="my-controller" data-my-controller-my-value-value="scalar-value"',
203206
];
204207

205208
yield 'single-controller-typed-data' => [
206-
'data' => [
209+
'dataOrControllerName' => [
207210
'my-controller' => [
208211
'boolean' => true,
209212
'number' => 4,
210213
'string' => 'str',
211214
],
212215
],
216+
'controllerValues' => [],
213217
'expected' => 'data-controller="my-controller" data-my-controller-boolean-value="1" data-my-controller-number-value="4" data-my-controller-string-value="str"',
214218
];
215219

216220
yield 'single-controller-nested-data' => [
217-
'data' => [
221+
'dataOrControllerName' => [
218222
'my-controller' => [
219223
'myValue' => ['nested' => 'array'],
220224
],
221225
],
226+
'controllerValues' => [],
222227
'expected' => 'data-controller="my-controller" data-my-controller-my-value-value="&#x7B;&quot;nested&quot;&#x3A;&quot;array&quot;&#x7D;"',
223228
];
224229

225230
yield 'multiple-controllers-scalar-data' => [
226-
'data' => [
231+
'dataOrControllerName' => [
227232
'my-controller' => [
228233
'myValue' => 'scalar-value',
229234
],
230235
'another-controller' => [
231236
'anotherValue' => 'scalar-value 2',
232237
],
233238
],
239+
'controllerValues' => [],
234240
'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"',
235241
];
236242

237243
yield 'normalize-names' => [
238-
'data' => [
244+
'dataOrControllerName' => [
239245
'@symfony/ux-dropzone/dropzone' => [
240246
'my"Key"' => true,
241247
],
242248
],
249+
'controllerValues' => [],
243250
'expected' => 'data-controller="symfony--ux-dropzone--dropzone" data-symfony--ux-dropzone--dropzone-my-key-value="1"',
244251
];
252+
253+
yield 'short-single-controller-no-data' => [
254+
'dataOrControllerName' => 'my-controller',
255+
'controllerValues' => [],
256+
'expected' => 'data-controller="my-controller"',
257+
];
258+
259+
yield 'short-single-controller-with-data' => [
260+
'dataOrControllerName' => 'my-controller',
261+
'controllerValues' => ['myValue' => 'scalar-value'],
262+
'expected' => 'data-controller="my-controller" data-my-controller-my-value-value="scalar-value"',
263+
];
245264
}
246265

247266
/**
248267
* @dataProvider provideRenderStimulusController
249268
*/
250-
public function testRenderStimulusController(array $data, string $expected)
269+
public function testRenderStimulusController($dataOrControllerName, array $controllerValues, string $expected)
251270
{
252271
$kernel = new WebpackEncoreIntegrationTestKernel(true);
253272
$kernel->boot();
254273
$twig = $this->getTwigEnvironmentFromBootedKernel($kernel);
255274

256275
$extension = new StimulusTwigExtension();
257-
$this->assertSame($expected, $extension->renderStimulusController($twig, $data));
276+
$this->assertSame($expected, $extension->renderStimulusController($twig, $dataOrControllerName, $controllerValues));
258277
}
259278

260279
private function getContainerFromBootedKernel(WebpackEncoreIntegrationTestKernel $kernel)

0 commit comments

Comments
 (0)