Skip to content

Commit 488e061

Browse files
committed
Custom action support
1 parent 01839ab commit 488e061

File tree

3 files changed

+75
-2
lines changed

3 files changed

+75
-2
lines changed

src/Turbo/src/Helper/TurboStream.php

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,45 @@ public static function refresh(?string $requestId = null): string
8686
return \sprintf('<turbo-stream action="refresh" request-id="%s"></turbo-stream>', htmlspecialchars($requestId));
8787
}
8888

89+
/**
90+
* Custom action and attributes.
91+
* When passing attributes use null value to for boolean attributes (e.g. disabled).
92+
*
93+
* @param array<string, string|int|float|null> $attr
94+
*/
95+
public static function action(string $action, string $target, string $html, array $attr = []): string
96+
{
97+
if (\array_key_exists('action', $attr) || \array_key_exists('targets', $attr)) {
98+
throw new \InvalidArgumentException('The "action" and "targets" attributes are reserved and cannot be used.');
99+
}
100+
101+
$attrString = '';
102+
foreach ($attr as $key => $value) {
103+
$key = htmlspecialchars($key);
104+
if (null === $value) {
105+
$attrString .= \sprintf(' %s', $key);
106+
} elseif (\is_int($value) || \is_float($value)) {
107+
$attrString .= \sprintf(' %s="%s"', $key, $value);
108+
} else {
109+
$attrString .= \sprintf(' %s="%s"', $key, htmlspecialchars($value));
110+
}
111+
}
112+
113+
return self::wrap(htmlspecialchars($action), $target, $html, $attrString);
114+
}
115+
89116
private static function wrap(string $action, string $target, string $html, string $attr = ''): string
90117
{
91-
return \sprintf(<<<EOHTML
118+
return \sprintf(
119+
<<<EOHTML
92120
<turbo-stream action="%s" targets="%s"%s>
93121
<template>%s</template>
94122
</turbo-stream>
95-
EOHTML, $action, htmlspecialchars($target), $attr, $html);
123+
EOHTML,
124+
$action,
125+
htmlspecialchars($target),
126+
$attr,
127+
$html
128+
);
96129
}
97130
}

src/Turbo/src/TurboStreamResponse.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,16 @@ public function refresh(?string $requestId = null): static
104104

105105
return $this;
106106
}
107+
108+
/**
109+
* @param array<string, string|int|float|null> $attr
110+
*
111+
* @return $this
112+
*/
113+
public function action(string $action, string $target, string $html, array $attr = []): static
114+
{
115+
$this->setContent($this->getContent().TurboStream::action($action, $target, $html, $attr));
116+
117+
return $this;
118+
}
107119
}

src/Turbo/tests/Helper/TurboStreamTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,32 @@ public function testRefreshWithId(): void
7676
TurboStream::refresh('a"b')
7777
);
7878
}
79+
80+
public function testCustom(): void
81+
{
82+
$this->assertSame(<<<EOHTML
83+
<turbo-stream action="customAction" targets="some[&quot;selector&quot;]" someAttr="someValue" boolAttr intAttr="0" floatAttr="3.14">
84+
<template><div>content</div></template>
85+
</turbo-stream>
86+
EOHTML,
87+
TurboStream::action('customAction', 'some["selector"]', '<div>content</div>', ['someAttr' => 'someValue', 'boolAttr' => null, 'intAttr' => 0, 'floatAttr' => 3.14])
88+
);
89+
}
90+
91+
/**
92+
* @dataProvider customThrowsExceptionDataProvider
93+
*
94+
* @param array<string, string|int|float|null> $attr
95+
*/
96+
public function testCustomThrowsException(string $action, string $target, string $html, array $attr): void
97+
{
98+
$this->expectException(\InvalidArgumentException::class);
99+
TurboStream::action($action, $target, $html, $attr);
100+
}
101+
102+
public static function customThrowsExceptionDataProvider(): \Generator
103+
{
104+
yield ['customAction', 'some["selector"]', '<div>content</div>', ['action' => 'someAction']];
105+
yield ['customAction', 'some["selector"]', '<div>content</div>', ['targets' => 'someTargets']];
106+
}
79107
}

0 commit comments

Comments
 (0)