Skip to content

[Turbo] add options to EventSource Mercure #1774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -3,11 +3,13 @@ export default class extends Controller {
static values: {
topic: StringConstructor;
hub: StringConstructor;
eventSourceOptions: ObjectConstructor;
};
es: EventSource | undefined;
url: string | undefined;
readonly topicValue: string;
readonly hubValue: string;
readonly eventSourceOptionsValue: object;
readonly hasHubValue: boolean;
readonly hasTopicValue: boolean;
initialize(): void;
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 @@ -16,7 +16,7 @@ class default_1 extends Controller {
}
connect() {
if (this.url) {
this.es = new EventSource(this.url);
this.es = new EventSource(this.url, this.eventSourceOptionsValue);
connectStreamSource(this.es);
}
}
Expand All @@ -30,6 +30,7 @@ class default_1 extends Controller {
default_1.values = {
topic: String,
hub: String,
eventSourceOptions: Object,
};

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 @@ -17,12 +17,14 @@ export default class extends Controller {
static values = {
topic: String,
hub: String,
eventSourceOptions: Object,
};
es: EventSource | undefined;
url: string | undefined;

declare readonly topicValue: string;
declare readonly hubValue: string;
declare readonly eventSourceOptionsValue: object;
declare readonly hasHubValue: boolean;
declare readonly hasTopicValue: boolean;

Expand All @@ -40,7 +42,7 @@ export default class extends Controller {

connect() {
if (this.url) {
this.es = new EventSource(this.url);
this.es = new EventSource(this.url, this.eventSourceOptionsValue);
connectStreamSource(this.es);
}
}
Expand Down
16 changes: 11 additions & 5 deletions src/Turbo/src/Bridge/Mercure/TurboStreamListenRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ public function __construct(HubInterface $hub, StimulusHelper|StimulusTwigExtens
$this->stimulusHelper = $stimulus;
}

public function renderTurboStreamListen(Environment $env, $topic): string
/**
* @param string|object $topic
* @param array<string,mixed> $eventSourceOptions
*/
public function renderTurboStreamListen(Environment $env, $topic, array $eventSourceOptions = []): string
{
if (\is_object($topic)) {
$class = $topic::class;
Expand All @@ -61,11 +65,13 @@ public function renderTurboStreamListen(Environment $env, $topic): string
$topic = sprintf(Broadcaster::TOPIC_PATTERN, rawurlencode($topic), '{id}');
}

$params = ['topic' => $topic, 'hub' => $this->hub->getPublicUrl()];
if ($eventSourceOptions) {
$params['eventSourceOptions'] = $eventSourceOptions;
}

$stimulusAttributes = $this->stimulusHelper->createStimulusAttributes();
$stimulusAttributes->addController(
'symfony/ux-turbo/mercure-turbo-stream',
['topic' => $topic, 'hub' => $this->hub->getPublicUrl()]
);
$stimulusAttributes->addController('symfony/ux-turbo/mercure-turbo-stream', $params);

return (string) $stimulusAttributes;
}
Expand Down
5 changes: 3 additions & 2 deletions src/Turbo/src/Twig/TurboStreamListenRendererInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
interface TurboStreamListenRendererInterface
{
/**
* @param string|object $topic
* @param string|object $topic
* @param array<string,mixed> $eventSourceOptions
*/
public function renderTurboStreamListen(Environment $env, $topic): string;
public function renderTurboStreamListen(Environment $env, $topic, array $eventSourceOptions = []): string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot add parameter on an interface, even with default values, without breaking existing implementation.

interface FooInterface
{
    public function bar(string $a, array $eventSourceOptions = []): string;
}

class AppFoo implements FooInterface
{
    // existing method matching previous interface
    public function bar(string $a): string
    {
        return $a;
    }
}

This throws a PHP Fatal error as a the concrete implementation is not compatible anymore (see here).

Fatal error: Declaration of AppFoo::bar(string $a): string must be compatible with FooInterface::bar(string $a, array $eventSourceOptions = []): string in php-wasm run script on line 11

So to make this change in a BC way, you need:

  • to comment the new argument in the interface
  • to use func_get_args to fetch the value in the concrete class

You can see here a recent example of Symfony PR with similar BC layer: symfony/symfony#54531

Poke me if you need a hand here!

}
7 changes: 4 additions & 3 deletions src/Turbo/src/Twig/TwigExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,17 @@ public function getFunctions(): iterable
}

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

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

return $this->turboStreamListenRenderers->get($transport)->renderTurboStreamListen($env, $topic);
return $this->turboStreamListenRenderers->get($transport)->renderTurboStreamListen($env, $topic, $eventSourceOptions);
}
}
Loading