Skip to content

Commit c4fab1b

Browse files
committed
Merge branch '5.2' into 5.3
* 5.2: Fix: Build [Mercure] integration with Symfony cli and various improvements
2 parents 08c643c + 6c14791 commit c4fab1b

File tree

2 files changed

+91
-78
lines changed

2 files changed

+91
-78
lines changed

.doctor-rst.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,4 @@ whitelist:
105105
- '// bin/console'
106106
- 'End to End Tests (E2E)'
107107
- '.. code-block:: php'
108+
- '.. _`a feature to test applications using Mercure`: https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket'

mercure.rst

+90-78
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ server to clients. It is a modern and efficient alternative to timer-based
2222
polling and to WebSocket.
2323

2424
Because it is built on top `Server-Sent Events (SSE)`_, Mercure is supported
25-
out of the box in most modern browsers (Edge and IE require `a polyfill`_) and
26-
has `high-level implementations`_ in many programming languages.
25+
out of the box in most modern browsers (old versions of Edge and IE require
26+
`a polyfill`_) and has `high-level implementations`_ in many programming
27+
languages.
2728

2829
Mercure comes with an authorization mechanism,
2930
automatic re-connection in case of network issues
@@ -65,34 +66,19 @@ clients.
6566

6667
.. image:: /_images/mercure/schema.png
6768

68-
An official and open source (AGPL) implementation of a Hub can be downloaded
69-
as a static binary from `Mercure.rocks`_.
69+
If you use the `Symfony Local Web Server </setup/symfony_server>`_ or `Symfony Docker`_,
70+
a Mercure Hub is automatically available.
7071

71-
If you use `Symfony Docker`_,
72-
a Mercure Hub is already included and you can skip straight to the next section.
73-
74-
On Linux and Mac, run the following command to start it:
75-
76-
.. rst-class:: command-linux
77-
78-
$ SERVER_NAME=:3000 MERCURE_PUBLISHER_JWT_KEY='!ChangeMe!' MERCURE_SUBSCRIBER_JWT_KEY='!ChangeMe!' ./mercure run -config Caddyfile.dev
79-
80-
On Windows run:
81-
82-
.. rst-class: command-windows
83-
84-
> $env:SERVER_NAME=':3000'; $env:MERCURE_PUBLISHER_JWT_KEY='!ChangeMe!'; $env:MERCURE_SUBSCRIBER_JWT_KEY='!ChangeMe!'; .\mercure.exe run -config Caddyfile.dev
85-
86-
.. note::
87-
88-
Alternatively to the binary, a Docker image, a Helm chart for Kubernetes
89-
and a managed, High Availability Hub are also provided by Mercure.rocks.
72+
For production usage, an official and open source (AGPL) Hub based on the Caddy web server
73+
can be downloaded as a static binary from `Mercure.rocks`_.
74+
Alternatively to the binary, a Docker image, a Helm chart for Kubernetes
75+
and a managed, High Availability Hub are also provided.
9076

9177
.. tip::
9278

9379
The `API Platform distribution`_ comes with a Docker Compose configuration
9480
as well as a Helm chart for Kubernetes that are 100% compatible with Symfony,
95-
and contain a Mercure hub.
81+
and contain a build of the Caddy web server including a Mercure hub.
9682
You can copy them in your project, even if you don't use API Platform.
9783

9884
Configuration
@@ -101,18 +87,30 @@ Configuration
10187
The preferred way to configure the MercureBundle is using
10288
:doc:`environment variables </configuration>`.
10389

104-
Set the URL of your hub as the value of the ``MERCURE_PUBLISH_URL`` env var.
105-
The ``.env`` file of your project has been updated by the Flex recipe to
106-
provide example values.
107-
Set it to the URL of the Mercure Hub (``http://localhost:3000/.well-known/mercure`` by default).
90+
When MercureBundle has been installed, the ``.env`` file of your project
91+
has been updated by the Flex recipe to include the available env vars.
92+
93+
If you use the Symfony Local Web Server or Symfony Docker,
94+
the default values are compatible with the provided Hub
95+
and you can skip straight to the next section.
10896

109-
In addition, the Symfony application must bear a `JSON Web Token`_ (JWT)
110-
to the Mercure Hub to be authorized to publish updates.
97+
Otherwise, set the URL of your hub as the value of the ``MERCURE_URL``
98+
and ``MERCURE_PUBLIC_URL`` env vars.
99+
Sometimes a different URL must be called by the Symfony app (usually to publish),
100+
and the JavaScript client (usually to subscrribe). It's especially common when
101+
the Symfony app must use a local URL and the client-side JavaScript code a public one.
102+
In this case, ``MERCURE_URL`` must contain the local URL that will be used by the
103+
Symfony app (e.g. ``https://mercure/.well-known/mercure``), and ``MERCURE_PUBLIC_URL``
104+
the publicly available URL (e.g. ``https://example.com/.well-known/mercure``).
111105

112-
This JWT should be stored in the ``MERCURE_JWT_TOKEN`` environment variable.
106+
The clients must also bear a `JSON Web Token`_ (JWT)
107+
to the Mercure Hub to be authorized to publish updates and, sometimes, to subscribe.
108+
109+
This JWT should be stored in the ``MERCURE_JWT_SECRET`` environment variable.
113110

114111
The JWT must be signed with the same secret key as the one used by
115-
the Hub to verify the JWT (``!ChangeMe!`` in our example).
112+
the Hub to verify the JWT (``!ChangeMe!`` in you use the Local Web Server or
113+
Symfony Docker).
116114
Its payload must contain at least the following structure to be allowed to
117115
publish:
118116

@@ -136,7 +134,7 @@ public updates (see the authorization_ section for further information).
136134

137135
.. caution::
138136

139-
Don't put the secret key in ``MERCURE_JWT_TOKEN``, it will not work!
137+
Don't put the secret key in ``MERCURE_JWT_SECRET``, it will not work!
140138
This environment variable must contain a JWT, signed with the secret key.
141139

142140
Also, be sure to keep both the secret key and the JWTs... secrets!
@@ -158,13 +156,14 @@ service, including controllers::
158156
// src/Controller/PublishController.php
159157
namespace App\Controller;
160158

159+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
161160
use Symfony\Component\HttpFoundation\Response;
162161
use Symfony\Component\Mercure\HubInterface;
163162
use Symfony\Component\Mercure\Update;
164163

165-
class PublishController
164+
class PublishController extends AbstractController
166165
{
167-
public function __invoke(HubInterface $hub): Response
166+
public function publish(HubInterface $hub): Response
168167
{
169168
$update = new Update(
170169
'http://example.com/books/1',
@@ -198,7 +197,7 @@ Subscribing to updates in JavaScript is straightforward:
198197

199198
.. code-block:: javascript
200199
201-
const eventSource = new EventSource('http://localhost:3000/.well-known/mercure?topic=' + encodeURIComponent('http://example.com/books/1'));
200+
const eventSource = new EventSource('/.well-known/mercure?topic=' + encodeURIComponent('http://example.com/books/1'));
202201
eventSource.onmessage = event => {
203202
// Will be called every time an update is published by the server
204203
console.log(JSON.parse(event.data));
@@ -211,7 +210,7 @@ as patterns:
211210
.. code-block:: javascript
212211
213212
// URL is a built-in JavaScript class to manipulate URLs
214-
const url = new URL('http://localhost:3000/.well-known/mercure');
213+
const url = new URL('/.well-known/mercure', window.origin);
215214
url.searchParams.append('topic', 'http://example.com/books/1');
216215
// Subscribe to updates of several Book resources
217216
url.searchParams.append('topic', 'http://example.com/books/2');
@@ -241,43 +240,6 @@ as patterns:
241240

242241
Test if a URI Template match a URL using `the online debugger`_
243242

244-
Async dispatching
245-
-----------------
246-
247-
Instead of calling the ``Publisher`` service directly, you can also let Symfony
248-
dispatching the updates asynchronously thanks to the provided integration with
249-
the Messenger component.
250-
251-
First, be sure :doc:`to install the Messenger component </messenger>`
252-
and to configure properly a transport (if you don't, the handler will
253-
be called synchronously).
254-
255-
Then, dispatch the Mercure ``Update`` to the Messenger's Message Bus,
256-
it will be handled automatically::
257-
258-
// src/Controller/PublishController.php
259-
namespace App\Controller;
260-
261-
use Symfony\Component\HttpFoundation\Response;
262-
use Symfony\Component\Mercure\Update;
263-
use Symfony\Component\Messenger\MessageBusInterface;
264-
265-
class PublishController
266-
{
267-
public function __invoke(MessageBusInterface $bus): Response
268-
{
269-
$update = new Update(
270-
'http://example.com/books/1',
271-
json_encode(['status' => 'OutOfStock'])
272-
);
273-
274-
// Sync, or async (RabbitMQ, Kafka...)
275-
$bus->dispatch($update);
276-
277-
return new Response('published!');
278-
}
279-
}
280-
281243
Discovery
282244
---------
283245

@@ -324,7 +286,7 @@ and to subscribe to it:
324286
const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1];
325287
326288
// Append the topic(s) to subscribe as query parameter
327-
const hub = new URL(hubUrl);
289+
const hub = new URL(hubUrl, window.origin);
328290
hub.searchParams.append('topic', 'http://example.com/books/{id}');
329291
330292
// Subscribe to updates
@@ -348,7 +310,7 @@ of the ``Update`` constructor to ``true``::
348310

349311
class PublishController extends AbstractController
350312
{
351-
public function __invoke(HubInterface $hub): Response
313+
public function publish(HubInterface $hub): Response
352314
{
353315
$update = new Update(
354316
'http://example.com/books/1',
@@ -457,7 +419,7 @@ And here is the controller::
457419

458420
class DiscoverController extends AbstractController
459421
{
460-
public function __invoke(Request $request, Discovery $discovery, Authorization $authorization): Response
422+
public function publish(Request $request, Discovery $discovery, Authorization $authorization): Response
461423
{
462424
$discovery->addLink($request);
463425

@@ -602,7 +564,7 @@ During unit testing there is not need to send updates to Mercure.
602564

603565
You can instead make use of the `MockHub`::
604566

605-
// tests/Functional/.php
567+
// tests/FunctionalTest.php
606568
namespace App\Tests\Unit\Controller;
607569

608570
use App\Controller\MessageController;
@@ -654,6 +616,10 @@ sent. Here is the HubStub implementation:
654616
App\Tests\Functional\Fixtures\HubStub:
655617
decorates: mercure.hub.default
656618
619+
.. tip::
620+
621+
Symfony Panther has `a feature to test applications using Mercure`_.
622+
657623
Debugging
658624
---------
659625

@@ -694,6 +660,51 @@ Enable the panel in your configuration, as follows:
694660
695661
.. image:: /_images/mercure/panel.png
696662

663+
Async dispatching
664+
-----------------
665+
666+
.. tip::
667+
668+
Async dispatching is discouraged. Most Mercure hubs already
669+
handle publications asynchronously and using Messenger is
670+
usually not necessary.
671+
672+
Instead of calling the ``Publisher`` service directly, you can also let Symfony
673+
dispatching the updates asynchronously thanks to the provided integration with
674+
the Messenger component.
675+
676+
First, be sure :doc:`to install the Messenger component </messenger>`
677+
and to configure properly a transport (if you don't, the handler will
678+
be called synchronously).
679+
680+
Then, dispatch the Mercure ``Update`` to the Messenger's Message Bus,
681+
it will be handled automatically::
682+
683+
// src/Controller/PublishController.php
684+
namespace App\Controller;
685+
686+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
687+
use Symfony\Component\HttpFoundation\Response;
688+
use Symfony\Component\Mercure\Update;
689+
use Symfony\Component\Messenger\MessageBusInterface;
690+
691+
class PublishController extends AbstractController
692+
{
693+
public function publish(MessageBusInterface $bus): Response
694+
{
695+
$update = new Update(
696+
'http://example.com/books/1',
697+
json_encode(['status' => 'OutOfStock'])
698+
);
699+
700+
// Sync, or async (Doctrine, RabbitMQ, Kafka...)
701+
$bus->dispatch($update);
702+
703+
return new Response('published!');
704+
}
705+
}
706+
707+
697708
.. _`the Mercure protocol`: https://mercure.rocks/spec
698709
.. _`Server-Sent Events (SSE)`: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
699710
.. _`a polyfill`: https://github.com/Yaffle/EventSource
@@ -708,3 +719,4 @@ Enable the panel in your configuration, as follows:
708719
.. _`practical UI`: https://twitter.com/ChromeDevTools/status/562324683194785792
709720
.. _`the dedicated API Platform documentation`: https://api-platform.com/docs/core/mercure/
710721
.. _`the online debugger`: https://uri-template-tester.mercure.rocks
722+
.. _`a feature to test applications using Mercure`: https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket

0 commit comments

Comments
 (0)