Skip to content

Commit 8067164

Browse files
committed
[Turbo] Add support for providing multiple mercure topics to turbo_stream_listen
1 parent 3ea19c1 commit 8067164

7 files changed

+49
-16
lines changed

src/Turbo/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Add `<twig:Turbo:Stream>` component
66
- Add `<twig:Turbo:Frame>` component
77
- Add support for custom actions in `TurboStream` and `TurboStreamResponse`
8+
- Add support for providing multiple mercure topics to `turbo_stream_listen`
89

910
## 2.21.0
1011

src/Turbo/assets/dist/turbo_stream_controller.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ import { Controller } from '@hotwired/stimulus';
22
export default class extends Controller {
33
static values: {
44
topic: StringConstructor;
5+
topics: ArrayConstructor;
56
hub: StringConstructor;
67
};
78
es: EventSource | undefined;
89
url: string | undefined;
910
readonly topicValue: string;
11+
readonly topicsValue: string[];
1012
readonly hubValue: string;
1113
readonly hasHubValue: boolean;
1214
readonly hasTopicValue: boolean;
15+
readonly hasTopicsValue: boolean;
1316
initialize(): void;
1417
connect(): void;
1518
disconnect(): void;

src/Turbo/assets/dist/turbo_stream_controller.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@ class default_1 extends Controller {
66
const errorMessages = [];
77
if (!this.hasHubValue)
88
errorMessages.push('A "hub" value pointing to the Mercure hub must be provided.');
9-
if (!this.hasTopicValue)
10-
errorMessages.push('A "topic" value must be provided.');
9+
if (!this.hasTopicValue && !this.hasTopicsValue)
10+
errorMessages.push('Either "topic" or "topics" value must be provided.');
1111
if (errorMessages.length)
1212
throw new Error(errorMessages.join(' '));
1313
const u = new URL(this.hubValue);
14-
u.searchParams.append('topic', this.topicValue);
14+
if (this.hasTopicValue) {
15+
u.searchParams.append('topic', this.topicValue);
16+
}
17+
else {
18+
this.topicsValue.forEach((topic) => {
19+
u.searchParams.append('topic', topic);
20+
});
21+
}
1522
this.url = u.toString();
1623
}
1724
connect() {
@@ -29,6 +36,7 @@ class default_1 extends Controller {
2936
}
3037
default_1.values = {
3138
topic: String,
39+
topics: Array,
3240
hub: String,
3341
};
3442

src/Turbo/assets/src/turbo_stream_controller.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,34 @@ import { connectStreamSource, disconnectStreamSource } from '@hotwired/turbo';
1616
export default class extends Controller {
1717
static values = {
1818
topic: String,
19+
topics: Array,
1920
hub: String,
2021
};
2122
es: EventSource | undefined;
2223
url: string | undefined;
2324

2425
declare readonly topicValue: string;
26+
declare readonly topicsValue: string[];
2527
declare readonly hubValue: string;
2628
declare readonly hasHubValue: boolean;
2729
declare readonly hasTopicValue: boolean;
30+
declare readonly hasTopicsValue: boolean;
2831

2932
initialize() {
3033
const errorMessages: string[] = [];
3134
if (!this.hasHubValue) errorMessages.push('A "hub" value pointing to the Mercure hub must be provided.');
32-
if (!this.hasTopicValue) errorMessages.push('A "topic" value must be provided.');
35+
if (!this.hasTopicValue && !this.hasTopicsValue)
36+
errorMessages.push('Either "topic" or "topics" value must be provided.');
3337
if (errorMessages.length) throw new Error(errorMessages.join(' '));
3438

3539
const u = new URL(this.hubValue);
36-
u.searchParams.append('topic', this.topicValue);
40+
if (this.hasTopicValue) {
41+
u.searchParams.append('topic', this.topicValue);
42+
} else {
43+
this.topicsValue.forEach((topic) => {
44+
u.searchParams.append('topic', topic);
45+
});
46+
}
3747

3848
this.url = u.toString();
3949
}

src/Turbo/src/Bridge/Mercure/TurboStreamListenRenderer.php

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,34 @@ public function __construct(
4444

4545
public function renderTurboStreamListen(Environment $env, $topic): string
4646
{
47-
if (\is_object($topic)) {
48-
$class = $topic::class;
47+
$topics = [];
4948

50-
if (!$id = $this->idAccessor->getEntityId($topic)) {
51-
throw new \LogicException(\sprintf('Cannot listen to entity of class "%s" as the PropertyAccess component is not installed. Try running "composer require symfony/property-access".', $class));
49+
foreach ((array) $topic as $topicVal) {
50+
if (\is_object($topicVal)) {
51+
$class = $topicVal::class;
52+
53+
if (!$id = $this->idAccessor->getEntityId($topicVal)) {
54+
throw new \LogicException(\sprintf('Cannot listen to entity of class "%s" as the PropertyAccess component is not installed. Try running "composer require symfony/property-access".', $class));
55+
}
56+
57+
$topics[] = \sprintf(Broadcaster::TOPIC_PATTERN, rawurlencode($class), rawurlencode(implode('-', $id)));
58+
} elseif (!preg_match('/[^a-zA-Z0-9_\x7f-\xff\\\\]/', $topic) && class_exists($topicVal)) {
59+
// Generate a URI template to subscribe to updates for all objects of this class
60+
$topics[] = \sprintf(Broadcaster::TOPIC_PATTERN, rawurlencode($topicVal), '{id}');
5261
}
62+
}
5363

54-
$topic = \sprintf(Broadcaster::TOPIC_PATTERN, rawurlencode($class), rawurlencode(implode('-', $id)));
55-
} elseif (!preg_match('/[^a-zA-Z0-9_\x7f-\xff\\\\]/', $topic) && class_exists($topic)) {
56-
// Generate a URI template to subscribe to updates for all objects of this class
57-
$topic = \sprintf(Broadcaster::TOPIC_PATTERN, rawurlencode($topic), '{id}');
64+
$controllerAttributes = ['hub' => $this->hub->getPublicUrl()];
65+
if (1 < \count($topics)) {
66+
$controllerAttributes['topics'] = $topics;
67+
} else {
68+
$controllerAttributes['topic'] = current($topics);
5869
}
5970

6071
$stimulusAttributes = $this->stimulusHelper->createStimulusAttributes();
6172
$stimulusAttributes->addController(
6273
'symfony/ux-turbo/mercure-turbo-stream',
63-
['topic' => $topic, 'hub' => $this->hub->getPublicUrl()]
74+
$controllerAttributes,
6475
);
6576

6677
return (string) $stimulusAttributes;

src/Turbo/src/Twig/TurboStreamListenRendererInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
interface TurboStreamListenRendererInterface
2222
{
2323
/**
24-
* @param string|object $topic
24+
* @param string|object|array<string> $topic
2525
*/
2626
public function renderTurboStreamListen(Environment $env, $topic): string;
2727
}

src/Turbo/src/Twig/TwigExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function getFunctions(): array
3535
}
3636

3737
/**
38-
* @param object|string $topic
38+
* @param object|string|array<string> $topic
3939
*/
4040
public function turboStreamListen(Environment $env, $topic, ?string $transport = null): string
4141
{

0 commit comments

Comments
 (0)