8000 [Messenger] allow specifying the dispatch key when calling dispatch() · symfony/symfony@7acc671 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7acc671

Browse files
[Messenger] allow specifying the dispatch key when calling dispatch()
1 parent 5ae0e89 commit 7acc671

23 files changed

+149
-65
lines changed

src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use Symfony\Component\HttpFoundation\StreamedResponse;
2828
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
2929
use Symfony\Component\HttpKernel\HttpKernelInterface;
30+
use Symfony\Component\Messenger\Envelope;
3031
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
3132
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
3233
use Symfony\Component\Security\Csrf\CsrfToken;
@@ -390,17 +391,19 @@ protected function isCsrfTokenValid(string $id, ?string $token): bool
390391
/**
391392
* Dispatches a message to the bus.
392393
*
393-
* @param object $message The message to dispatch
394+
* @param object|Envelope $message The message or the message pre-wrapped in an envelope
395+
* @param string|null $key The key to use to select the senders and/or the handlers for the message;
396+
* if not provided, the key is derived from the class of the message
394397
*
395398
* @final
396399
*/
397-
protected function dispatchMessage($message)
400+
protected function dispatchMessage($message, string $key = null): void
398401
{
399402
if (!$this->container->has('message_bus')) {
400403
throw new \LogicException('The message bus is not enabled in your application. Try running "composer require symfony/messenger".');
401404
}
402405

403-
return $this->container->get('message_bus')->dispatch($message);
406+
$this->container->get('message_bus')->dispatch($message, $key);
404407
}
405408

406409
/**

src/Symfony/Component/Messenger/CHANGELOG.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* The component is not experimental anymore
88
* All the changes below are BC BREAKS
9+
* `MessageBusInterface::dispatch()` now requires a second `string $key = null` argument
910
* `MessageBusInterface::dispatch()` and `MiddlewareInterface::handle()` now return `void`
1011
* `MiddlewareInterface::handle()` now require an `Envelope` as first argument
1112
* `EnvelopeAwareInterface` has been removed
@@ -22,16 +23,14 @@ CHANGELOG
2223
as first constructor argument
2324
* The `EncoderInterface` and `DecoderInterface` have been replaced by a unified `Symfony\Component\Messenger\Transport\Serialization\SerializerInterface`.
2425
* The locator passed to `ContainerHandlerLocator` should not prefix its keys by "handler." anymore
25-
* The `AbstractHandlerLocator::getHandler()` method uses `?callable` as return type
2626
* Renamed `EnvelopeItemInterface` to `StampInterface`
2727
* `Envelope`'s constructor and `with()` method now accept 10000 `StampInterface` objects as variadic parameters
2828
* Renamed and moved `ReceivedMessage`, `ValidationConfiguration` and `SerializerConfiguration` in the `Stamp` namespace
2929
* Removed the `WrapIntoReceivedMessage`
30-
* `SenderLocatorInterface::getSenderForMessage()` has been replaced by `getSender(Envelope $envelope)`
3130
* `MessengerDataCollector::getMessages()` returns an iterable, not just an array anymore
3231
* `AbstractHandlerLocator` is now internal
33-
* `HandlerLocatorInterface::resolve()` has been replaced by `getHandler(Envelope $envelope): ?callable` and shouldn't throw when no handlers are found
34-
* `SenderLocatorInterface::getSenderForMessage()` has been replaced by `getSender(Envelope $envelope)`
32+
* `HandlerLocatorInterface::resolve()` has been replaced by `getHandler(string $key): ?callable` and shouldn't throw when no handlers are found
33+
* `SenderLocatorInterface::getSenderForMessage()` has been replaced by `getSender(string $key): ?SenderInterface`
3534
* `SenderInterface::send()` returns `void`
3635
* Classes in the `Middleware\Enhancers` sub-namespace have been moved to the `Middleware` one
3736
* Classes in the `Asynchronous\Routing` sub-namespace have been moved to the `Transport\Sender\Locator` sub-namespace

src/Symfony/Component/Messenger/Envelope.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Messenger;
1313

14+
use Symfony\Component\Messenger\Stamp\DispatchKeyStamp;
1415
use Symfony\Component\Messenger\Stamp\StampInterface;
1516

1617
/**
@@ -38,6 +39,18 @@ public function __construct($message, StampInterface ...$stamps)
3839
}
3940
}
4041

42+
/**
43+
* Wraps a message into an envelope if not already wrapped.
44+
*
45+
* @param Envelope|object $message
46+
*/
47+
public static function wrap($message, ?string $key): self
48+
{
49+
$envelope = $message instanceof self ? $message : new self($message);
50+
51+
return null !== $key ? $envelope->with(new DispatchKeyStamp($key)) : $envelope;
52+
}
53+
4154
/**
4255
* @return Envelope a new Envelope instance with additional stamp
4356
*/
@@ -72,4 +85,13 @@ public function getMessage()
7285
{
7386
return $this->message;
7487
}
88+
89+
public function getDispatchKey(): string
90+
{
91+
if (null !== $key = $this->stamps[DispatchKeyStamp::class] ?? null) {
92+
return $key->getName();
93+
}
94+
95+
return \get_class($this->message);
96+
}
7597
}

src/Symfony/Component/Messenger/Handler/Locator/AbstractHandlerLocator.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,26 @@
2121
*/
2222
abstract class AbstractHandlerLocator implements HandlerLocatorInterface
2323
{
24-
public function getHandler(Envelope $envelope): ?callable
24+
public function getHandler(string $key): ?callable
2525
{
26-
$class = \get_class($envelope->getMessage());
27-
28-
if ($handler = $this->getHandlerByName($class)) {
26+
if ($handler = $this->getHandlerByType($key)) {
2927
return $handler;
3028
}
3129

32-
foreach (class_parents($class) as $name) {
33-
if ($handler = $this->getHandlerByName($name)) {
30+
foreach (class_parents($key) as $type) {
31+
if ($handler = $this->getHandlerByType($type)) {
3432
return $handler;
3533
}
3634
}
3735

38-
foreach (class_implements($class) as $name) {
39-
if ($handler = $this->getHandlerByName($name)) {
36+
foreach (class_implements($key, false) as $type) {
37+
if ($handler = $this->getHandlerByType($type)) {
4038
return $handler;
4139
}
4240
}
4341

4442
return null;
4543
}
4644

47-
abstract protected function getHandlerByName(string $name): ?callable;
45+
abstract protected function getHandlerByType(string $type): ?callable;
4846
}

src/Symfony/Component/Messenger/Handler/Locator/ContainerHandlerLocator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ public function __construct(ContainerInterface $container)
2929
/**
3030
* {@inheritdoc}
3131
*/
32-
protected function getHandlerByName(string $name): ?callable
32+
protected function getHandlerByType(string $type): ?callable
3333
{
34-
return $this->container->has($name) ? $this->container->get($name) : null;
34+
return $this->container->has($type) ? $this->container->get($type) : null;
3535
}
3636
}

src/Symfony/Component/Messenger/Handler/Locator/HandlerLocator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ public function __construct(array $messageToHandlerMapping = array())
2929
/**
3030
* {@inheritdoc}
3131
*/
32-
protected function getHandlerByName(string $name): ?callable
32+
protected function getHandlerByType(string $type): ?callable
3333
{
34-
return $this->messageToHandlerMapping[$name] ?? null;
34+
return $this->messageToHandlerMapping[$type] ?? null;
3535
}
3636
}

src/Symfony/Component/Messenger/Handler/Locator/HandlerLocatorInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ interface HandlerLocatorInterface
2121
/**
2222
* Returns the handler for the given message.
2323
*/
24-
public function getHandler(Envelope $envelope): ?callable;
24+
public function getHandler(string $key): ?callable;
2525
}

src/Symfony/Component/Messenger/MessageBus.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function getIterator()
4949
/**
5050
* {@inheritdoc}
5151
*/
52-
public function dispatch($message): void
52+
public function dispatch($message, string $key = null): void
5353
{
5454
if (!\is_object($message)) {
5555
throw new \TypeError(sprintf('Invalid argument provided to "%s()": expected object, but got %s.', __METHOD__, \gettype($message)));
@@ -72,6 +72,6 @@ public function dispatch($message): void
7272
}
7373
};
7474

75-
$middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $next);
75+
$middlewareIterator->current()->handle(Envelope::wrap($message, $key), $next);
7676
}
7777
}

src/Symfony/Component/Messenger/MessageBusInterface.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ interface MessageBusInterface
2020
* Dispatches the given message.
2121
*
2222
* @param object|Envelope $message The message or the message pre-wrapped in an envelope
23+
* @param string|null $key The key to use to select the senders and/or the handlers for the message;
24+
* if not provided, the key is derived from the class of the message
2325
*/
24-
public function dispatch($message): void;
26+
public function dispatch($message, string $key = null): void;
2527
}

src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function __construct(HandlerLocatorInterface $messageHandlerLocator, bool
3636
*/
3737
public function handle(Envelope $envelope, callable $next): void
3838
{
39-
if (null !== $handler = $this->messageHandlerLocator->getHandler($envelope)) {
39+
if (null !== $handler = $this->messageHandlerLocator->getHandler($envelope->getDispatchKey())) {
4040
$handler($envelope->getMessage());
4141
$next($envelope);
4242
} elseif (!$this->allowNoHandlers) {

src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,19 @@ public function handle(Envelope $envelope, callable $next): void
3434
$message = $envelope->getMessage();
3535
$context = array(
3636
'message' => $message,
37-
'name' => \get_class($message),
37+
'name' => $envelope->getDispatchKey(),
3838
);
39-
$this->logger->debug('Starting handling message {name}', $context);
39+
$this->logger->debug('Starting handling message "{name}"', $context);
4040

4141
try {
4242
$next($envelope);
4343
} catch (\Throwable $e) {
4444
$context['exception'] = $e;
45-
$this->logger->warning('An exception occurred while handling message {name}', $context);
45+
$this->logger->warning('An exception occurred while handling message "{name}"', $context);
4646

4747
throw $e;
4848
}
4949

50-
$this->logger->debug('Finished handling message {name}', $context);
50+
$this->logger->debug('Finished handling message "{name}"', $context);
5151
}
5252
}

src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ public function handle(Envelope $envelope, callable $next): void
4343
return;
4444
}
4545

46-
$sender = $this->senderLocator->getSender($envelope);
46+
$sender = $this->senderLocator->getSender($envelope->getDispatchKey());
4747

4848
if ($sender) {
4949
$sender->send($envelope);
5050

51-
if (!AbstractSenderLocator::getValueFromMessageRouting($this->messagesToSendAndHandleMapping, $envelope)) {
51+
if (!AbstractSenderLocator::getValueFromMessageRouting($this->messagesToSendAndHandleMapping, $envelope->getDispatchKey())) {
5252
// message has no corresponding handler
5353
return;
5454
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Messenger\Stamp;
13+
14+
/**
15+
* A stamp that defines the key that should be used to decide
16+
* which senders and/or handlers are bound to a message.
17+
*
18+
* @author Nicolas Grekas <p@tchwork.com>
19+
*/
20+
final class DispatchKeyStamp implements StampInterface
21+
{
22+
private $name;
23+
24+
public function __construct(string $name)
25+
{
26+
$this->name = $name;
27+
}
28+
29+
public function getName()
30+
{
31+
return $this->name;
32+
}
33+
}

src/Symfony/Component/Messenger/Tests/Handler/Locator/ContainerHandlerLocatorTest.php

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use PHPUnit\Framework\TestCase;
66
use Symfony\Component\DependencyInjection\Container;
7-
use Symfony\Component\Messenger\Envelope;
87
use Symfony\Component\Messenger\Handler\Locator\ContainerHandlerLocator;
98
use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage;
109
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
@@ -20,15 +19,15 @@ public function testItLocatesHandlerUsingTheMessageClass()
2019
$container->set(DummyMessage::class, $handler);
2120

2221
$locator = new ContainerHandlerLocator($container);
23-
$resolvedHandler = $locator->getHandler(new Envelope(new DummyMessage('Hey')));
22+
$resolvedHandler = $locator->getHandler(DummyMessage::class);
2423

2524
$this->assertSame($handler, $resolvedHandler);
2625
}
2726

2827
public function testNoHandlersReturnsNull()
2928
{
3029
$locator = new ContainerHandlerLocator(new Container());
31-
$this->assertNull($locator->getHandler(new Envelope(new DummyMessage('Hey'))));
30+
$this->assertNull($locator->getHandler(DummyMessage::class));
3231
}
3332

3433
public function testGetHandlerViaInterface()
@@ -39,7 +38,7 @@ public function testGetHandlerViaInterface()
3938
$container->set(DummyMessageInterface::class, $handler);
4039

4140
$locator = new ContainerHandlerLocator($container);
42-
$resolvedHandler = $locator->getHandler(new Envelope(new DummyMessage('Hey')));
41+
$resolvedHandler = $locator->getHandler(DummyMessage::class);
4342

4443
$this->assertSame($handler, $resolvedHandler);
4544
}
@@ -52,8 +51,22 @@ public function testGetHandlerViaParentClass()
5251
$container->set(DummyMessage::class, $handler);
5352

5453
$locator = new ContainerHandlerLocator($container);
55-
$resolvedHandler = $locator->getHandler(new Envelope(new ChildDummyMessage('Hey')));
54+
$resolvedHandler = $locator->getHandler(ChildDummyMessage::class);
5655

5756
$this->assertSame($handler, $resolvedHandler);
5857
}
58+
59+
public function testGetHandlerViaDispatchKey()
60+
{
61+
$handler1 = function () {};
62+
$handler2 = function () {};
63+
64+
$container = new Container();
65+
$locator = new ContainerHandlerLocator($container);
66+
$container->set(DummyMessage::class, $handler1);
67+
$container->set('foo', $handler2);
68+
69+
$resolvedHandler = $locator->getHandler('foo');
70+
$this->assertSame($handler2, $resolvedHandler);
71+
}
5972
}

src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public function __construct(?SenderInterface $sender)
158158
$this->sender = $sender;
159159
}
160160

161-
public function getSender(Envelope $envelope): ?SenderInterface
161+
public function getSender(string $key): ?SenderInterface
162162
{
163163
return $this->sender;
164164
}

src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
require_once $autoload;
1414

15+
use Symfony\Component\Messenger\Envelope;
1516
use Symfony\Component\Messenger\MessageBusInterface;
1617
use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver;
1718
use Symfony\Component\Messenger\Transport\AmqpExt\Connection;
@@ -29,9 +30,10 @@
2930
$receiver = new AmqpReceiver($connection, $serializer);
3031

3132
$worker = new Worker($receiver, new class() implements MessageBusInterface {
32-
public function dispatch($envelope): void
33+
public function dispatch($message, string $key = null): void
3334
{
34-
echo 'Get envelope with message: '.get_class($envelope->getMessage())."\n";
35+
$envelope = Envelope::wrap($message, $key);
36+
echo 'Get envelope with message: '.$envelope->getDispatchKey()."\n";
3537
echo sprintf("with stamps: %s\n", json_encode(array_keys($envelope->all()), JSON_PRETTY_PRINT));
3638

3739
sleep(30);

0 commit comments

Comments
 (0)
10C6
0