4. What's Symfony Messenger about?
1. Messages. Any serialisable PHP object.
2. Message bus. Where you dispatch your messages.
3. Message handlers. Will execute your business logic when the
message arrives to them.
4. Transports. Allow to send and receive messages through 3rd
party systems.
5. Worker. To consume messages from transports.
5.
6.
7.
8.
9.
10. $ composer req symfony/messenger
or composer req messenger
11. A message
No specific requirement.
namespace AppMessage;
class SendNotification
{
// ...properties
public function __construct(string $message, array $users)
{
$this->message = $message;
$this->users = $users;
}
// ...getters
}
12. As a component
use SymfonyComponentMessengerMessageBus;
use SymfonyComponentMessengerHandlerLocator;
use SymfonyComponentMessengerMiddlewareHandleMessageMiddleware;
$handler = function(SendNotification $message) {
// ...
};
$messageBus = new MessageBus([
new HandleMessageMiddleware(new HandlerLocator([
SendNotification::class => $handler,
])),
]);
14. Dispatching a message
namespace AppController;
use AppMessageSendNotification;
// ...
use SymfonyComponentMessengerMessageBusInterface;
class DefaultController
{
public function index(MessageBusInterface $bus, Request $request)
{
$users = ['samuel', 'christelle'];
$bus->dispatch(new SendNotification(
$request->query->get('message', 'Hello London.'),
$users
));
return new Response('<html><body>OK.</body></html>');
}
}
15. Dispatching a message
namespace AppController;
use AppMessageSendNotification;
// ...
use SymfonyComponentMessengerMessageBusInterface;
class DefaultController
{
public function index(MessageBusInterface $bus, Request $request)
{
$users = ['samuel', 'christelle'];
$bus->dispatch(new SendNotification(
$request->query->get('message', 'Hello London.'),
$users
));
return new Response('<html><body>OK.</body></html>');
}
}
16.
17. A message handler
namespace AppMessageHandler;
use AppMessageSendNotification;
class SendNotificationHandler
{
public function __invoke(SendNotification $message)
{
foreach ($message->getUsers() as $user) {
echo "Send notification to... ".$user."n";
}
}
}
18. Register your handler
# config/services.yaml
services:
AppMessageHandlerSendNotificationHandler:
tags: ['messenger.message_handler']
20. Register your handlers (op3on 3)
namespace AppMessageHandler;
use AppMessageSendNotification;
use SymfonyComponentMessengerHandlerMessageHandlerInterface;
class SendNotificationHandler implements MessageHandlerInterface
{
public function __invoke(SendNotification $message)
{
foreach ($message->getUsers() as $user) {
echo "Send notification to... ".$user."n";
}
}
}
29. What's a transport?
1. Has a sender & receiver
Guess what. They send and receive messages.
2. Is configurable via a DSN
So we have a unique and common way of configuring them.
3. Use a Messenger Serializer
By defaut, uses Symfony Serializer. Replace as you wish.
30. Transports
1. Built-in AMQP.
You don't need anything more than the component and the PHP
extension.
2. More with Enqueue. (10+ other transports)
h>ps://github.com/php-enqueue/messenger-adapter
3. Fully extensible.
Create your own very easily by registering your implementaIon
of the TransportFactory interface.
48. Envelopes
namespace AppMiddleware;
use SymfonyComponentMessengerMiddlewareMiddlewareInterface;
use SymfonyComponentMessengerEnvelopeAwareInterface;
use SymfonyComponentMessengerAsynchronousTransportReceivedMessage;
class AuditMiddleware implements MiddlewareInterface,
EnvelopeAwareInterface
{
public function handle($envelope, callable $next)
{
try {
if (null !== $envelope->get(ReceivedMessage::class)) {
echo sprintf('Consumed message "%s"'."n", get_class($message));
} else {
echo sprintf('Dispatched message "%s"'."n", get_class($message));
}
return $next($envelope);
} finally {
echo sprintf('Ended with message "%s"'."n", get_class($message));
}
}
}
49. Envelopes
namespace AppMiddleware;
use SymfonyComponentMessengerMiddlewareMiddlewareInterface;
use SymfonyComponentMessengerEnvelopeAwareInterface;
use SymfonyComponentMessengerAsynchronousTransportReceivedMessage;
class AuditMiddleware implements MiddlewareInterface,
EnvelopeAwareInterface
{
public function handle($envelope, callable $next)
{
try {
if (null !== $envelope->get(ReceivedMessage::class)) {
echo sprintf('Consumed message "%s"'."n", get_class($message));
} else {
echo sprintf('Dispatched message "%s"'."n", get_class($message));
}
return $next($envelope);
} finally {
echo sprintf('Ended with message "%s"'."n", get_class($message));
}
}
}
50. Your own Envelope item
use SymfonyComponentMessengerEnvelopeAwareInterface;
use SymfonyComponentMessengerMiddlewareMiddlewareInterface;
class AuditMiddleware implements MiddlewareInterface,
EnvelopeAwareInterface
{
public function handle($envelope, callable $next)
{
$message = $envelope->getMessage();
if (null === $auditEnvelope = $envelope->get(AuditEnvelopeItem::class)) {
$envelope = $envelope->with(
$auditEnvelope = new AuditEnvelopeItem(uniqid())
);
}
try {
echo sprintf('[%s] Started with message "%s"' . "n", $auditEnvelope->getUuid(), get_class($message));
return $next($envelope);
} finally {
echo sprintf('[%s] Ended with message "%s"'."n", $auditEnvelope->getUuid(), get_class($message));
}
}
}
51. Your own Envelope item
use SymfonyComponentMessengerEnvelopeItemInterface;
class AuditEnvelopeItem implements EnvelopeItemInterface
{
private $uuid;
public function __construct(string $uuid)
{
$this->uuid = $uuid;
}
public function getUuid()
{
return $this->uuid;
}
}
52. Envelopes: also for "configura3on"
use SymfonyComponentMessengerEnvelope;
use SymfonyComponentMessengerTransport
SerializationSerializerConfiguration;
$bus->dispatch(
(new Envelope($message))->with(new SerializerConfiguration([
'groups' => ['my_serialization_groups'],
]))
);
53. What can you do?
1. Try it!
It has arrived in Symfony 4.1. Stable in 4.2.
2. Help us make it great again.
Open an issue, a pull-request, create another transport, a set of
middleware, ...
3. Enjoy.