Skip to content

Commit db9d8e1

Browse files
committed
minor #9437 Symfony Messenger component documentation (sroze, javiereguiluz, wiese)
This PR was merged into the master branch. Discussion ---------- Symfony Messenger component documentation This pull-request adds some documentation for the Messenger component. As it is, it's extracted from the README built incrementally in the code pull-request. I'm sure there will be lots to change when the implementation is merged :) Commits ------- c5306b8 Minor wording change 32403ea Update the documentation to reflect the latest changes 3fb973c Update based on comments 509e149 Add a documentation about middlewares and update based on reviews fb88abc Add Messenger in the topics a15752b Fix unresolved reference 25c0b6e It helps multiple applications Please enter the commit message for your changes. Lines starting bcfae23 Finish the documentation about the custom adapter 2493c90 Update typos and missing reference 31a56ee Uses `::` to display as code blocks 5c828e4 Update the documentation a bit, and add more FrameworkBundle documentation 88ba8fe Merge pull request #1 from wiese/patch-3 b26de80 minor doc fixes for the Message component b40bc71 Fixed the RST syntax issues 585491d Move the documentation from the main PR to RST format.
2 parents 44f1f4d + c5306b8 commit db9d8e1

File tree

4 files changed

+426
-0
lines changed

4 files changed

+426
-0
lines changed
21.9 KB
Loading

components/messenger.rst

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
.. index::
2+
single: Messenger
3+
single: Components; Messenger
4+
5+
The Messenger Component
6+
=======================
7+
8+
The Messenger component helps applications send and receive messages to/from other applications or via message queues.
9+
10+
Installation
11+
------------
12+
13+
.. code-block:: terminal
14+
15+
$ composer require symfony/messenger
16+
17+
Alternatively, you can clone the `<https://github.com/symfony/messenger>`_ repository.
18+
19+
.. include:: /components/require_autoload.rst.inc
20+
21+
Concepts
22+
--------
23+
24+
.. image:: /_images/components/messenger/overview.png
25+
26+
**Sender**:
27+
Responsible for serializing and sending messages to _something_. This
28+
something can be a message broker or a third party API for example.
29+
30+
**Receiver**:
31+
Responsible for deserializing and forwarding messages to handler(s). This
32+
can be a message queue puller or an API endpoint for example.
33+
34+
**Handler**:
35+
Responsible for handling messages using the business logic applicable to the messages.
36+
37+
Bus
38+
---
39+
40+
The bus is used to dispatch messages. The behaviour of the bus is in its ordered
41+
middleware stack. The component comes with a set of middleware that you can use.
42+
43+
When using the message bus with Symfony's FrameworkBundle, the following middleware
44+
are configured for you:
45+
46+
#. ``LoggingMiddleware`` (logs the processing of your messages)
47+
#. ``SendMessageMiddleware`` (enables asynchronous processing)
48+
#. ``HandleMessageMiddleware`` (calls the registered handle)
49+
50+
Example::
51+
52+
use App\Message\MyMessage;
53+
use Symfony\Component\Messenger\MessageBus;
54+
use Symfony\Component\Messenger\HandlerLocator;
55+
use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware;
56+
57+
$bus = new MessageBus([
58+
new HandleMessageMiddleware(new HandlerLocator([
59+
MyMessage::class => $handler,
60+
])),
61+
]);
62+
63+
$result = $bus->handle(new MyMessage(/* ... */));
64+
65+
.. note:
66+
67+
Every middleware needs to implement the ``MiddlewareInterface`` interface.
68+
69+
Handlers
70+
--------
71+
72+
Once dispatched to the bus, messages will be handled by a "message handler". A
73+
message handler is a PHP callable (i.e. a function or an instance of a class)
74+
that will do the required processing for your message::
75+
76+
namespace App\MessageHandler;
77+
78+
use App\Message\MyMessage;
79+
80+
class MyMessageHandler
81+
{
82+
public function __invoke(MyMessage $message)
83+
{
84+
// Message processing...
85+
}
86+
}
87+
88+
Adapters
89+
--------
90+
91+
In order to send and receive messages, you will have to configure an adapter. An
92+
adapter will be responsible of communicating with your message broker or 3rd parties.
93+
94+
Your own sender
95+
~~~~~~~~~~~~~~~
96+
97+
Using the ``SenderInterface``, you can easily create your own message sender.
98+
Let's say you already have an ``ImportantAction`` message going through the
99+
message bus and handled by a handler. Now, you also want to send this message as
100+
an email.
101+
102+
First, create your sender::
103+
104+
namespace App\MessageSender;
105+
106+
use App\Message\ImportantAction;
107+
use Symfony\Component\Message\SenderInterface;
108+
109+
class ImportantActionToEmailSender implements SenderInterface
110+
{
111+
private $toEmail;
112+
private $mailer;
113+
114+
public function __construct(\Swift_Mailer $mailer, string $toEmail)
115+
{
116+
$this->mailer = $mailer;
117+
$this->toEmail = $toEmail;
118+
}
119+
120+
public function send($message)
121+
{
122+
if (!$message instanceof ImportantAction) {
123+
throw new \InvalidArgumentException(sprintf('Producer only supports "%s" messages.', ImportantAction::class));
124+
}
125+
126+
$this->mailer->send(
127+
(new \Swift_Message('Important action made'))
128+
->setTo($this->toEmail)
129+
->setBody(
130+
'<h1>Important action</h1><p>Made by '.$message->getUsername().'</p>',
131+
'text/html'
132+
)
133+
);
134+
}
135+
}
136+
137+
Your own receiver
138+
~~~~~~~~~~~~~~~~~
139+
140+
A receiver is responsible for receiving messages from a source and dispatching
141+
them to the application.
142+
143+
Let's say you already processed some "orders" in your application using a
144+
``NewOrder`` message. Now you want to integrate with a 3rd party or a legacy
145+
application but you can't use an API and need to use a shared CSV file with new
146+
orders.
147+
148+
You will read this CSV file and dispatch a ``NewOrder`` message. All you need to
149+
do is to write your custom CSV receiver and Symfony will do the rest.
150+
151+
First, create your receiver::
152+
153+
namespace App\MessageReceiver;
154+
155+
use App\Message\NewOrder;
156+
use Symfony\Component\Message\ReceiverInterface;
157+
use Symfony\Component\Serializer\SerializerInterface;
158+
159+
class NewOrdersFromCsvFile implements ReceiverInterface
160+
{
161+
private $serializer;
162+
private $filePath;
163+
164+
public function __construct(SerializerInteface $serializer, string $filePath)
165+
{
166+
$this->serializer = $serializer;
167+
$this->filePath = $filePath;
168+
}
169+
170+
public function receive(callable $handler) : void
171+
{
172+
$ordersFromCsv = $this->serializer->deserialize(file_get_contents($this->filePath), 'csv');
173+
174+
foreach ($ordersFromCsv as $orderFromCsv) {
175+
$handler(new NewOrder($orderFromCsv['id'], $orderFromCsv['account_id'], $orderFromCsv['amount']));
176+
}
177+
}
178+
179+
public function stop(): void
180+
{
181+
// noop
182+
}
183+
}
184+
185+
Receiver and Sender on the same bus
186+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
187+
188+
To allow us to receive and send messages on the same bus and prevent an infinite
189+
loop, the message bus is equipped with the ``WrapIntoReceivedMessage`` middleware.
190+
It will wrap the received messages into ``ReceivedMessage`` objects and the
191+
``SendMessageMiddleware`` middleware will know it should not route these
192+
messages again to an adapter.

index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Topics
4141
frontend
4242
http_cache
4343
logging
44+
messenger
4445
performance
4546
profiler
4647
routing

0 commit comments

Comments
 (0)