Skip to content

Commit

Permalink
Fix double escaping in stimulus DTOs when using toArray() in combinat…
Browse files Browse the repository at this point in the history
…ion with form methods

toArray() should return an array with non-escaped attribute key-value pairs, because
they will be escaped when printed.
  • Loading branch information
jeroennoten committed Jan 15, 2023
1 parent 52443ff commit 0d40126
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/Dto/AbstractStimulusDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected function getFormattedValue($value)
$value = $value ? 'true' : 'false';
}

return $this->escapeAsHtmlAttr($value);
return (string) $value;
}

protected function escapeAsHtmlAttr($value): string
Expand Down
4 changes: 2 additions & 2 deletions src/Dto/StimulusActionsDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public function __toString(): string
return '';
}

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

Expand Down
8 changes: 4 additions & 4 deletions src/Dto/StimulusControllersDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ public function __toString(): string

return rtrim(
'data-controller="'.implode(' ', $this->controllers).'" '.
implode(' ', array_map(static function (string $attribute, string $value): string {
return $attribute.'="'.$value.'"';
implode(' ', array_map(function (string $attribute, string $value): string {
return $attribute.'="'.$this->escapeAsHtmlAttr($value).'"';
}, array_keys($this->values), $this->values)).' '.
implode(' ', array_map(static function (string $attribute, string $value): string {
return $attribute.'="'.$value.'"';
implode(' ', array_map(function (string $attribute, string $value): string {
return $attribute.'="'.$this->escapeAsHtmlAttr($value).'"';
}, array_keys($this->classes), $this->classes))
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/Dto/StimulusTargetsDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function addTarget(string $controllerName, string $targetNames = null): v
{
$controllerName = $this->getFormattedControllerName($controllerName);

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

public function __toString(): string
Expand All @@ -32,8 +32,8 @@ public function __toString(): string
return '';
}

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

Expand Down
42 changes: 42 additions & 0 deletions tests/Dto/StimulusActionsDtoTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/*
* This file is part of the Symfony WebpackEncoreBundle package.
* (c) Fabien Potencier <fabien@symfony.com>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\WebpackEncoreBundle\Tests\Dto;

use PHPUnit\Framework\TestCase;
use Symfony\WebpackEncoreBundle\Dto\StimulusActionsDto;
use Twig\Environment;
use Twig\Loader\ArrayLoader;

class StimulusActionsDtoTest extends TestCase
{
/**
* @var StimulusActionsDto
*/
private $stimulusActionsDto;

protected function setUp(): void
{
$this->stimulusActionsDto = new StimulusActionsDto(new Environment(new ArrayLoader()));
}

public function testToStringEscapingAttributeValues(): void
{
$this->stimulusActionsDto->addAction('foo', 'bar', 'baz', ['qux' => '"']);
$attributesHtml = (string) $this->stimulusActionsDto;
self::assertSame('data-action="baz->foo#bar" data-foo-qux-param="&quot;"', $attributesHtml);
}

public function testToArrayNoEscapingAttributeValues(): void
{
$this->stimulusActionsDto->addAction('foo', 'bar', 'baz', ['qux' => '"']);
$attributesArray = $this->stimulusActionsDto->toArray();
self::assertSame(['data-action' => 'baz->foo#bar', 'data-foo-qux-param' => '"'], $attributesArray);
}
}
54 changes: 54 additions & 0 deletions tests/Dto/StimulusControllersDtoTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/*
* This file is part of the Symfony WebpackEncoreBundle package.
* (c) Fabien Potencier <fabien@symfony.com>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\WebpackEncoreBundle\Tests\Dto;

use PHPUnit\Framework\TestCase;
use Symfony\WebpackEncoreBundle\Dto\StimulusControllersDto;
use Twig\Environment;
use Twig\Loader\ArrayLoader;

class StimulusControllersDtoTest extends TestCase
{
/**
* @var StimulusControllersDto
*/
private $stimulusControllersDto;

protected function setUp(): void
{
$this->stimulusControllersDto = new StimulusControllersDto(new Environment(new ArrayLoader()));
}

public function testToStringEscapingAttributeValues(): void
{
$this->stimulusControllersDto->addController('foo', ['bar' => '"'], ['baz' => '"']);
$attributesHtml = (string) $this->stimulusControllersDto;
self::assertSame(
'data-controller="foo" '.
'data-foo-bar-value="&quot;" '.
'data-foo-baz-class="&quot;"',
$attributesHtml
);
}

public function testToArrayNoEscapingAttributeValues(): void
{
$this->stimulusControllersDto->addController('foo', ['bar' => '"'], ['baz' => '"']);
$attributesArray = $this->stimulusControllersDto->toArray();
self::assertSame(
[
'data-controller' => 'foo',
'data-foo-bar-value' => '"',
'data-foo-baz-class' => '"',
],
$attributesArray
);
}
}
42 changes: 42 additions & 0 deletions tests/Dto/StimulusTargetsDtoTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/*
* This file is part of the Symfony WebpackEncoreBundle package.
* (c) Fabien Potencier <fabien@symfony.com>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\WebpackEncoreBundle\Tests\Dto;

use PHPUnit\Framework\TestCase;
use Symfony\WebpackEncoreBundle\Dto\StimulusTargetsDto;
use Twig\Environment;
use Twig\Loader\ArrayLoader;

class StimulusTargetsDtoTest extends TestCase
{
/**
* @var StimulusTargetsDto
*/
private $stimulusTargetsDto;

protected function setUp(): void
{
$this->stimulusTargetsDto = new StimulusTargetsDto(new Environment(new ArrayLoader()));
}

public function testToStringEscapingAttributeValues(): void
{
$this->stimulusTargetsDto->addTarget('foo', '"');
$attributesHtml = (string) $this->stimulusTargetsDto;
self::assertSame('data-foo-target="&quot;"', $attributesHtml);
}

public function testToArrayNoEscapingAttributeValues(): void
{
$this->stimulusTargetsDto->addTarget('foo', '"');
$attributesArray = $this->stimulusTargetsDto->toArray();
self::assertSame(['data-foo-target' => '"'], $attributesArray);
}
}
6 changes: 3 additions & 3 deletions tests/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ public function provideLegacyRenderMultipleStimulusControllers()
],
'controllerValues' => [],
'expectedString' => 'data-controller="my-controller" data-my-controller-my-value-value="&#x7B;&quot;nested&quot;&#x3A;&quot;array&quot;&#x7D;"',
'expectedArray' => ['data-controller' => 'my-controller', 'data-my-controller-my-value-value' => '&#x7B;&quot;nested&quot;&#x3A;&quot;array&quot;&#x7D;'],
'expectedArray' => ['data-controller' => 'my-controller', 'data-my-controller-my-value-value' => '{"nested":"array"}'],
];

yield 'multiple-controllers-scalar-data' => [
Expand All @@ -344,7 +344,7 @@ public function provideLegacyRenderMultipleStimulusControllers()
],
'controllerValues' => [],
'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"',
'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'],
'expectedArray' => ['data-controller' => 'my-controller another-controller', 'data-my-controller-my-value-value' => 'scalar-value', 'data-another-controller-another-value-value' => 'scalar-value 2'],
];

yield 'normalize-names' => [
Expand Down Expand Up @@ -582,7 +582,7 @@ public function testLegacyRenderMultipleStimulusTargets()

$this->assertSame([
'data-my-controller-target' => 'myTarget',
'data-symfony--ux-dropzone--dropzone-target' => 'anotherTarget&#x20;fooTarget',
'data-symfony--ux-dropzone--dropzone-target' => 'anotherTarget fooTarget',
],
$dto->toArray()
);
Expand Down

0 comments on commit 0d40126

Please sign in to comment.