@@ -11,253 +11,3 @@ Resources
1111 * [ Report issues] ( https://github.com/symfony/symfony/issues ) and
1212 [ send Pull Requests] ( https://github.com/symfony/symfony/pulls )
1313 in the [ main Symfony repository] ( https://github.com/symfony/symfony )
14-
15-
16- Documentation
17- -------------
18-
19- ** Note:** this documentation is to be moved to symfony.com when merging the Component.
20-
21- ### Concepts
22-
23- ![ Component overview] ( Resources/doc/component-overview.png )
24-
25- 1 . ** Sender**
26- Responsible for serializing and sending the message to _ something_ . This something can be a message broker or a 3rd
27- party API for example.
28-
29- 2 . ** Receiver**
30- Responsible for deserializing and forwarding the messages to handler(s). This can be a message queue puller or an API
31- endpoint for example.
32-
33- 3 . ** Handler**
34- Given a received message, contains the user business logic related to the message. In practice, that is just a PHP
35- callable.
36-
37-
38- ### Bus
39-
40- The bus is used to dispatch messages. MessageBus' behaviour is in its ordered middleware stack. When using
41- the message bus with Symfony's FrameworkBundle, the following middlewares are configured for you:
42-
43- 1 . ` LoggingMiddleware ` (log the processing of your messages)
44- 2 . ` SendMessageMiddleware ` (enable asynchronous processing)
45- 3 . ` HandleMessageMiddleware ` (call the registered handle)
46-
47- ``` php
48- use App\Message\MyMessage;
49-
50- $result = $this->get('message_bus')->handle(new MyMessage(/* ... */));
51- ```
52-
53- ### Handlers
54-
55- Once dispatched to the bus, messages will be handled by a "message handler". A message handler is a PHP callable
56- (i.e. a function or an instance of a class) that will do the required processing for your message. It _ might_ return a
57- result.
58-
59- ``` php
60- namespace App\MessageHandler;
61-
62- use App\Message\MyMessage;
63-
64- class MyMessageHandler
65- {
66- public function __invoke(MyMessage $message)
67- {
68- // Message processing...
69- }
70- }
71- ```
72-
73- ``` xml
74- <service id =" App\Handler\MyMessageHandler" >
75- <tag name =" message_handler" />
76- </service >
77- ```
78-
79- ** Note:** If the message cannot be guessed from the handler's type-hint, use the ` handles ` attribute on the tag.
80-
81- ### Asynchronous messages
82-
83- Using the Message Component is useful to decouple your application but it also very useful when you want to do some
84- asychronous processing. This means that your application will produce a message to a queuing system and consume this
85- message later in the background, using a _ worker_ .
86-
87- #### Adapters
88-
89- The communication with queuing system or 3rd parties is for delegated to libraries for now. You can use one of the
90- following adapters:
91-
92- - [ PHP Enqueue bridge] ( https://github.com/sroze/enqueue-bridge ) to use one of their 10+ compatible queues such as
93- RabbitMq, Amazon SQS or Google Pub/Sub.
94- - [ Swarrot adapter] ( https://github.com/sroze/swarrot-bridge ) to use Swarrot, a library specialised in consuming
95- messages from AMQP brokers such as RabbitMq.
96- - [ HTTP adapter] ( https://github.com/sroze/message-http-adapter ) to receive and send messages through HTTP APIs.
97-
98- #### Routing
99-
100- When doing asynchronous processing, the key is to route the message to the right sender. As the routing is
101- application-specific and not message-specific, the configuration can be made within the ` framework.yaml `
102- configuration file as well:
103-
104- ``` yaml
105- framework :
106- message :
107- routing :
108- ' My\Message\MessageAboutDoingOperationalWork ' : my_operations_queue_sender
109- ` ` `
110-
111- Such configuration would only route the ` MessageAboutDoingOperationalWork` message to be asynchronous, the rest of the
112- messages would still be directly handled.
113-
114- If you want to do route all the messages to a queue by default, you can use such configuration :
115- ` ` ` yaml
116- framework:
117- message:
118- routing:
119- 'My\M essage\M essageAboutDoingOperationalWork': my_operations_queue_sender
120- '*': my_default_sender
121- ` ` `
122-
123- Note that you can also route a message to multiple senders at the same time :
124- ` ` ` yaml
125- framework:
126- message:
127- routing:
128- 'My\M essage\A nImportantMessage': [my_default_sender, my_audit_sender]
129- ` ` `
130-
131- # ### Same bus received and sender
132-
133- To allow us to receive and send messages on the same bus and prevent a loop, the message bus is equipped with the
134- ` WrapIntoReceivedMessage` received. It will wrap the received messages into `ReceivedMessage` objects and the
135- ` SendMessageMiddleware` middleware will know it should not send these messages.
136-
137- # ## Your own sender
138-
139- Using the `SenderInterface`, you can easily create your own message sender. Let's say you already have an
140- ` ImportantAction` message going through the message bus and handled by a handler. Now, you also want to send this
141- message as an email.
142-
143- 1. Create your sender
144-
145- ` ` ` php
146- namespace App\M essageSender;
147-
148- use Symfony\C omponent\M essage\S enderInterface;
149- use App\M essage\I mportantAction;
150-
151- class ImportantActionToEmailSender implements SenderInterface
152- {
153- private $toEmail;
154- private $mailer;
155-
156- public function __construct(\S wift_Mailer $mailer, string $toEmail)
157- {
158- $this->mailer = $mailer;
159- $this->toEmail = $toEmail;
160- }
161-
162- public function send($message)
163- {
164- if (!$message instanceof ImportantAction) {
165- throw new \I nvalidArgumentException(sprintf('Producer only supports "%s" messages.', ImportantAction::class));
166- }
167-
168- $this->mailer->send(
169- (new \S wift_Message('Important action made'))
170- ->setTo($this->toEmail)
171- ->setBody(
172- '<h1>Important action</h1><p>Made by '.$message->getUsername().'</p>',
173- 'text/html'
174- )
175- );
176- }
177- }
178- ` ` `
179-
180- 2. Register your sender service
181-
182- ` ` ` yaml
183- services:
184- App\M essageSender\I mportantActionToEmailSender:
185- arguments:
186- - "@mailer"
187- - "%to_email%"
188-
189- tags:
190- - message.sender
191- ` ` `
192-
193- 3. Route your important message to the sender
194-
195- ` ` ` yaml
196- framework:
197- message:
198- routing:
199- 'App\M essage\I mportantAction': [App\M essageSender\I mportantActionToEmailSender, ~]
200- ` ` `
201-
202- **Note:** this example shows you how you can at the same time send your message and directly handle it using a `null`
203- (`~`) sender.
204-
205- # ## Your own receiver
206-
207- A consumer is responsible of receiving messages from a source and dispatching them to the application.
208-
209- Let's say you already proceed some "orders" on your application using a `NewOrder` message. Now you want to integrate with
210- a 3rd party or a legacy application but you can't use an API and need to use a shared CSV file with new orders.
211-
212- You will read this CSV file and dispatch a `NewOrder` message. All you need to do is your custom CSV consumer and Symfony will do the rest.
213-
214- 1. Create your receiver
215-
216- ` ` ` php
217- namespace App\M essageReceiver;
218-
219- use Symfony\C omponent\M essage\R eceiverInterface;
220- use Symfony\C omponent\S erializer\S erializerInterface;
221-
222- use App\M essage\N ewOrder;
223-
224- class NewOrdersFromCsvFile implements ReceiverInterface
225- {
226- private $serializer;
227- private $filePath;
228-
229- public function __construct(SerializerInteface $serializer, string $filePath)
230- {
231- $this->serializer = $serializer;
232- $this->filePath = $filePath;
233- }
234-
235- public function receive() : \G enerator
236- {
237- $ordersFromCsv = $this->serializer->deserialize(file_get_contents($this->filePath), 'csv');
238-
239- foreach ($ordersFromCsv as $orderFromCsv) {
240- yield new NewOrder($orderFromCsv['id'], $orderFromCsv['account_id'], $orderFromCsv['amount']);
241- }
242- }
243- }
244- ` ` `
245-
246- 2. Register your receiver service
247-
248- ` ` ` yaml
249- services:
250- App\M essageReceiver\N ewOrdersFromCsvFile:
251- arguments:
252- - "@serializer"
253- - "%new_orders_csv_file_path%"
254-
255- tags:
256- - message.receiver
257- ` ` `
258-
259- 3. Use your consumer
260-
261- ` ` ` bash
262- $ bin/console message:consume App\M essageReceived\N ewOrdersFromCsvFile
263- ` ` `
0 commit comments