1313
1414use Symfony \Component \Mercure \HubInterface ;
1515use Symfony \Component \Mercure \Update ;
16- use Symfony \Component \PropertyAccess \PropertyAccess ;
17- use Symfony \Component \PropertyAccess \PropertyAccessorInterface ;
1816use Symfony \UX \Turbo \Attribute \Broadcast ;
1917use Symfony \UX \Turbo \Broadcaster \BroadcasterInterface ;
20- use Twig \Environment ;
2118
2219/**
2320 * Broadcasts updates rendered using Twig with Mercure.
2724 * * id (string[]) The (potentially composite) identifier of the broadcasted entity
2825 * * transports (string[]) The name of the transports to broadcast to
2926 * * topics (string[]) The topics to use; the default topic is derived from the FQCN of the entity and from its id
30- * * template (string) The Twig template to render when a new object is created, updated or removed
27+ * * rendered_action (string) The turbo-stream action rendered as HTML
3128 * * private (bool) Marks Mercure updates as private
3229 * * sse_id (string) ID field of the SSE
3330 * * sse_type (string) type field of the SSE
@@ -45,58 +42,38 @@ final class Broadcaster implements BroadcasterInterface
4542 public const TOPIC_PATTERN = 'https://symfony.com/ux-turbo/%s/%s ' ;
4643
4744 private $ name ;
48- private $ twig ;
4945 private $ hub ;
50- private $ propertyAccessor ;
51- private $ templatePrefixes ;
5246
53- private const OPTIONS = [
54- // Generic options
55- 'id ' ,
56- 'transports ' ,
57- // Twig options
58- 'template ' ,
59- // Mercure options
60- 'topics ' ,
61- 'private ' ,
62- 'sse_id ' ,
63- 'sse_type ' ,
64- 'sse_retry ' ,
65- ];
66-
67- /**
68- * @param array<string, string> $templatePrefixes
69- */
70- public function __construct (string $ name , Environment $ twig , HubInterface $ hub , array $ templatePrefixes = [], PropertyAccessorInterface $ propertyAccessor = null )
47+ public function __construct (string $ name , HubInterface $ hub )
7148 {
72- if (80000 > \PHP_VERSION_ID ) {
73- throw new \LogicException ('The broadcast feature requires PHP 8.0 or greater, you must either upgrade to PHP 8 or disable it. ' );
74- }
75-
7649 $ this ->name = $ name ;
77- $ this ->twig = $ twig ;
7850 $ this ->hub = $ hub ;
79- $ this ->templatePrefixes = $ templatePrefixes ;
80- $ this ->propertyAccessor = $ propertyAccessor ?? (class_exists (PropertyAccess::class) ? PropertyAccess::createPropertyAccessor () : null );
8151 }
8252
8353 /**
8454 * {@inheritdoc}
8555 */
8656 public function broadcast (object $ entity , string $ action , array $ options ): void
8757 {
88- $ options = $ this ->normalizeOptions ($ entity , $ action , $ options );
89-
90- if (isset ($ options ['transports ' ]) && !\in_array ($ this ->name , $ options ['transports ' ], true )) {
58+ if (isset ($ options ['transports ' ]) && !\in_array ($ this ->name , (array ) $ options ['transports ' ], true )) {
9159 return ;
9260 }
9361
94- // Will throw if the template or the block doesn't exist
95- $ data = $ this ->twig ->load ($ options ['template ' ])->renderBlock ($ action , ['entity ' => $ entity , 'action ' => $ action ] + $ options );
62+ $ entityClass = \get_class ($ entity );
63+
64+ if (!isset ($ options ['rendered_action ' ])) {
65+ throw new \InvalidArgumentException (sprintf ('Cannot broadcast entity of class "%s" as option "rendered_action" is missing. ' , $ entityClass ));
66+ }
67+
68+ if (!isset ($ options ['topic ' ]) && !isset ($ options ['id ' ])) {
69+ throw new \InvalidArgumentException (sprintf ('Cannot broadcast entity of class "%s": either option "topics" or "id" is missing, or the PropertyAccess component is not installed. Try running "composer require property-access". ' , $ entityClass ));
70+ }
71+
72+ $ options ['topics ' ] = (array ) ($ options ['topics ' ] ?? sprintf (self ::TOPIC_PATTERN , rawurlencode ($ entityClass ), rawurlencode (implode ('- ' , (array ) $ options ['id ' ]))));
9673
9774 $ update = new Update (
9875 $ options ['topics ' ],
99- $ data ,
76+ $ options [ ' rendered_action ' ] ,
10077 $ options ['private ' ] ?? false ,
10178 $ options ['sse_id ' ] ?? null ,
10279 $ options ['sse_type ' ] ?? null ,
@@ -105,49 +82,4 @@ public function broadcast(object $entity, string $action, array $options): void
10582
10683 $ this ->hub ->publish ($ update );
10784 }
108-
109- /**
110- * @param mixed[] $options
111- *
112- * @return mixed[]
113- */
114- private function normalizeOptions (object $ entity , string $ action , array $ options ): array
115- {
116- if (isset ($ options ['transports ' ])) {
117- $ options ['transports ' ] = (array ) $ options ['transports ' ];
118- }
119-
120- $ entityClass = \get_class ($ entity );
121-
122- if ($ extraKeys = array_diff (array_keys ($ options ), self ::OPTIONS )) {
123- throw new \InvalidArgumentException (sprintf ('Unknown broadcast options "%s" on class "%s". Valid options are: "%s" ' , implode ('", " ' , $ extraKeys ), $ entityClass , implode ('", " ' , self ::OPTIONS )));
124- }
125-
126- if (isset ($ options ['id ' ])) {
127- $ options ['id ' ] = \is_array ($ options ['id ' ]) ? implode ('- ' , $ options ['id ' ]) : $ options ['id ' ];
128- } elseif (!isset ($ options ['topics ' ])) {
129- if (!$ this ->propertyAccessor ) {
130- throw new \InvalidArgumentException (sprintf ('Cannot broadcast entity of class "%s": either option "topics" or "id" is missing, or the PropertyAccess component is not installed. Try running "composer require property-access". ' , $ entityClass ));
131- }
132-
133- $ options ['id ' ] = $ this ->propertyAccessor ->getValue ($ entity , 'id ' );
134- }
135-
136- $ options ['topics ' ] = (array ) ($ options ['topics ' ] ?? sprintf (self ::TOPIC_PATTERN , rawurlencode ($ entityClass ), rawurlencode ($ options ['id ' ])));
137- if (isset ($ options ['template ' ])) {
138- return $ options ;
139- }
140-
141- $ file = $ entityClass ;
142- foreach ($ this ->templatePrefixes as $ namespace => $ prefix ) {
143- if (0 === strpos ($ entityClass , $ namespace )) {
144- $ file = substr_replace ($ entityClass , $ prefix , 0 , \strlen ($ namespace ));
145- break ;
146- }
147- }
148-
149- $ options ['template ' ] = str_replace ('\\' , '/ ' , $ file ).'.stream.html.twig ' ;
150-
151- return $ options ;
152- }
15385}
0 commit comments