Skip to content

Commit

Permalink
Add support for custom actions in TurboStream and `TurboStreamRespo…
Browse files Browse the repository at this point in the history
…nse`
  • Loading branch information
DRaichev committed Oct 31, 2024
1 parent bf3a0f0 commit 8c46bf3
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/Turbo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# CHANGELOG
## 2.22.0

- Add support for custom actions in `TurboStream` and `TurboStreamResponse`

## 2.22.0

Expand Down
28 changes: 28 additions & 0 deletions src/Turbo/src/Helper/TurboStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,34 @@ public static function refresh(?string $requestId = null): string
return \sprintf('<turbo-stream action="refresh" request-id="%s"></turbo-stream>', htmlspecialchars($requestId));
}

/**
* Custom action and attributes.
*
* Set boolean attributes (e.g., `disabled`) by providing the attribute name as key with `null` as value.
*
* @param array<string, string|int|float|null> $attr
*/
public static function action(string $action, string $target, string $html, array $attr = []): string
{
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.');
}

$attrString = '';
foreach ($attr as $key => $value) {
$key = htmlspecialchars($key);
if (null === $value) {
$attrString .= \sprintf(' %s', $key);
} elseif (\is_int($value) || \is_float($value)) {
$attrString .= \sprintf(' %s="%s"', $key, $value);
} else {
$attrString .= \sprintf(' %s="%s"', $key, htmlspecialchars($value));
}
}

return self::wrap(htmlspecialchars($action), $target, $html, $attrString);
}

private static function wrap(string $action, string $target, string $html, string $attr = ''): string
{
return \sprintf(<<<EOHTML
Expand Down
12 changes: 12 additions & 0 deletions src/Turbo/src/TurboStreamResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,16 @@ public function refresh(?string $requestId = null): static

return $this;
}

/**
* @param array<string, string|int|float|null> $attr
*
* @return $this
*/
public function action(string $action, string $target, string $html, array $attr = []): static
{
$this->setContent($this->getContent().TurboStream::action($action, $target, $html, $attr));

return $this;
}
}
28 changes: 28 additions & 0 deletions src/Turbo/tests/Helper/TurboStreamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,32 @@ public function testRefreshWithId(): void
TurboStream::refresh('a"b')
);
}

public function testCustom(): void
{
$this->assertSame(<<<EOHTML
<turbo-stream action="customAction" targets="some[&quot;selector&quot;]" someAttr="someValue" boolAttr intAttr="0" floatAttr="3.14">
<template><div>content</div></template>
</turbo-stream>
EOHTML,
TurboStream::action('customAction', 'some["selector"]', '<div>content</div>', ['someAttr' => 'someValue', 'boolAttr' => null, 'intAttr' => 0, 'floatAttr' => 3.14])
);
}

/**
* @dataProvider customThrowsExceptionDataProvider
*
* @param array<string, string|int|float|null> $attr
*/
public function testCustomThrowsException(string $action, string $target, string $html, array $attr): void
{
$this->expectException(\InvalidArgumentException::class);
TurboStream::action($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 8c46bf3

Please sign in to comment.