Skip to content

Commit e7af7ec

Browse files
committed
minor #27002 [Messenger] implement several senders using a ChainSender (Tobion)
This PR was merged into the 4.1 branch. Discussion ---------- [Messenger] implement several senders using a ChainSender | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | | License | MIT | Doc PR | Commits ------- 198925ee4e [Messenger] implement several senders using a ChainSender
2 parents 5993728 + 2585050 commit e7af7ec

File tree

6 files changed

+158
-76
lines changed

6 files changed

+158
-76
lines changed

Asynchronous/Middleware/SendMessageMiddleware.php

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

1212
namespace Symfony\Component\Messenger\Asynchronous\Middleware;
1313

14+
use Symfony\Component\Messenger\Asynchronous\Routing\SenderLocator;
1415
use Symfony\Component\Messenger\Asynchronous\Routing\SenderLocatorInterface;
1516
use Symfony\Component\Messenger\Asynchronous\Transport\ReceivedMessage;
1617
use Symfony\Component\Messenger\Envelope;
@@ -19,14 +20,17 @@
1920

2021
/**
2122
* @author Samuel Roze <samuel.roze@gmail.com>
23+
* @author Tobias Schultze <http://tobion.de>
2224
*/
2325
class SendMessageMiddleware implements MiddlewareInterface, EnvelopeAwareInterface
2426
{
2527
private $senderLocator;
28+
private $messagesToSendAndHandleMapping;
2629

27-
public function __construct(SenderLocatorInterface $senderLocator)
30+
public function __construct(SenderLocatorInterface $senderLocator, array $messagesToSendAndHandleMapping = array())
2831
{
2932
$this->senderLocator = $senderLocator;
33+
$this->messagesToSendAndHandleMapping = $messagesToSendAndHandleMapping;
3034
}
3135

3236
/**
@@ -40,20 +44,21 @@ public function handle($message, callable $next)
4044
return $next($message);
4145
}
4246

43-
if (!empty($senders = $this->senderLocator->getSendersForMessage($envelope->getMessage()))) {
44-
foreach ($senders as $sender) {
45-
if (null === $sender) {
46-
continue;
47-
}
47+
$sender = $this->senderLocator->getSenderForMessage($envelope->getMessage());
4848

49-
$sender->send($envelope);
50-
}
49+
if ($sender) {
50+
$sender->send($envelope);
5151

52-
if (!\in_array(null, $senders, true)) {
52+
if (!$this->mustSendAndHandle($envelope->getMessage())) {
5353
return;
5454
}
5555
}
5656

5757
return $next($message);
5858
}
59+
60+
private function mustSendAndHandle($message): bool
61+
{
62+
return (bool) SenderLocator::getValueFromMessageRouting($this->messagesToSendAndHandleMapping, $message);
63+
}
5964
}

Asynchronous/Routing/SenderLocator.php

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,49 +12,55 @@
1212
namespace Symfony\Component\Messenger\Asynchronous\Routing;
1313

1414
use Psr\Container\ContainerInterface;
15+
use Symfony\Component\Messenger\Transport\SenderInterface;
1516

1617
/**
1718
* @author Samuel Roze <samuel.roze@gmail.com>
1819
*/
1920
class SenderLocator implements SenderLocatorInterface
2021
{
2122
private $senderServiceLocator;
22-
private $messageToSenderIdsMapping;
23+
private $messageToSenderIdMapping;
2324

24-
public function __construct(ContainerInterface $senderServiceLocator, array $messageToSenderIdsMapping)
25+
public function __construct(ContainerInterface $senderServiceLocator, array $messageToSenderIdMapping)
2526
{
2627
$this->senderServiceLocator = $senderServiceLocator;
27-
$this->messageToSenderIdsMapping = $messageToSenderIdsMapping;
28+
$this->messageToSenderIdMapping = $messageToSenderIdMapping;
2829
}
2930

3031
/**
3132
* {@inheritdoc}
3233
*/
33-
public function getSendersForMessage($message): array
34+
public function getSenderForMessage($message): ?SenderInterface
3435
{
35-
$senders = array();
36-
foreach ($this->getSenderIds($message) as $senderId) {
37-
$senders[] = $this->senderServiceLocator->get($senderId);
38-
}
36+
$senderId = $this->getSenderId($message);
37+
38+
return $senderId ? $this->senderServiceLocator->get($senderId) : null;
39+
}
3940

40-
return $senders;
41+
private function getSenderId($message): ?string
42+
{
43+
return self::getValueFromMessageRouting($this->messageToSenderIdMapping, $message);
4144
}
4245

43-
private function getSenderIds($message): array
46+
/**
47+
* @internal
48+
*/
49+
public static function getValueFromMessageRouting(array $mapping, $message)
4450
{
45-
if (isset($this->messageToSenderIdsMapping[\get_class($message)])) {
46-
return $this->messageToSenderIdsMapping[\get_class($message)];
51+
if (isset($mapping[\get_class($message)])) {
52+
return $mapping[\get_class($message)];
4753
}
48-
if ($messageToSenderIdsMapping = array_intersect_key($this->messageToSenderIdsMapping, class_parents($message))) {
49-
return current($messageToSenderIdsMapping);
54+
if ($parentsMapping = array_intersect_key($mapping, class_parents($message))) {
55+
return current($parentsMapping);
5056
}
51-
if ($messageToSenderIdsMapping = array_intersect_key($this->messageToSenderIdsMapping, class_implements($message))) {
52-
return current($messageToSenderIdsMapping);
57+
if ($interfaceMapping = array_intersect_key($mapping, class_implements($message))) {
58+
return current($interfaceMapping);
5359
}
54-
if (isset($this->messageToSenderIdsMapping['*'])) {
55-
return $this->messageToSenderIdsMapping['*'];
60+
if (isset($mapping['*'])) {
61+
return $mapping['*'];
5662
}
5763

58-
return array();
64+
return null;
5965
}
6066
}

Asynchronous/Routing/SenderLocatorInterface.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
/**
1717
* @author Samuel Roze <samuel.roze@gmail.com>
18+
* @author Tobias Schultze <http://tobion.de>
1819
*
1920
* @experimental in 4.1
2021
*/
@@ -25,7 +26,7 @@ interface SenderLocatorInterface
2526
*
2627
* @param object $message
2728
*
28-
* @return SenderInterface[]
29+
* @return SenderInterface|null
2930
*/
30-
public function getSendersForMessage($message): array;
31+
public function getSenderForMessage($message): ?SenderInterface;
3132
}

Tests/Asynchronous/Middleware/SendMessageMiddlewareTest.php

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
use Symfony\Component\Messenger\Asynchronous\Routing\SenderLocatorInterface;
1717
use Symfony\Component\Messenger\Asynchronous\Transport\ReceivedMessage;
1818
use Symfony\Component\Messenger\Envelope;
19+
use Symfony\Component\Messenger\Tests\Asynchronous\Routing\ChildDummyMessage;
1920
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
21+
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterface;
2022
use Symfony\Component\Messenger\Transport\SenderInterface;
2123

2224
class SendMessageMiddlewareTest extends TestCase
@@ -27,9 +29,7 @@ public function testItSendsTheMessageToAssignedSender()
2729
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
2830
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
2931

30-
$middleware = new SendMessageMiddleware(new InMemorySenderLocator(array(
31-
$sender,
32-
)));
32+
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender));
3333

3434
$sender->expects($this->once())->method('send')->with(Envelope::wrap($message));
3535
$next->expects($this->never())->method($this->anything());
@@ -43,26 +43,71 @@ public function testItSendsTheMessageToAssignedSenderWithPreWrappedMessage()
4343
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
4444
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
4545

46-
$middleware = new SendMessageMiddleware(new InMemorySenderLocator(array(
47-
$sender,
48-
)));
46+
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender));
4947

5048
$sender->expects($this->once())->method('send')->with($envelope);
5149
$next->expects($this->never())->method($this->anything());
5250

5351
$middleware->handle($envelope, $next);
5452
}
5553

56-
public function testItAlsoCallsTheNextMiddlewareIfASenderIsNull()
54+
public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageClass()
5755
{
5856
$message = new DummyMessage('Hey');
5957
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
6058
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
6159

62-
$middleware = new SendMessageMiddleware(new InMemorySenderLocator(array(
63-
$sender,
64-
null,
65-
)));
60+
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array(
61+
DummyMessage::class => true,
62+
));
63+
64+
$sender->expects($this->once())->method('send')->with(Envelope::wrap($message));
65+
$next->expects($this->once())->method($this->anything());
66+
67+
$middleware->handle($message, $next);
68+
}
69+
70+
public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageParentClass()
71+
{
72+
$message = new ChildDummyMessage('Hey');
73+
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
74+
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
75+
76+
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array(
77+
DummyMessage::class => true,
78+
));
79+
80+
$sender->expects($this->once())->method('send')->with(Envelope::wrap($message));
81+
$next->expects($this->once())->method($this->anything());
82+
83+
$middleware->handle($message, $next);
84+
}
85+
86+
public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageInterface()
87+
{
88+
$message = new DummyMessage('Hey');
89+
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
90+
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
91+
92+
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array(
93+
DummyMessageInterface::class => true,
94+
));
95+
96+
$sender->expects($this->once())->method('send')->with(Envelope::wrap($message));
97+
$next->expects($this->once())->method($this->anything());
98+
99+
$middleware->handle($message, $next);
100+
}
101+
102+
public function testItAlsoCallsTheNextMiddlewareBasedOnWildcard()
103+
{
104+
$message = new DummyMessage('Hey');
105+
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
106+
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
107+
108+
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array(
109+
'*' => true,
110+
));
66111

67112
$sender->expects($this->once())->method('send')->with(Envelope::wrap($message));
68113
$next->expects($this->once())->method($this->anything());
@@ -75,7 +120,7 @@ public function testItCallsTheNextMiddlewareWhenNoSenderForThisMessage()
75120
$message = new DummyMessage('Hey');
76121
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
77122

78-
$middleware = new SendMessageMiddleware(new InMemorySenderLocator(array()));
123+
$middleware = new SendMessageMiddleware(new InMemorySenderLocator(null));
79124

80125
$next->expects($this->once())->method($this->anything());
81126

@@ -89,9 +134,7 @@ public function testItSkipsReceivedMessages()
89134
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
90135
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
91136

92-
$middleware = new SendMessageMiddleware(new InMemorySenderLocator(array(
93-
$sender,
94-
)));
137+
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender));
95138

96139
$sender->expects($this->never())->method('send');
97140
$next->expects($this->once())->method('__invoke')->with($envelope);
@@ -102,15 +145,15 @@ public function testItSkipsReceivedMessages()
102145

103146
class InMemorySenderLocator implements SenderLocatorInterface
104147
{
105-
private $senders;
148+
private $sender;
106149

107-
public function __construct(array $senders)
150+
public function __construct(?SenderInterface $sender)
108151
{
109-
$this->senders = $senders;
152+
$this->sender = $sender;
110153
}
111154

112-
public function getSendersForMessage($message): array
155+
public function getSenderForMessage($message): ?SenderInterface
113156
{
114-
return $this->senders;
157+
return $this->sender;
115158
}
116159
}

Tests/Asynchronous/Routing/SenderLocatorTest.php

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,11 @@ public function testItReturnsTheSenderBasedOnTheMessageClass()
2828
$container->set('my_amqp_sender', $sender);
2929

3030
$locator = new SenderLocator($container, array(
31-
DummyMessage::class => array(
32-
'my_amqp_sender',
33-
),
31+
DummyMessage::class => 'my_amqp_sender',
3432
));
3533

36-
$this->assertSame(array($sender), $locator->getSendersForMessage(new DummyMessage('Hello')));
37-
$this->assertSame(array(), $locator->getSendersForMessage(new SecondMessage()));
34+
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
35+
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
3836
}
3937

4038
public function testItReturnsTheSenderBasedOnTheMessageParentClass()
@@ -48,15 +46,12 @@ public function testItReturnsTheSenderBasedOnTheMessageParentClass()
4846
$container->set('my_api_sender', $apiSender);
4947

5048
$locator = new SenderLocator($container, array(
51-
DummyMessageInterface::class => array(
52-
'my_api_sender',
53-
),
54-
DummyMessage::class => array(
55-
'my_amqp_sender',
56-
),
49+
DummyMessageInterface::class => 'my_api_sender',
50+
DummyMessage::class => 'my_amqp_sender',
5751
));
58-
$this->assertSame(array($sender), $locator->getSendersForMessage(new ChildDummyMessage('Hello')));
59-
$this->assertSame(array(), $locator->getSendersForMessage(new SecondMessage()));
52+
53+
$this->assertSame($sender, $locator->getSenderForMessage(new ChildDummyMessage('Hello')));
54+
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
6055
}
6156

6257
public function testItReturnsTheSenderBasedOnTheMessageInterface()
@@ -67,13 +62,11 @@ public function testItReturnsTheSenderBasedOnTheMessageInterface()
6762
$container->set('my_amqp_sender', $sender);
6863

6964
$locator = new SenderLocator($container, array(
70-
DummyMessageInterface::class => array(
71-
'my_amqp_sender',
72-
),
65+
DummyMessageInterface::class => 'my_amqp_sender',
7366
));
7467

75-
$this->assertSame(array($sender), $locator->getSendersForMessage(new DummyMessage('Hello')));
76-
$this->assertSame(array(), $locator->getSendersForMessage(new SecondMessage()));
68+
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
69+
$this->assertNull($locator->getSenderForMessage(new SecondMessage()));
7770
}
7871

7972
public function testItSupportsAWildcardInsteadOfTheMessageClass()
@@ -87,16 +80,12 @@ public function testItSupportsAWildcardInsteadOfTheMessageClass()
8780
$container->set('my_api_sender', $apiSender);
8881

8982
$locator = new SenderLocator($container, array(
90-
DummyMessage::class => array(
91-
'my_amqp_sender',
92-
),
93-
'*' => array(
94-
'my_api_sender',
95-
),
83+
DummyMessage::class => 'my_amqp_sender',
84+
'*' => 'my_api_sender',
9685
));
9786

98-
$this->assertSame(array($sender), $locator->getSendersForMessage(new DummyMessage('Hello')));
99-
$this->assertSame(array($apiSender), $locator->getSendersForMessage(new SecondMessage()));
87+
$this->assertSame($sender, $locator->getSenderForMessage(new DummyMessage('Hello')));
88+
$this->assertSame($apiSender, $locator->getSenderForMessage(new SecondMessage()));
10089
}
10190
}
10291

0 commit comments

Comments
 (0)