Skip to content

Commit

Permalink
Add options to turbo stream
Browse files Browse the repository at this point in the history
  • Loading branch information
Fan2Shrek committed Dec 13, 2024
1 parent dec3eb3 commit abcc723
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 34 deletions.
4 changes: 4 additions & 0 deletions src/Turbo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 2.23.0

- Add support for providing options to the EventSource via `turbo_stream_listen`

## 2.22.0

- Add `<twig:Turbo:Stream>` component
Expand Down
2 changes: 2 additions & 0 deletions src/Turbo/assets/dist/turbo_stream_controller.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ export default class extends Controller {
topic: StringConstructor;
topics: ArrayConstructor;
hub: StringConstructor;
withCredentials: BooleanConstructor;
};
es: EventSource | undefined;
url: string | undefined;
readonly topicValue: string;
readonly topicsValue: string[];
readonly withCredentialsValue: boolean;
readonly hubValue: string;
readonly hasHubValue: boolean;
readonly hasTopicValue: boolean;
Expand Down
3 changes: 2 additions & 1 deletion src/Turbo/assets/dist/turbo_stream_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class default_1 extends Controller {
}
connect() {
if (this.url) {
this.es = new EventSource(this.url);
this.es = new EventSource(this.url, { withCredentials: this.withCredentialsValue });
connectStreamSource(this.es);
}
}
Expand All @@ -38,6 +38,7 @@ default_1.values = {
topic: String,
topics: Array,
hub: String,
withCredentials: Boolean,
};

export { default_1 as default };
4 changes: 3 additions & 1 deletion src/Turbo/assets/src/turbo_stream_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ export default class extends Controller {
topic: String,
topics: Array,
hub: String,
withCredentials: Boolean,
};
es: EventSource | undefined;
url: string | undefined;

declare readonly topicValue: string;
declare readonly topicsValue: string[];
declare readonly withCredentialsValue: boolean;
declare readonly hubValue: string;
declare readonly hasHubValue: boolean;
declare readonly hasTopicValue: boolean;
Expand All @@ -50,7 +52,7 @@ export default class extends Controller {

connect() {
if (this.url) {
this.es = new EventSource(this.url);
this.es = new EventSource(this.url, { withCredentials: this.withCredentialsValue });
connectStreamSource(this.es);
}
}
Expand Down
12 changes: 11 additions & 1 deletion src/Turbo/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Symfony\Component\Mercure\Authorization;
use Symfony\UX\Turbo\Twig\TurboRuntime;
use Symfony\UX\Turbo\Broadcaster\BroadcasterInterface;
use Symfony\UX\Turbo\Broadcaster\IdAccessor;
use Symfony\UX\Turbo\Broadcaster\ImuxBroadcaster;
Expand Down Expand Up @@ -45,9 +47,17 @@
->decorate('turbo.broadcaster.imux')

->set('turbo.twig.extension', TwigExtension::class)
->args([tagged_locator('turbo.renderer.stream_listen', 'transport'), abstract_arg('default')])
->tag('twig.extension')

->set('turbo.twig.runtime', TurboRuntime::class)
->args([
tagged_locator('turbo.renderer.stream_listen', 'transport'),
abstract_arg('default'),
service(Authorization::class)->nullOnInvalid(),
service('request_stack')->nullOnInvalid(),
])
->tag('twig.runtime')

->set('turbo.doctrine.event_listener', BroadcastListener::class)
->args([
service('turbo.broadcaster.imux'),
Expand Down
10 changes: 9 additions & 1 deletion src/Turbo/src/Bridge/Mercure/TurboStreamListenRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,12 @@ public function __construct(
$this->stimulusHelper = $stimulus;
}

public function renderTurboStreamListen(Environment $env, $topic): string
public function renderTurboStreamListen(Environment $env, $topic /* array $eventSourceOptions = [] */): string
{
if (\func_num_args() > 2) {
$eventSourceOptions = func_get_arg(2);
}

$topics = $topic instanceof TopicSet
? array_map($this->resolveTopic(...), $topic->getTopics())
: [$this->resolveTopic($topic)];
Expand All @@ -55,6 +59,10 @@ public function renderTurboStreamListen(Environment $env, $topic): string
$controllerAttributes['topic'] = current($topics);
}

if (isset($eventSourceOptions, $eventSourceOptions['withCredentials'])) {
$controllerAttributes['withCredentials'] = $eventSourceOptions['withCredentials'];
}

$stimulusAttributes = $this->stimulusHelper->createStimulusAttributes();
$stimulusAttributes->addController(
'symfony/ux-turbo/mercure-turbo-stream',
Expand Down
2 changes: 1 addition & 1 deletion src/Turbo/src/DependencyInjection/TurboExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function load(array $configs, ContainerBuilder $container): void

$loader = (new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/../config')));
$loader->load('services.php');
$container->getDefinition('turbo.twig.extension')->replaceArgument(1, $config['default_transport']);
$container->getDefinition('turbo.twig.runtime')->replaceArgument(1, $config['default_transport']);

$this->registerTwig($config, $container);
$this->registerBroadcast($config, $container, $loader);
Expand Down
71 changes: 71 additions & 0 deletions src/Turbo/src/Twig/TurboRuntime.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\Turbo\Twig;

use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Mercure\Authorization;
use Symfony\UX\Turbo\Bridge\Mercure\TopicSet;
use Twig\Extension\RuntimeExtensionInterface;
use Twig\Environment;

/**
* @author Pierre Ambroise <[email protected]>
*
* @internal
*/
class TurboRuntime implements RuntimeExtensionInterface
{
public function __construct(
private ContainerInterface $turboStreamListenRenderers,
private string $default,
private ?Authorization $authorization = null,
private ?RequestStack $requestStack = null,
) {
}

/**
* @param object|string|array<object|string> $topic
* @param array<string, mixed> $options
*/
public function renderTurboStreamListen(Environment $env, $topic, ?string $transport = null, array $options = []): string
{
$transport ??= $this->default;

if (!$this->turboStreamListenRenderers->has($transport)) {
throw new \InvalidArgumentException(\sprintf('The Turbo stream transport "%s" does not exist.', $transport));
}

if (\is_array($topic)) {
$topic = new TopicSet($topic);
}

if (
null !== $this->authorization
&& null !== $this->requestStack
&& (isset($options['subscribe']) || isset($options['publish']) || isset($options['additionalClaims']))
&& null !== $request = $this->requestStack->getMainRequest()
) {
$this->authorization->setCookie(
$request,
$options['subscribe'] ?? [],
$options['publish'] ?? [],
$options['additionalClaims'] ?? [],
$transport,
);

unset($options['subscribe'], $options['publish'], $options['additionalClaims']);
}

return $this->turboStreamListenRenderers->get($transport)->renderTurboStreamListen($env, $topic, $options);
}
}
2 changes: 1 addition & 1 deletion src/Turbo/src/Twig/TurboStreamListenRendererInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ interface TurboStreamListenRendererInterface
/**
* @param string|object $topic
*/
public function renderTurboStreamListen(Environment $env, $topic): string;
public function renderTurboStreamListen(Environment $env, $topic /* , array $eventSourceOptions = [] */): string;
}
31 changes: 3 additions & 28 deletions src/Turbo/src/Twig/TwigExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,20 @@

namespace Symfony\UX\Turbo\Twig;

use Psr\Container\ContainerInterface;
use Symfony\UX\Turbo\Bridge\Mercure\TopicSet;
use Twig\Environment;
use Symfony\UX\Turbo\Twig\TurboRuntime;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

/**
* @author Kévin Dunglas <[email protected]>
* @author Pierre Ambroise <[email protected]>
*/
final class TwigExtension extends AbstractExtension
{
public function __construct(
private ContainerInterface $turboStreamListenRenderers,
private string $default,
) {
}

public function getFunctions(): array
{
return [
new TwigFunction('turbo_stream_listen', $this->turboStreamListen(...), ['needs_environment' => true, 'is_safe' => ['html']]),
new TwigFunction('turbo_stream_listen', [TurboRuntime::class, 'renderTurboStreamListen'], ['needs_environment' => true, 'is_safe' => ['html']]),
];
}

/**
* @param object|string|array<object|string> $topic
*/
public function turboStreamListen(Environment $env, $topic, ?string $transport = null): string
{
$transport ??= $this->default;

if (!$this->turboStreamListenRenderers->has($transport)) {
throw new \InvalidArgumentException(\sprintf('The Turbo stream transport "%s" does not exist.', $transport));
}

if (\is_array($topic)) {
$topic = new TopicSet($topic);
}

return $this->turboStreamListenRenderers->get($transport)->renderTurboStreamListen($env, $topic);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,13 @@ public static function provideTestCases(): iterable
? 'data-controller="symfony--ux-turbo--mercure-turbo-stream" data-symfony--ux-turbo--mercure-turbo-stream-hub-value="http://127.0.0.1:3000/.well-known/mercure" data-symfony--ux-turbo--mercure-turbo-stream-topics-value="[&quot;a_topic&quot;,&quot;AppEntityBook&quot;,&quot;https:\/\/symfony.com\/ux-turbo\/App%5CEntity%5CBook\/123&quot;]"'
: 'data-controller="symfony--ux-turbo--mercure-turbo-stream" data-symfony--ux-turbo--mercure-turbo-stream-hub-value="http&#x3A;&#x2F;&#x2F;127.0.0.1&#x3A;3000&#x2F;.well-known&#x2F;mercure" data-symfony--ux-turbo--mercure-turbo-stream-topics-value="&#x5B;&quot;a_topic&quot;,&quot;AppEntityBook&quot;,&quot;https&#x3A;&#x5C;&#x2F;&#x5C;&#x2F;symfony.com&#x5C;&#x2F;ux-turbo&#x5C;&#x2F;App&#x25;5CEntity&#x25;5CBook&#x5C;&#x2F;123&quot;&#x5D;"',
];

yield [
"{{ turbo_stream_listen('a_topic', 'default', { withCredentials: true }) }}",
[],
$newEscape
? 'data-controller="symfony--ux-turbo--mercure-turbo-stream" data-symfony--ux-turbo--mercure-turbo-stream-hub-value="http://127.0.0.1:3000/.well-known/mercure" data-symfony--ux-turbo--mercure-turbo-stream-topic-value="a_topic" data-symfony--ux-turbo--mercure-turbo-stream-with-credentials-value="true"'
: 'data-controller="symfony--ux-turbo--mercure-turbo-stream" data-symfony--ux-turbo--mercure-turbo-stream-hub-value="http&#x3A;&#x2F;&#x2F;127.0.0.1&#x3A;3000&#x2F;.well-known&#x2F;mercure" data-symfony--ux-turbo--mercure-turbo-stream-topic-value="a_topic" data-symfony--ux-turbo--mercure-turbo-stream-with-credentials-value="true"',
];
}
}

0 comments on commit abcc723

Please sign in to comment.