Skip to content

Commit

Permalink
Check for attributes overlapping with the reserved ones (action, targ…
Browse files Browse the repository at this point in the history
…ets), use the same rendering for the reserved and user-defined attributes.
  • Loading branch information
DRaichev committed Oct 27, 2024
1 parent 69fcf9f commit 66f7e36
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 8 deletions.
30 changes: 23 additions & 7 deletions src/Turbo/src/Helper/TurboStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ public static function prepend(string $target, string $html): string
*/
public static function replace(string $target, string $html, bool $morph = false): string
{
return self::custom('replace', $target, $html, $morph ? ['method="morph"'] : []);
return self::custom('replace', $target, $html, $morph ? ['method' => 'morph'] : []);
}

/**
* Updates the content of the element(s) designated by the target CSS selector.
*/
public static function update(string $target, string $html, bool $morph = false): string
{
return self::custom('update', $target, $html, $morph ? ['method="morph"'] : []);
return self::custom('update', $target, $html, $morph ? ['method' => 'morph'] : []);
}

/**
Expand Down Expand Up @@ -87,17 +87,33 @@ public static function refresh(?string $requestId = null): string
}

/**
* @param array<string> $attr
* Custom action and attributes.
*
* @param array<string, string|int|null> $attr
*/
public static function custom(string $action, string $target, string $html, array $attr = []): string
{
// Join array elements with a space and prepend a leading space
$atrrString = empty($attr) ? '' : ' '.implode(' ', $attr);
if (\array_key_exists('action', $attr) || \array_key_exists('targets', $attr)) {
throw new \InvalidArgumentException('The "action" and "targets" attributes are reserved and cannot be used.');
}

$attr['action'] = $action;
$attr['targets'] = $target;
$attr = array_merge(['action' => $action, 'targets' => $target], $attr);

$attrString = '';
foreach ($attr as $key => $value) {
if (null === $value) {
$attrString .= \sprintf(' %s', $key);
} else {
$attrString .= \sprintf(' %s="%s"', $key, \is_string($value) ? htmlspecialchars($value) : $value);
}
}

return \sprintf(<<<EOHTML
<turbo-stream action="%s" targets="%s"%s>
<turbo-stream%s>
<template>%s</template>
</turbo-stream>
EOHTML, $action, htmlspecialchars($target), $atrrString, $html);
EOHTML, $attrString, $html);
}
}
21 changes: 20 additions & 1 deletion src/Turbo/tests/Helper/TurboStreamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\UX\Turbo\Tests\Helper;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\TestCase;
use Symfony\UX\Turbo\Helper\TurboStream;

Expand Down Expand Up @@ -84,7 +86,24 @@ public function testCustom(): void
<template><div>content</div></template>
</turbo-stream>
EOHTML,
TurboStream::custom('customAction', 'some["selector"]', '<div>content</div>', ['someAttr="someValue"', 'boolAttr'])
TurboStream::custom('customAction', 'some["selector"]', '<div>content</div>', ['someAttr' => 'someValue', 'boolAttr' => null])
);
}

/**
* @dataProvider customThrowsExceptionDataProvider
*
* @param array<string, string|int|null> $attr
*/
public function testCustomThrowsException(string $action, string $target, string $html, array $attr): void
{
$this->expectException(\InvalidArgumentException::class);
TurboStream::custom($action, $target, $html, $attr);
}

public static function customThrowsExceptionDataProvider(): \Generator
{
yield ['customAction', 'some["selector"]', '<div>content</div>', ['action' => 'someAction']];
yield ['customAction', 'some["selector"]', '<div>content</div>', ['targets' => 'someTargets']];
}
}

0 comments on commit 66f7e36

Please sign in to comment.