Skip to content

Commit 53b99fb

Browse files
committed
feature #387 [Turbo] Make the Broadcast attribute repeatable (dunglas)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- [Turbo] Make the Broadcast attribute repeatable | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes <!-- please update src/**/CHANGELOG.md files --> | Tickets | n/a | License | MIT Allow the `Broadcast` attribute to be used many times. This is convenient to update different pages (ex: the list and the detail page) containing the same data but rendered differently. Ex: ```php #[Broadcast(topics: '@="product-detail-" ~ entity.id', template: 'product-detail.stream.html.twig'] #[Broadcast(topics: '@="product-list-" ~ entity.id', template: 'product-list.stream.html.twig'] class Product { public string $id; } ``` Commits ------- 298229e [Turbo] Make the Broadcast attribute repeatable
2 parents 1a617b5 + 298229e commit 53b99fb

File tree

5 files changed

+39
-16
lines changed

5 files changed

+39
-16
lines changed

src/Turbo/Attribute/Broadcast.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*
2424
* @experimental
2525
*/
26-
#[\Attribute(\Attribute::TARGET_CLASS)]
26+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
2727
final class Broadcast
2828
{
2929
public const ACTION_CREATE = 'create';

src/Turbo/CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
## 2.2
44

5-
- The topics defined in the Broadcast attribute now support expression language when prefixed with `@=`.
5+
- The topics defined in the `Broadcast` attribute now support expression language when prefixed with `@=`.
6+
- The `Broadcast` attribute can now be repeated, this is convenient to render several Turbo Streams Twig templates for the same change
67

78
## 2.1
89

src/Turbo/Doctrine/BroadcastListener.php

+28-12
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ final class BroadcastListener implements ResetInterface
3333
private $annotationReader;
3434

3535
/**
36-
* @var array<class-string, mixed[]|false>
36+
* @var array<class-string, array[]>
3737
*/
3838
private $broadcastedClasses;
3939

@@ -96,16 +96,23 @@ public function postFlush(EventArgs $eventArgs): void
9696
try {
9797
foreach ($this->createdEntities as $entity) {
9898
$options = $this->createdEntities[$entity];
99-
$options['id'] = $em->getClassMetadata(\get_class($entity))->getIdentifierValues($entity);
100-
$this->broadcaster->broadcast($entity, Broadcast::ACTION_CREATE, $options);
99+
$id = $em->getClassMetadata(\get_class($entity))->getIdentifierValues($entity);
100+
foreach ($options as $option) {
101+
$option['id'] = $id;
102+
$this->broadcaster->broadcast($entity, Broadcast::ACTION_CREATE, $option);
103+
}
101104
}
102105

103106
foreach ($this->updatedEntities as $entity) {
104-
$this->broadcaster->broadcast($entity, Broadcast::ACTION_UPDATE, $this->updatedEntities[$entity]);
107+
foreach ($this->updatedEntities[$entity] as $option) {
108+
$this->broadcaster->broadcast($entity, Broadcast::ACTION_UPDATE, $option);
109+
}
105110
}
106111

107112
foreach ($this->removedEntities as $entity) {
108-
$this->broadcaster->broadcast($entity, Broadcast::ACTION_REMOVE, $this->removedEntities[$entity]);
113+
foreach ($this->removedEntities[$entity] as $option) {
114+
$this->broadcaster->broadcast($entity, Broadcast::ACTION_REMOVE, $option);
115+
}
109116
}
110117
} finally {
111118
$this->reset();
@@ -124,21 +131,30 @@ private function storeEntitiesToPublish(EntityManagerInterface $em, object $enti
124131
$class = \get_class($entity);
125132

126133
if (!isset($this->broadcastedClasses[$class])) {
127-
$this->broadcastedClasses[$class] = false;
134+
$this->broadcastedClasses[$class] = [];
128135
$r = null;
129136

130137
if (\PHP_VERSION_ID >= 80000 && $options = ($r = new \ReflectionClass($class))->getAttributes(Broadcast::class)) {
131-
$options = $options[0]->newInstance();
132-
$this->broadcastedClasses[$class] = $options->options;
133-
} elseif ($this->annotationReader && $options = $this->annotationReader->getClassAnnotation($r ?? new \ReflectionClass($class), Broadcast::class)) {
134-
$this->broadcastedClasses[$class] = $options->options;
138+
foreach ($options as $option) {
139+
$this->broadcastedClasses[$class][] = $option->newInstance()->options;
140+
}
141+
} elseif ($this->annotationReader && $options = $this->annotationReader->getClassAnnotations($r ?? new \ReflectionClass($class))) {
142+
foreach ($options as $option) {
143+
if ($option instanceof Broadcast) {
144+
$this->broadcastedClasses[$class][] = $option->options;
145+
}
146+
}
135147
}
136148
}
137149

138-
if (false !== $options = $this->broadcastedClasses[$class]) {
150+
if ($options = $this->broadcastedClasses[$class]) {
139151
if ('createdEntities' !== $property) {
140-
$options['id'] = $em->getClassMetadata($class)->getIdentifierValues($entity);
152+
$id = $em->getClassMetadata($class)->getIdentifierValues($entity);
153+
foreach ($options as $k => $option) {
154+
$options[$k]['id'] = $id;
155+
}
141156
}
157+
142158
$this->{$property}->attach($entity, $options);
143159
}
144160
}

src/Turbo/Resources/doc/index.rst

+7-1
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,11 @@ The ``Broadcast`` attribute comes with a set of handy options:
620620
is derived from the FQCN of the entity and from its id
621621
- ``template`` (``string``): Twig template to render (see above)
622622

623+
The ``Broadcast`` attribute can be repeated. This is convenient to
624+
to render several templates associated with their own topics for the
625+
same change (e.g. the same data is rendered in different way in the
626+
list and in the detail pages).
627+
623628
Options are transport-specific. When using Mercure, some extra options
624629
are supported:
625630

@@ -638,7 +643,8 @@ Example::
638643

639644
use Symfony\UX\Turbo\Attribute\Broadcast;
640645

641-
#[Broadcast(topics: ['@="books_by_author_" ~ entity.author?.id', 'books'], template: 'foo.stream.html.twig', private: true)]
646+
#[Broadcast(topics: ['@="book_detail" ~ entity.id', 'books'], template: 'book_detail.stream.html.twig', private: true)]
647+
#[Broadcast(topics: ['@="book_list" ~ entity.id', 'books'], template: 'book_list.stream.html.twig', private: true)]
642648
class Book
643649
{
644650
// ...

src/Turbo/Tests/app/Entity/Song.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class Song
4040
public $title = '';
4141

4242
/**
43-
* @ORM\ManyToOne(targetEntity="App\Entity\Artist", inversedBy="songs")
43+
* @ORM\ManyToOne(targetEntity=Artist::class, inversedBy="songs")
4444
*
4545
* @var Artist|null
4646
*/

0 commit comments

Comments
 (0)