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

Skip to content

Commit bd0ced5

Browse files
[Messenger] allow specifying the message name when calling dispatch()
1 parent d5771cc commit bd0ced5

21 files changed

+147
-68
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,17 +391,19 @@ protected function isCsrfTokenValid(string $id, ?string $token): bool
391391
/**
392392
* Dispatches a message to the bus.
393393
*
394-
* @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 $topic The topic that senders and/or handlers can subscribe to to get the message;
396+
* if not provided, the topic is the class of the message
395397
*
396398
* @final
397399
*/
398-
protected function dispatchMessage($message): Envelope
400+
protected function dispatchMessage($message, string $topic = null): Envelope
399401
{
400402
if (!$this->container->has('message_bus')) {
401403
throw new \LogicException('The message bus is not enabled in your application. Try running "composer require symfony/messenger".');
402404
}
403405

404-
return $this->container->get('message_bus')->dispatch($message);
406+
return $this->container->get('message_bus')->dispatch($message, $topic);
405407
}
406408

407409
/**

src/Symfony/Component/Messenger/CHANGELOG.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* The component is not experimental anymore
88
* All the changes below are BC BREAKS
99
* `MessageBusInterface::dispatch()`, `MiddlewareInterface::handle()` and `SenderInterface::send()` return `Envelope`
10+
* `MessageBusInterface::dispatch()` now takes a second `string $topic = null` argument
1011
* `MiddlewareInterface::handle()` now require an `Envelope` as first argument and a `StackInterface` as second
1112
* `EnvelopeAwareInterface` has been removed
1213
* The signature of `Amqp*` classes changed to take a `Connection` as a first argument and an optional
@@ -21,16 +22,14 @@ CHANGELOG
2122
as first constructor argument
2223
* The `EncoderInterface` and `DecoderInterface` have been replaced by a unified `Symfony\Component\Messenger\Transport\Serialization\SerializerInterface`.
2324
* The locator passed to `ContainerHandlerLocator` should not prefix its keys by "handler." anymore
24-
* The `AbstractHandlerLocator::getHandler()` method uses `?callable` as return type
2525
* Renamed `EnvelopeItemInterface` to `StampInterface`
2626
* `Envelope`'s constructor and `with()` method now accept `StampInterface` objects as variadic parameters
2727
* Renamed and moved `ReceivedMessage`, `ValidationConfiguration` and `SerializerConfiguration` in the `Stamp` namespace
2828
* Removed the `WrapIntoReceivedMessage`
29-
* `SenderLocatorInterface::getSenderForMessage()` has been replaced by `getSender(Envelope $envelope)`
3029
* `MessengerDataCollector::getMessages()` returns an iterable, not just an array anymore
3130
* `AbstractHandlerLocator` is now internal
32-
* `HandlerLocatorInterface::resolve()` has been replaced by `getHandler(Envelope $envelope): ?callable` and shouldn't throw when no handlers are found
33-
* `SenderLocatorInterface::getSenderForMessage()` has been replaced by `getSender(Envelope $envelope)`
31+
* `HandlerLocatorInterface::resolve()` has been replaced by `getHandler(string $topic): ?callable` and shouldn't throw when no handlers are found
32+
* `SenderLocatorInterface::getSenderForMessage()` has been replaced by `getSender(string $topic): ?SenderInterface`
3433
* Classes in the `Middleware\Enhancers` sub-namespace have been moved to the `Middleware` one
3534
* Classes in the `Asynchronous\Routing` sub-namespace have been moved to the `Transport\Sender\Locator` sub-namespace
3635
* The `Asynchronous/Middleware/SendMessageMiddleware` class has been moved to the `Middleware` namespace

src/Symfony/Component/Messenger/Envelope.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Messenger;
1313

1414
use Symfony\Component\Messenger\Stamp\StampInterface;
15+
use Symfony\Component\Messenger\Stamp\TopicStamp;
1516

1617
/**
1718
* A message wrapped in an envelope with stamps (configurations, markers, ...).
@@ -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 $topic): self
48+
{
49+
$envelope = $message instanceof self ? $message : new self($message);
50+
51+
return null !== $topic ? $envelope->with(new TopicStamp($topic)) : $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 getTopic(): string
90+
{
91+
if (null !== $topic = $this->stamps[TopicStamp::class] ?? null) {
92+
return $topic->getName();
93+
}
94+
95+
return \get_class($this->message);
96+
}
7597
}

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

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

1212
namespace Symfony\Component\Messenger\Handler\Locator;
1313

14-
use Symfony\Component\Messenger\Envelope;
15-
1614
/**
1715
* @author Miha Vrhovnik <miha.vrhovnik@gmail.com>
1816
* @author Samuel Roze <samuel.roze@gmail.com>
@@ -21,21 +19,23 @@
2119
*/
2220
abstract class AbstractHandlerLocator implements Handle 1CF5 rLocatorInterface
2321
{
24-
public function getHandler(Envelope $envelope): ?callable
22+
public function getHandler(string $topic): ?callable
2523
{
26-
$class = \get_class($envelope->getMessage());
27-
28-
if ($handler = $this->getHandlerByName($class)) {
24+
if ($handler = $this->getHandlerByName($topic)) {
2925
return $handler;
3026
}
3127

32-
foreach (class_parents($class) as $name) {
28+
if (!\class_exists($topic) && !\interface_exists($topic)) {
29+
return null;
30+
}
31+
32+
foreach (class_parents($topic) as $name) {
3333
if ($handler = $this->getHandlerByName($name)) {
3434
return $handler;
3535
}
3636
}
3737

38-
foreach (class_implements($class) as $name) {
38+
foreach (class_implements($topic) as $name) {
3939
if ($handler = $this->getHandlerByName($name)) {
4040
return $handler;
4141
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
namespace Symfony\Component\Messenger\Handler\Locator;
1313

14-
use Symfony\Component\Messenger\Envelope;
15-
1614
/**
1715
* @author Samuel Roze <samuel.roze@gmail.com>
1816
*/
@@ -21,5 +19,5 @@ interface HandlerLocatorInterface
2119
/**
2220
* Returns the handler for the given message.
2321
*/
24-
public function getHandler(Envelope $envelope): ?callable;
22+
public function getHandler(string $topic): ?callable;
2523
}

src/Symfony/Component/Messenger/MessageBus.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ public function getIterator()
5050
/**
5151
* {@inheritdoc}
5252
*/
53-
public function dispatch($message): Envelope
53+
public function dispatch($message, string $topic = null): Envelope
5454
{
5555
if (!\is_object($message)) {
5656
throw new \TypeError(sprintf('Invalid argument provided to "%s()": expected object, but got %s.', __METHOD__, \gettype($message)));
5757
}
58-
$envelope = $message instanceof Envelope ? $message : new Envelope($message);
58+
$envelope = Envelope::wrap($message, $topic);
5959
$middlewareIterator = $this->middlewareAggregate->getIterator();
6060

6161
while ($middlewareIterator instanceof \IteratorAggregate) {

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 $topic The topic that senders and/or handlers can subscribe to to get the message;
24+
* if not provided, the topic is the class of the message
2325
*/
24-
public function dispatch($message): Envelope;
26+
public function dispatch($message, string $topic = null): Envelope;
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, StackInterface $stack): Envelope
3838
{
39-
if (null !== $handler = $this->messageHandlerLocator->getHandler($envelope)) {
39+
if (null !== $handler = $this->messageHandlerLocator->getHandler($envelope->getTopic())) {
4040
$handler($envelope->getMessage());
4141
} elseif (!$this->allowNoHandlers) {
4242
throw new NoHandlerForMessageException(sprintf('No handler for message "%s".', \get_class($envelope->getMessage())));

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

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

4141
try {
4242
$envelope = $stack->next()->handle($envelope, $stack);
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 "{topic}"', $context);
4646

4747
throw $e;
4848
}
4949

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

5252
return $envelope;
5353
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope
4141
return $stack->next()->handle($envelope, $stack);
4242
}
4343

44-
$sender = $this->senderLocator->getSender($envelope);
44+
$sender = $this->senderLocator->getSender($envelope->getTopic());
4545

4646
if ($sender) {
4747
$envelope = $sender->send($envelope);
4848

49-
if (!AbstractSenderLocator::getValueFromMessageRouting($this->messagesToSendAndHandleMapping, $envelope)) {
49+
if (!AbstractSenderLocator::getValueFromMessageRouting($this->messagesToSendAndHandleMapping, $envelope->getTopic())) {
5050
// message has no corresponding handler
5151
return $envelope;
5252
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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 topic that senders and/or handlers can subscribe to to get a message.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*/
19+
final class TopicStamp implements StampInterface
20+
{
21+
private $name;
22+
23+
public function __construct(string $name)
24+
{
25+
$this->name = $name;
26+
}
27+
28+
public function getName()
29+
{
30+
return $this->name;
31+
}
32+
}

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 testGetHandlerViaTopic()
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
@@ -142,7 +142,7 @@ public function __construct(?SenderInterface $sender)
142142
$this->sender = $sender;
143143
}
144144

145-
public function getSender(Envelope $envelope): ?SenderInterface
145+
public function getSender(string $topic): ?SenderInterface
146146
{
147147
return $this->sender;
148148
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
$receiver = new AmqpReceiver($connection, $serializer);
3131

3232
$worker = new Worker($receiver, new class() implements MessageBusInterface {
33-
public function dispatch($envelope): Envelope
33+
public function dispatch($envelope, string $topic = null): Envelope
3434
{
35-
echo 'Get envelope with message: '.get_class($envelope->getMessage())."\n";
35+
$envelope = Envelope::wrap($message, $topic);
36+
echo 'Get envelope with message: '.$envelope->getTopic()."\n";
3637
echo sprintf("with stamps: %s\n", json_encode(array_keys($envelope->all()), JSON_PRETTY_PRINT));
3738

3839
sleep(30);

src/Symfony/Component/Messenger/Tests/Transport/Sender/Locator/ContainerSenderLocatorTest.php

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\DependencyInjection\Container;
16-
use Symfony\Component\Messenger\Envelope;
1716
use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage;
1817
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
1918
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterface;
@@ -33,8 +32,8 @@ public function testItReturnsTheSenderBasedOnTheMessageClass()
3332
DummyMessage::class => 'my_amqp_sender',
3433
));
3534

36-
$this->assertSame($sender, $locator->getSender(new Envelope(new DummyMessage('Hello'))));
37-
$this->assertNull($locator->getSender(new Envelope(new SecondMessage())));
35+
$this->assertSame($sender, $locator->getSender(DummyMessage::class));
36+
$this->assertNull($locator->getSender(SecondMessage::class));
3837
}
3938

4039
public function testItReturnsTheSenderBasedOnTheMessageParentClass()
@@ -52,8 +51,8 @@ public function testItReturnsTheSenderBasedOnTheMessageParentClass()
5251
DummyMessage::class => 'my_amqp_sender',
5352
));
5453

55-
$this->assertSame($sender, $locator->getSender(new Envelope(new ChildDummyMessage('Hello'))));
56-
$this->assertNull($locator->getSender(new Envelope(new SecondMessage())));
54+
$this->assertSame($sender, $locator->getSender(ChildDummyMessage::class));
55+
$this->assertNull($locator->getSender(SecondMessage::class));
5756
}
5857

5958
public function testItReturnsTheSenderBasedOnTheMessageInterface()
@@ -67,8 +66,21 @@ public function testItReturnsTheSenderBasedOnTheMessageInterface()
6766
DummyMessageInterface::class => 'my_amqp_sender',
6867
));
6968

70-
$this->assertSame($sender, $locator->getSender(new Envelope(new DummyMessage('Hello'))));
71-
$this->assertNull($locator->getSender(new Envelope(new SecondMessage())));
69+
$this->assertSame($sender, $locator->getSender(DummyMessage::class));
70+
$this->assertNull($locator->getSender(SecondMessage::class));
71+
}
72+
73+
public function testItReturnsTheSenderBasedOnTheTopic()
74+
{
75+
$container = new Container();
76+
$container->set('my_amqp_sender1', $sender1 = $this->getMockBuilder(SenderInterface::class)->getMock());
77+
$container->set('my_amqp_sender2', $sender2 = $this->getMockBuilder(SenderInterface::class)->getMock());
78+
79+
$locator = new ContainerSenderLocator($container, array(
80+
DummyMessageInterface::class => 'my_amqp_sender1',
81+
'foo' => 'my_amqp_sender2',
82+
));
83+
$this->assertSame($sender2, $locator->getSender('foo'));
7284
}
7385

7486
public function testItSupportsAWildcardInsteadOfTheMessageClass()
@@ -86,7 +98,7 @@ public function testItSupportsAWildcardInsteadOfTheMessageClass()
8698
'*' => 'my_api_sender',
8799
));
88100

89-
$this->assertSame($sender, $locator->getSender(new Envelope(new DummyMessage('Hello'))));
90-
$this->assertSame($apiSender, $locator->getSender(new Envelope(new SecondMessage())));
101+
$this->assertSame($sender, $locator->getSender(DummyMessage::class));
102+
$this->assertSame($apiSender, $locator->getSender(SecondMessage::class));
91103
}
92104
}

0 commit comments

Comments
 (0)
0