Skip to content

Commit 1862d71

Browse files
committed
bug #202 Fix double escaping in stimulus DTOs when using toArray() in combination with form methods (jeroennoten)
This PR was merged into the main branch. Discussion ---------- Fix double escaping in stimulus DTOs when using toArray() in combination with form methods This fixes a double-escaping bug when the `toArray()` methods are used in combination with the `form_` functions, as described in the README. `toArray()` should return an array with non-escaped attribute key-value pairs, because they will be escaped when printed. Therefore, I moved the escaping of the values to the `toString()` methods and I added some additional tests for the DTO classes to verify the change. This additionally fixes a missed escape for the `data-[controller]-[key]-class` attribute values. Commits ------- 0d40126 Fix double escaping in stimulus DTOs when using toArray() in combination with form methods
2 parents 52443ff + 0d40126 commit 1862d71

8 files changed

+151
-13
lines changed

src/Dto/AbstractStimulusDto.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ protected function getFormattedValue($value)
4545
$value = $value ? 'true' : 'false';
4646
}
4747

48-
return $this->escapeAsHtmlAttr($value);
48+
return (string) $value;
4949
}
5050

5151
protected function escapeAsHtmlAttr($value): string

src/Dto/StimulusActionsDto.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ public function __toString(): string
4141
return '';
4242
}
4343

44-
return rtrim('data-action="'.implode(' ', $this->actions).'" '.implode(' ', array_map(static function (string $attribute, string $value): string {
45-
return $attribute.'="'.$value.'"';
44+
return rtrim('data-action="'.implode(' ', $this->actions).'" '.implode(' ', array_map(function (string $attribute, string $value): string {
45+
return $attribute.'="'.$this->escapeAsHtmlAttr($value).'"';
4646
}, array_keys($this->parameters), $this->parameters)));
4747
}
4848

src/Dto/StimulusControllersDto.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ public function __toString(): string
4848

4949
return rtrim(
5050
'data-controller="'.implode(' ', $this->controllers).'" '.
51-
implode(' ', array_map(static function (string $attribute, string $value): string {
52-
return $attribute.'="'.$value.'"';
51+
implode(' ', array_map(function (string $attribute, string $value): string {
52+
return $attribute.'="'.$this->escapeAsHtmlAttr($value).'"';
5353
}, array_keys($this->values), $this->values)).' '.
54-
implode(' ', array_map(static function (string $attribute, string $value): string {
55-
return $attribute.'="'.$value.'"';
54+
implode(' ', array_map(function (string $attribute, string $value): string {
55+
return $attribute.'="'.$this->escapeAsHtmlAttr($value).'"';
5656
}, array_keys($this->classes), $this->classes))
5757
);
5858
}

src/Dto/StimulusTargetsDto.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function addTarget(string $controllerName, string $targetNames = null): v
2323
{
2424
$controllerName = $this->getFormattedControllerName($controllerName);
2525

26-
$this->targets['data-'.$controllerName.'-target'] = $this->escapeAsHtmlAttr($targetNames);
26+
$this->targets['data-'.$controllerName.'-target'] = $targetNames;
2727
}
2828

2929
public function __toString(): string
@@ -32,8 +32,8 @@ public function __toString(): string
3232
return '';
3333
}
3434

35-
return implode(' ', array_map(static function (string $attribute, string $value): string {
36-
return $attribute.'="'.$value.'"';
35+
return implode(' ', array_map(function (string $attribute, string $value): string {
36+
return $attribute.'="'.$this->escapeAsHtmlAttr($value).'"';
3737
}, array_keys($this->targets), $this->targets));
3838
}
3939

tests/Dto/StimulusActionsDtoTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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\Tests\Dto;
11+
12+
use PHPUnit\Framework\TestCase;
13+
use Symfony\WebpackEncoreBundle\Dto\StimulusActionsDto;
14+
use Twig\Environment;
15+
use Twig\Loader\ArrayLoader;
16+
17+
class StimulusActionsDtoTest extends TestCase
18+
{
19+
/**
20+
* @var StimulusActionsDto
21+
*/
22+
private $stimulusActionsDto;
23+
24+
protected function setUp(): void
25+
{
26+
$this->stimulusActionsDto = new StimulusActionsDto(new Environment(new ArrayLoader()));
27+
}
28+
29+
public function testToStringEscapingAttributeValues(): void
30+
{
31+
$this->stimulusActionsDto->addAction('foo', 'bar', 'baz', ['qux' => '"']);
32+
$attributesHtml = (string) $this->stimulusActionsDto;
33+
self::assertSame('data-action="baz->foo#bar" data-foo-qux-param="&quot;"', $attributesHtml);
34+
}
35+
36+
public function testToArrayNoEscapingAttributeValues(): void
37+
{
38+
$this->stimulusActionsDto->addAction('foo', 'bar', 'baz', ['qux' => '"']);
39+
$attributesArray = $this->stimulusActionsDto->toArray();
40+
self::assertSame(['data-action' => 'baz->foo#bar', 'data-foo-qux-param' => '"'], $attributesArray);
41+
}
42+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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\Tests\Dto;
11+
12+
use PHPUnit\Framework\TestCase;
13+
use Symfony\WebpackEncoreBundle\Dto\StimulusControllersDto;
14+
use Twig\Environment;
15+
use Twig\Loader\ArrayLoader;
16+
17+
class StimulusControllersDtoTest extends TestCase
18+
{
19+
/**
20+
* @var StimulusControllersDto
21+
*/
22+
private $stimulusControllersDto;
23+
24+
protected function setUp(): void
25+
{
26+
$this->stimulusControllersDto = new StimulusControllersDto(new Environment(new ArrayLoader()));
27+
}
28+
29+
public function testToStringEscapingAttributeValues(): void
30+
{
31+
$this->stimulusControllersDto->addController('foo', ['bar' => '"'], ['baz' => '"']);
32+
$attributesHtml = (string) $this->stimulusControllersDto;
33+
self::assertSame(
34+
'data-controller="foo" '.
35+
'data-foo-bar-value="&quot;" '.
36+
'data-foo-baz-class="&quot;"',
37+
$attributesHtml
38+
);
39+
}
40+
41+
public function testToArrayNoEscapingAttributeValues(): void
42+
{
43+
$this->stimulusControllersDto->addController('foo', ['bar' => '"'], ['baz' => '"']);
44+
$attributesArray = $this->stimulusControllersDto->toArray();
45+
self::assertSame(
46+
[
47+
'data-controller' => 'foo',
48+
'data-foo-bar-value' => '"',
49+
'data-foo-baz-class' => '"',
50+
],
51+
$attributesArray
52+
);
53+
}
54+
}

tests/Dto/StimulusTargetsDtoTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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\Tests\Dto;
11+
12+
use PHPUnit\Framework\TestCase;
13+
use Symfony\WebpackEncoreBundle\Dto\StimulusTargetsDto;
14+
use Twig\Environment;
15+
use Twig\Loader\ArrayLoader;
16+
17+
class StimulusTargetsDtoTest extends TestCase
18+
{
19+
/**
20+
* @var StimulusTargetsDto
21+
*/
22+
private $stimulusTargetsDto;
23+
24+
protected function setUp(): void
25+
{
26+
$this->stimulusTargetsDto = new StimulusTargetsDto(new Environment(new ArrayLoader()));
27+
}
28+
29+
public function testToStringEscapingAttributeValues(): void
30+
{
31+
$this->stimulusTargetsDto->addTarget('foo', '"');
32+
$attributesHtml = (string) $this->stimulusTargetsDto;
33+
self::assertSame('data-foo-target="&quot;"', $attributesHtml);
34+
}
35+
36+
public function testToArrayNoEscapingAttributeValues(): void
37+
{
38+
$this->stimulusTargetsDto->addTarget('foo', '"');
39+
$attributesArray = $this->stimulusTargetsDto->toArray();
40+
self::assertSame(['data-foo-target' => '"'], $attributesArray);
41+
}
42+
}

tests/IntegrationTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ public function provideLegacyRenderMultipleStimulusControllers()
330330
],
331331
'controllerValues' => [],
332332
'expectedString' => 'data-controller="my-controller" data-my-controller-my-value-value="&#x7B;&quot;nested&quot;&#x3A;&quot;array&quot;&#x7D;"',
333-
'expectedArray' => ['data-controller' => 'my-controller', 'data-my-controller-my-value-value' => '&#x7B;&quot;nested&quot;&#x3A;&quot;array&quot;&#x7D;'],
333+
'expectedArray' => ['data-controller' => 'my-controller', 'data-my-controller-my-value-value' => '{"nested":"array"}'],
334334
];
335335

336336
yield 'multiple-controllers-scalar-data' => [
@@ -344,7 +344,7 @@ public function provideLegacyRenderMultipleStimulusControllers()
344344
],
345345
'controllerValues' => [],
346346
'expectedString' => 'data-controller="my-controller another-controller" data-my-controller-my-value-value="scalar-value" data-another-controller-another-value-value="scalar-value&#x20;2"',
347-
'expectedArray' => ['data-controller' => 'my-controller another-controller', 'data-my-controller-my-value-value' => 'scalar-value', 'data-another-controller-another-value-value' => 'scalar-value&#x20;2'],
347+
'expectedArray' => ['data-controller' => 'my-controller another-controller', 'data-my-controller-my-value-value' => 'scalar-value', 'data-another-controller-another-value-value' => 'scalar-value 2'],
348348
];
349349

350350
yield 'normalize-names' => [
@@ -582,7 +582,7 @@ public function testLegacyRenderMultipleStimulusTargets()
582582

583583
$this->assertSame([
584584
'data-my-controller-target' => 'myTarget',
585-
'data-symfony--ux-dropzone--dropzone-target' => 'anotherTarget&#x20;fooTarget',
585+
'data-symfony--ux-dropzone--dropzone-target' => 'anotherTarget fooTarget',
586586
],
587587
$dto->toArray()
588588
);

0 commit comments

Comments
 (0)