@@ -11,253 +11,3 @@ Resources
11
11
* [ Report issues] ( https://github.com/symfony/symfony/issues ) and
12
12
[ send Pull Requests] ( https://github.com/symfony/symfony/pulls )
13
13
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