Компонент Messenger¶
Компонент Messenger помогает приложениям отправлять и принимать сообщения из других приложений или через очереди сообщений.
Компонент во многом был основан на серии постов Маттиаса Нобака об автобусах команд и проект SimpleBus.
Установка¶
1 | $ composer require symfony/messenger
|
Как вариант, вы можете клонировать хранилище https://github.com/symfony/messenger.
Note
If you install this component outside of a Symfony application, you must
require the vendor/autoload.php
file in your code to enable the class
autoloading mechanism provided by Composer. Read
this article for more details.
Концепты¶

- Отправитель:
- Отвечает за сериализацию и отправку сообщений чему-то. Это что-то может быть брокером сообщений или сторонней API, к примеру.
- Получатель:
- Отвечает за десериализацию и перенаправление сообщений обработчку(ам). Это может быть пулер очереди сообщений или конечная точка API, к примеру.
- Обработчик:
- Отвечает за обработку сообщений, используя бизнес-логику, применимую к сообщениям.
Автобус¶
Bus используется для запуска сообщений. Поведение автобуса упорядочено в связующем стеке. Компонент поставляется с набором связующего ПО, которое вы можете использовать.
При использовании автобуса сообщений с пакетом Symfony FrameworkBundle, для вас конфигурируется следующее связующее ПО:
LoggingMiddleware
(ведет логи обработки ваших сообщений)SendMessageMiddleware
(включает асинхронную обработку)HandleMessageMiddleware
(вызывает зарегистрированный идентификатор)
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 | use App\Message\MyMessage;
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\HandlerLocator;
use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware;
$bus = new MessageBus([
new HandleMessageMiddleware(new HandlerLocator([
MyMessage::class => $handler,
])),
]);
$result = $bus->dispatch(new MyMessage(/* ... */));
|
Note
Каждое связующее ПО должно реализовывать MiddlewareInterface
.
Обработчики¶
После диспетчеризации в автобус, сообщения будут обработаны "обработчиками сообщений". Обработчик сообщений - это PHP вызываемое (т.е. функция или экземпляр класса), которое будет проводить необходимую обработку для вашего сообщения:
1 2 3 4 5 6 7 8 9 10 11 | namespace App\MessageHandler;
use App\Message\MyMessage;
class MyMessageHandler
{
public function __invoke(MyMessage $message)
{
// Обработка сообщения...
}
}
|
Транспорт¶
Для отправки и получения сообщений вам понадобится сконфигурировать транспорт. Транспорт будет отвечать за коммуникацию с вашим брокером сообщений или третьими сторонами.
Ваш собственный отправитель¶
Используя SenderInterface
вы можете с лёгкостью создать ваш собственный
отправитель сообщений. Представьте, что у вас уже есть сообщение ImportantAction
,
которое проходит через автобус сообщений и обрабатывается обработчиком. Теперь,
вам также надо отправить это сообщение в виде электронного письма.
Для начала, создайте ваш отправитель:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | namespace App\MessageSender;
use App\Message\ImportantAction;
use Symfony\Component\Messenger\Transport\SenderInterface;
class ImportantActionToEmailSender implements SenderInterface
{
private $toEmail;
private $mailer;
public function __construct(\Swift_Mailer $mailer, string $toEmail)
{
$this->mailer = $mailer;
$this->toEmail = $toEmail;
}
public function send($message)
{
if (!$message instanceof ImportantAction) {
throw new \InvalidArgumentException(sprintf('Producer only supports "%s" messages.', ImportantAction::class));
}
$this->mailer->send(
(new \Swift_Message('Important action made'))
->setTo($this->toEmail)
->setBody(
'<h1>Important action</h1><p>Made by '.$message->getUsername().'</p>',
'text/html'
)
);
}
}
|
Ваш собственный получатель¶
Получатель отвечает за получение сообщений из источника и их диспетчеризацию приложению.
Представьте, что вы уже обработали какие-то "команды" в вашем приложении,
используя сообщение NewOrder
. Теперь вы хотите интегрироваться с третьей
стороной или унаследованным приложением, но вы не можете использовать API
и вам нужно использовать общедоступный CSV с новыми командами.
Вы прочтёте этот CSV файл и запустите сообщение NewOrder
. Всё, что вам нужно
сделать - это написать ваш пользовательский CSV получатель, а Symfony сделает всё
остальное.
Для начала, создайте ваш собственный получатель:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | namespace App\MessageReceiver;
use App\Message\NewOrder;
use Symfony\Component\Messenger\Transport\ReceiverInterface;
use Symfony\Component\Serializer\SerializerInterface;
class NewOrdersFromCsvFile implements ReceiverInterface
{
private $serializer;
private $filePath;
public function __construct(SerializerInterface $serializer, string $filePath)
{
$this->serializer = $serializer;
$this->filePath = $filePath;
}
public function receive(callable $handler) : void
{
$ordersFromCsv = $this->serializer->deserialize(file_get_contents($this->filePath), 'csv');
foreach ($ordersFromCsv as $orderFromCsv) {
$handler(new NewOrder($orderFromCsv['id'], $orderFromCsv['account_id'], $orderFromCsv['amount']));
}
}
public function stop(): void
{
// noop
}
}
|
Получатель и отправитель в одном автобусе¶
Чтобы разрешить отправку и получение сообщений в одном и том же автобусе и предотвратить
бесконечный цикл, автобус сообщений оснащён связующим ПО WrapIntoReceivedMessage
.
Оно обернёт полученные сообщения в объекты ReceivedMessage
и связующее ПО
SendMessageMiddleware
будет знать, что ему не нужно повторно маршрутизировать
эти сообщения к транспорту.
Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.