@@ -17,12 +17,12 @@ requiring "push" capabilities.
1717Symfony provides a straightforward component, built on top of
1818`the Mercure protocol `_, specifically designed for this class of use cases.
1919
20- Mercure is an open protocol designed from the ground to publish updates from
20+ Mercure is an open protocol designed from the ground up to publish updates from
2121server to clients. It is a modern and efficient alternative to timer-based
2222polling and to WebSocket.
2323
2424Because it is built on top `Server-Sent Events (SSE) `_, Mercure is supported
25- out of the box in most modern browsers (old versions of Edge and IE require
25+ out of the box in modern browsers (old versions of Edge and IE require
2626`a polyfill `_) and has `high-level implementations `_ in many programming
2727languages.
2828
@@ -42,49 +42,44 @@ generated using the API Platform client generator.
4242Installation
4343------------
4444
45- Running a Mercure Hub
46- ~~~~~~~~~~~~~~~~~~~~~
45+ Installing the Symfony Bundle
46+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47+
48+ Run this command to install the Mercure support:
49+
50+ .. code-block :: terminal
51+
52+ $ composer require mercure
4753
4854 To manage persistent connections, Mercure relies on a Hub: a dedicated server
4955that handles persistent SSE connections with the clients.
5056The Symfony app publishes the updates to the hub, that will broadcast them to
5157clients.
5258
53- .. image :: /_images/mercure/schema.png
54-
55- An official and open source (AGPL) Hub based on the Caddy web server
56- can be downloaded as a static binary from `Mercure.rocks `_.
57- A Docker image, a Helm chart for Kubernetes
58- and a managed, High Availability Hub are also provided.
59-
60- If you use `Symfony Docker `_ or the `API Platform distribution `_, a Mercure Hub
61- is automatically installed and your Symfony application is automatically
62- configured to use it. You can jump directly to the next section.
59+ Thanks to :ref: `the Docker integration of Symfony </setup/docker >`,
60+ :ref: `Flex <symfony-flex >` proposes to install a Mercure hub.
61+ Run ``docker-compose up `` to start the hub if you have chosen this option.
6362
6463If you use the :doc: `Symfony Local Web Server </setup/symfony_server >`,
65- a Mercure hub will be automatically available as a Docker service thanks to its
66- :ref: `Docker integration <symfony-server-docker>.
67-
68- Be sure that recent versions of Docker and Docker Compose are properly installed
69- on your computer and to start the Symfony Local Web Server with the ``--no-tls``
70- option:
64+ you must start it with the ``--no-tls `` option.
7165
7266.. code-block :: terminal
7367
7468 $ symfony server:start --no-tls -d
7569
76- Installing the Symfony Bundle
77- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78-
79- Run this command to install the Mercure support before using it:
70+ Running a Mercure Hub
71+ ~~~~~~~~~~~~~~~~~~~~~
8072
81- .. code-block :: terminal
73+ .. image :: /_images/mercure/schema.png
8274
83- $ composer require mercure
75+ If you use the Docker integration, a hub is already up and running,
76+ and you can go straight to the next section.
8477
85- :ref: `Symfony Flex <symfony-flex >` has automatically installed and configured
86- MercureBundle. It also created (if needed) and configured a Docker Compose
87- definition that provides a Mercure service. Run ``docker-compose up `` to start it.
78+ Otherwise, and in production, you have to install a hub by yourself.
79+ An official and open source (AGPL) Hub based on the Caddy web server
80+ can be downloaded as a static binary from `Mercure.rocks `_.
81+ A Docker image, a Helm chart for Kubernetes
82+ and a managed, High Availability Hub are also provided.
8883
8984Configuration
9085-------------
@@ -95,57 +90,37 @@ The preferred way to configure MercureBundle is using
9590When MercureBundle has been installed, the ``.env `` file of your project
9691has been updated by the Flex recipe to include the available env vars.
9792
98- If you use the Symfony Local Web Server, Symfony Docker or the API Platform
99- distribution, the Symfony app is automatically configured and you can skip
100- straight to the next section.
93+ Also, if you are using the Docker integration with the Symfony Local Web Server,
94+ `Symfony Docker `_ or the `API Platform distribution `_,
95+ the proper environment variables have been automatically set.
96+ Skip straight to the next section.
10197
10298Otherwise, set the URL of your hub as the value of the ``MERCURE_URL ``
10399and ``MERCURE_PUBLIC_URL `` env vars.
104100Sometimes a different URL must be called by the Symfony app (usually to publish),
105101and the JavaScript client (usually to subscribe). It's especially common when
106102the Symfony app must use a local URL and the client-side JavaScript code a public one.
107- In this case, ``MERCURE_URL `` must contain the local URL that will be used by the
103+ In this case, ``MERCURE_URL `` must contain the local URL used by the
108104Symfony app (e.g. ``https://mercure/.well-known/mercure ``), and ``MERCURE_PUBLIC_URL ``
109105the publicly available URL (e.g. ``https://example.com/.well-known/mercure ``).
110106
111107The clients must also bear a `JSON Web Token `_ (JWT)
112108to the Mercure Hub to be authorized to publish updates and, sometimes, to subscribe.
113109
114- This JWT should be stored in the ``MERCURE_JWT_SECRET `` environment variable.
110+ This token must be signed with the same secret key as the one used by the Hub to verify the JWT (``!ChangeMe! `` in you use the Docker integration).
111+ This secret key must be stored in the ``MERCURE_JWT_SECRET `` environment variable.
112+ MercureBundle will use it to automatically generate and sign the needed JWTs.
115113
116- The JWT must be signed with the same secret key as the one used by
117- the Hub to verify the JWT (``!ChangeMe! `` in you use the Local Web Server or
118- Symfony Docker).
119- Its payload must contain at least the following structure to be allowed to
120- publish:
114+ In addition to these environment variables,
115+ MercureBundle provides a more advanced configuration configuration:
121116
122- .. code-block :: json
123-
124- {
125- "mercure" : {
126- "publish" : []
127- }
128- }
129-
130- Because the array is empty, the Symfony app will only be authorized to publish
131- public updates (see the authorization _ section for further information).
132-
133- .. tip ::
134-
135- The jwt.io website is a convenient way to create and sign JWTs.
136- Checkout this `example JWT `_, that grants publishing rights for all *topics *
137- (notice the star in the array).
138- Don't forget to set your secret key properly in the bottom of the right panel of the form!
139-
140- .. caution ::
141-
142- Don't put the secret key in ``MERCURE_JWT_SECRET ``, it will not work!
143- This environment variable must contain a JWT, signed with the secret key.
144-
145- Also, be sure to keep both the secret key and the JWTs... secrets!
146-
147- If you don't want to use the provided environment variables,
148- use the following configuration:
117+ * ``secret ``: the key to use to sign the JWT (all other options, beside `algorithm `, `subscribe `, and `publish ` will be ignored)
118+ * ``publish ``: a list of topics to allow publishing to when generating the JWT (only usable when `secret `, or `factory ` are provided)
119+ * ``subscribe ``: a list of topics to allow subscribing to when generating the JWT (only usable when `secret `, or `factory ` are provided)
120+ * ``algorithm ``: The algorithm to use to sign the JWT (only usable when `secret ` is provided)
121+ * ``provider ``: The ID of a service to call to provide the JWT (all other options will be ignored)
122+ * ``factory ``: The ID of a service to call to create the JWT (all other options, beside `subscribe `, and `publish ` will be ignored)
123+ * ``value ``: the raw JWT to use (all other options will be ignored)
149124
150125.. configuration-block ::
151126
@@ -158,6 +133,12 @@ use the following configuration:
158133 url : https://mercure-hub.example.com/.well-known/mercure
159134 jwt :
160135 secret : ' !ChangeMe!'
136+ publish : ['foo', 'https://example.com/foo']
137+ subscribe : ['bar', 'https://example.com/bar']
138+ algorithm : ' hmac.sha256'
139+ provider : ' My\Provider'
140+ factory : ' My\Factory'
141+ value : ' my.jwt'
161142
162143 .. code-block :: xml
163144
@@ -168,7 +149,18 @@ use the following configuration:
168149 name =" default"
169150 url =" https://mercure-hub.example.com/.well-known/mercure"
170151 >
171- <jwt secret =" !ChangeMe!" />
152+ <jwt
153+ secret =" !ChangeMe!"
154+ algorithm =" hmac.sha256"
155+ provider =" My\Provider"
156+ factory =" My\Factory"
157+ value =" my.jwt"
158+ >
159+ <publish >foo</publish >
160+ <publish >https://example.com/foo</publish >
161+ <subscribe >bar</subscribe >
162+ <subscribe >https://example.com/bar</subscribe >
163+ </jwt >
172164 </hub >
173165 </config >
174166
@@ -181,11 +173,37 @@ use the following configuration:
181173 'url' => 'https://mercure-hub.example.com/.well-known/mercure',
182174 'jwt' => [
183175 'secret' => '!ChangeMe!',
176+ 'publish' => ['foo', 'https://example.com/foo'],
177+ 'subscribe' => ['bar', 'https://example.com/bar'],
178+ 'algorithm' => 'hmac.sha256',
179+ 'provider' => 'My\Provider',
180+ 'factory' => 'My\Factory',
181+ 'value' => 'my.jwt',
184182 ],
185183 ],
186184 ],
187185 ]);
188186
187+ .. tip ::
188+
189+ The JWT payload must contain at least the following structure to be allowed to
190+ publish:
191+
192+ .. code-block :: json
193+
194+ {
195+ "mercure" : {
196+ "publish" : []
197+ }
198+ }
199+
200+ Because the array is empty, the Symfony app will only be authorized to publish
201+ public updates (see the authorization _ section for further information).
202+
203+ The jwt.io website is a convenient way to create and sign JWTs.
204+ Checkout this `example JWT `_, that grants publishing rights for all *topics *
205+ (notice the star in the array).
206+ Don't forget to set your secret key properly in the bottom of the right panel of the form!
189207
190208Basic Usage
191209-----------
@@ -253,8 +271,8 @@ Subscribing to updates in JavaScript from a Twig template is straightforward:
253271 }
254272 </script>
255273
256- The ``mercure() `` Twig function will generate the URL of the Mercure hub
257- according to the configuration. The URL will include the ``topic `` query
274+ The ``mercure() `` Twig function generates the URL of the Mercure hub
275+ according to the configuration. The URL includes the ``topic `` query
258276parameters corresponding to the topics passed as first argument.
259277
260278If you want to access to this URL from an external JavaScript file, generate the
@@ -333,9 +351,9 @@ by using the ``AbstractController::addLink`` helper method::
333351
334352 class DiscoverController extends AbstractController
335353 {
336- public function __invoke (Request $request, Discovery $discovery): JsonResponse
354+ public function discover (Request $request, Discovery $discovery): JsonResponse
337355 {
338- // Link: <http ://localhost:3000 /.well-known/mercure>; rel="mercure"
356+ // Link: <https ://hub.example.com /.well-known/mercure>; rel="mercure"
339357 $discovery->addLink($request);
340358
341359 return $this->json([
@@ -351,7 +369,7 @@ and to subscribe to it:
351369.. code-block :: javascript
352370
353371 // Fetch the original resource served by the Symfony web API
354- fetch (' /books/1' ) // Has Link: <http ://localhost:3000 /.well-known/mercure>; rel="mercure"
372+ fetch (' /books/1' ) // Has Link: <https ://hub.example.com /.well-known/mercure>; rel="mercure"
355373 .then (response => {
356374 // Extract the hub URL from the Link header
357375 const hubUrl = response .headers .get (' Link' ).match (/ <([^ >] + )>;\s + rel=(?:mercure| "[^ "] * mercure[^ "] * ")/ )[1 ];
@@ -404,9 +422,9 @@ To provide this JWT, the subscriber can use a cookie,
404422or a ``Authorization `` HTTP header.
405423
406424Cookies can be set automatically by Symfony by passing the appropriate options
407- to the ``mercure() `` Twig function. Cookies set by Symfony will be automatically
425+ to the ``mercure() `` Twig function. Cookies set by Symfony are automatically
408426passed by the browsers to the Mercure hub if the ``withCredentials `` attribute
409- of the ``EventSource `` class is set to ``true ``. Then, the Hub will verify the
427+ of the ``EventSource `` class is set to ``true ``. Then, the Hub verifies the
410428validity of the provided JWT, and extract the topic selectors from it.
411429
412430.. code-block :: twig
@@ -482,6 +500,14 @@ And here is the controller::
482500 }
483501 }
484502
503+
504+ .. tip ::
505+
506+ You cannot use the ``mercure() `` helper and the ``setCookie() ``
507+ method at the same time (it would set the cookie twice on a single request). Choose
508+ either one method or the other.
509+
510+
485511Programmatically Generating The JWT Used to Publish
486512---------------------------------------------------
487513
@@ -595,9 +621,9 @@ its Mercure support.
595621Testing
596622--------
597623
598- During unit testing there is no need to send updates to Mercure.
624+ During unit testing it's usually not needed to send updates to Mercure.
599625
600- You can instead make use of the `MockHub `::
626+ You can instead make use of the `MockHub ` class ::
601627
602628 // tests/FunctionalTest.php
603629 namespace App\Tests\Unit\Controller;
@@ -624,10 +650,10 @@ You can instead make use of the `MockHub`::
624650 }
625651 }
626652
627- During functional testing you can instead decorate the Hub::
653+ For functional testing, you can instead create a stub of the Hub::
628654
629- // tests/Functional/Fixtures /HubStub.php
630- namespace App\Tests\Functional\Fixtures ;
655+ // tests/Functional/Stub /HubStub.php
656+ namespace App\Tests\Functional\Stub ;
631657
632658 use Symfony\Component\Mercure\HubInterface;
633659 use Symfony\Component\Mercure\Update;
@@ -642,14 +668,17 @@ During functional testing you can instead decorate the Hub::
642668 // implement rest of HubInterface methods here
643669 }
644670
645- HubStub decorates the default hub service so no updates are actually
646- sent. Here is the HubStub implementation :
671+ Use `` HubStub `` to replace the default hub service so no updates are actually
672+ sent:
647673
648674.. code-block :: yaml
649675
650676 # config/services_test.yaml
651- App\Tests\Functional\Fixtures\HubStub :
652- decorates : mercure.hub.default
677+ mercure.hub.default :
678+ class : App\Tests\Functional\Stub\HubStub
679+
680+ As MercureBundle support multiple hubs, you may have to replace
681+ the other service definitions accordingly.
653682
654683.. tip ::
655684
0 commit comments