feature #30650 Dispatching two events when a message is sent & handled (weaverryan)
This PR was merged into the 4.3-dev branch.
Discussion
----------
Dispatching two events when a message is sent & handled
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | none
| License | MIT
| Doc PR | TODO
Alternative to #30646. This uses a more generic system, so you could do anything when a message is sent. The main use-case is when a message is dispatched by a 3rd party.
I didn't try to add *exhaustive* events everywhere: I added an event for a very specific use-case:
When a message is dispatched by a 3rd party, being able to add stamps (e.g. `DelayStamp` or a future `AmqpRoutingKeyStamp` before the message is sent. Example:
```php
class MailerMessageSendToTransportEventSubscriber implements EventSubscriberInterface
{
public function onSendMessage(SendMessageToTransportsEvent $event)
{
$envelope = $event->getEnvelope();
if (!$envelope->getMessage() instanceof SomeMailerMessage) {
return;
}
$event->setEnvelope($envelope->with(new AmpqRoutingKeyStamp('mailer-route')));
}
public static function getSubscribedEvents()
{
return [SendMessageToTransportsEvent::class => 'onSendMessage'];
}
}
```
Along with #30557, we will now have the following events, regarding async messages:
* Event when a message is sent to transports (this PR)
* Event when a message is received from transport, but before handling it
* Event when a message is received from transport and after handling it
Commits
-------
a7ad1b4ccc
Dispatching two events when a message is sent & handled
This commit is contained in:
commit
e3970f9879
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Messenger\Event;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
|
||||
/**
|
||||
* Event is dispatched before a message is sent to the transport.
|
||||
*
|
||||
* The event is *only* dispatched if the message will actually
|
||||
* be sent to at least one transport. If the message is sent
|
||||
* to multiple transports, the message is dispatched only one time.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@symfonycasts.com>
|
||||
*/
|
||||
class SendMessageToTransportsEvent extends Event
|
||||
{
|
||||
private $envelope;
|
||||
|
||||
public function __construct(Envelope $envelope)
|
||||
{
|
||||
$this->envelope = $envelope;
|
||||
}
|
||||
|
||||
public function getEnvelope(): Envelope
|
||||
{
|
||||
return $this->envelope;
|
||||
}
|
||||
|
||||
public function setEnvelope(Envelope $envelope)
|
||||
{
|
||||
$this->envelope = $envelope;
|
||||
}
|
||||
}
|
@ -13,7 +13,9 @@ namespace Symfony\Component\Messenger\Middleware;
|
||||
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent;
|
||||
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
|
||||
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
|
||||
use Symfony\Component\Messenger\Stamp\SentStamp;
|
||||
@ -30,10 +32,12 @@ class SendMessageMiddleware implements MiddlewareInterface
|
||||
use LoggerAwareTrait;
|
||||
|
||||
private $sendersLocator;
|
||||
private $eventDispatcher;
|
||||
|
||||
public function __construct(SendersLocatorInterface $sendersLocator)
|
||||
public function __construct(SendersLocatorInterface $sendersLocator, EventDispatcherInterface $eventDispatcher = null)
|
||||
{
|
||||
$this->sendersLocator = $sendersLocator;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->logger = new NullLogger();
|
||||
}
|
||||
|
||||
@ -58,7 +62,15 @@ class SendMessageMiddleware implements MiddlewareInterface
|
||||
/** @var RedeliveryStamp|null $redeliveryStamp */
|
||||
$redeliveryStamp = $envelope->last(RedeliveryStamp::class);
|
||||
|
||||
foreach ($this->sendersLocator->getSenders($envelope, $handle) as $alias => $sender) {
|
||||
$senders = \iterator_to_array($this->sendersLocator->getSenders($envelope, $handle));
|
||||
|
||||
if (null !== $this->eventDispatcher && \count($senders) > 0) {
|
||||
$event = new SendMessageToTransportsEvent($envelope);
|
||||
$this->eventDispatcher->dispatch($event);
|
||||
$envelope = $event->getEnvelope();
|
||||
}
|
||||
|
||||
foreach ($senders as $alias => $sender) {
|
||||
// on redelivery, only deliver to the given sender
|
||||
if (null !== $redeliveryStamp && !$redeliveryStamp->shouldRedeliverToSender(\get_class($sender), $alias)) {
|
||||
continue;
|
||||
|
@ -11,7 +11,9 @@
|
||||
|
||||
namespace Symfony\Component\Messenger\Tests\Middleware;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent;
|
||||
use Symfony\Component\Messenger\Middleware\SendMessageMiddleware;
|
||||
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
|
||||
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
|
||||
@ -202,4 +204,24 @@ class SendMessageMiddlewareTest extends MiddlewareTestCase
|
||||
|
||||
$this->assertNull($envelope->last(SentStamp::class), 'it does not add sent stamp for received messages');
|
||||
}
|
||||
|
||||
public function testItDispatchesTheEventOnceTime()
|
||||
{
|
||||
$envelope = new Envelope(new DummyMessage('original envelope'));
|
||||
|
||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(new SendMessageToTransportsEvent($envelope));
|
||||
|
||||
$sender1 = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
$sender2 = $this->getMockBuilder(SenderInterface::class)->getMock();
|
||||
|
||||
$middleware = new SendMessageMiddleware(new SendersLocator([DummyMessage::class => [$sender1, $sender2]]), $dispatcher);
|
||||
|
||||
$sender1->expects($this->once())->method('send')->willReturn($envelope);
|
||||
$sender2->expects($this->once())->method('send')->willReturn($envelope);
|
||||
|
||||
$middleware->handle($envelope, $this->getStackMock(false));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user