Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6c14791

Browse filesBrowse files
committed
Merge branch '4.4' into 5.2
* 4.4: Fix: Build [Mercure] integration with Symfony cli and various improvements
2 parents 62f10cd + 5b0869f commit 6c14791
Copy full SHA for 6c14791

File tree

Expand file treeCollapse file tree

2 files changed

+91
-78
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+91
-78
lines changed

‎.doctor-rst.yaml

Copy file name to clipboardExpand all lines: .doctor-rst.yaml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,4 @@ whitelist:
104104
- '.. versionadded:: 3.6' # MonologBundle
105105
- 'End to End Tests (E2E)'
106106
- '.. code-block:: php'
107+
- '.. _`a feature to test applications using Mercure`: https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket'

‎mercure.rst

Copy file name to clipboardExpand all lines: mercure.rst
+90-78Lines changed: 90 additions & 78 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.