Skip to content

Commit ad01c29

Browse files
committed
Ensure the envelope is passed back and can be altered
Ensure that the middlewares can also update the message within the envelope
1 parent cd0aec9 commit ad01c29

File tree

3 files changed

+136
-5
lines changed

3 files changed

+136
-5
lines changed

src/Symfony/Component/Messenger/Envelope.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ public function with(EnvelopeItemInterface $item): self
5757
return $cloned;
5858
}
5959

60+
public function withMessage($message): self
61+
{
62+
$cloned = clone $this;
63+
64+
$cloned->message = $message;
65+
66+
return $cloned;
67+
}
68+
6069
public function get(string $itemFqcn): ?EnvelopeItemInterface
6170
{
6271
return $this->items[$itemFqcn] ?? null;

src/Symfony/Component/Messenger/MessageBus.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ public function __construct(iterable $middlewareHandlers = array())
3939
*/
4040
public function dispatch($message)
4141
{
42-
return \call_user_func($this->callableForNextMiddleware(0), $message);
42+
return \call_user_func($this->callableForNextMiddleware(0, Envelope::wrap($message)), $message);
4343
}
4444

45-
private function callableForNextMiddleware(int $index): callable
45+
private function callableForNextMiddleware(int $index, Envelope $currentEnvelope): callable
4646
{
4747
if (null === $this->indexedMiddlewareHandlers) {
4848
$this->indexedMiddlewareHandlers = \is_array($this->middlewareHandlers) ? array_values($this->middlewareHandlers) : iterator_to_array($this->middlewareHandlers, false);
@@ -54,14 +54,19 @@ private function callableForNextMiddleware(int $index): callable
5454

5555
$middleware = $this->indexedMiddlewareHandlers[$index];
5656

57-
return function ($message) use ($middleware, $index) {
58-
$message = Envelope::wrap($message);
57+
return function ($message) use ($middleware, $index, $currentEnvelope) {
58+
if ($message instanceof Envelope) {
59+
$currentEnvelope = $message;
60+
} else {
61+
$message = $currentEnvelope->withMessage($message);
62+
}
63+
5964
if (!$middleware instanceof EnvelopeAwareInterface) {
6065
// Do not provide the envelope if the middleware cannot read it:
6166
$message = $message->getMessage();
6267
}
6368

64-
return $middleware->handle($message, $this->callableForNextMiddleware($index + 1));
69+
return $middleware->handle($message, $this->callableForNextMiddleware($index + 1, $currentEnvelope));
6570
};
6671
}
6772
}

src/Symfony/Component/Messenger/Tests/MessageBusTest.php

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

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Messenger\Asynchronous\Transport\ReceivedMessage;
16+
use Symfony\Component\Messenger\Envelope;
17+
use Symfony\Component\Messenger\EnvelopeAwareInterface;
18+
use Symfony\Component\Messenger\EnvelopeItemInterface;
1519
use Symfony\Component\Messenger\MessageBus;
1620
use Symfony\Component\Messenger\MessageBusInterface;
1721
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
@@ -52,4 +56,117 @@ public function testItCallsMiddlewareAndChainTheReturnValue()
5256

5357
$this->assertEquals($responseFromDepthMiddleware, $bus->dispatch($message));
5458
}
59+
60+
public function testItKeepsTheEnvelopeEvenThroughAMiddlewareThatIsNotEnvelopeAware()
61+
{
62+
$message = new DummyMessage('Hello');
63+
$envelope = new Envelope($message, array(new ReceivedMessage()));
64+
65+
$firstMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
66+
$firstMiddleware->expects($this->once())
67+
->method('handle')
68+
->with($message, $this->anything())
69+
->will($this->returnCallback(function ($message, $next) {
70+
return $next($message);
71+
}));
72+
73+
$secondMiddleware = $this->getMockBuilder(array(MiddlewareInterface::class, EnvelopeAwareInterface::class))->getMock();
74+
$secondMiddleware->expects($this->once())
75+
->method('handle')
76+
->with($envelope, $this->anything())
77+
;
78+
79+
$bus = new MessageBus(array(
80+
$firstMiddleware,
81+
$secondMiddleware,
82+
));
83+
84+
$bus->dispatch($envelope);
85+
}
86+
87+
public function testThatAMiddlewareCanAddSomeItemsToTheEnvelope()
88+
{
89+
$message = new DummyMessage('Hello');
90+
$envelope = new Envelope($message, array(new ReceivedMessage()));
91+
$envelopeWithAnotherItem = $envelope->with(new AnEnvelopeItem());
92+
93+
$firstMiddleware = $this->getMockBuilder(array(MiddlewareInterface::class, EnvelopeAwareInterface::class))->getMock();
94+
$firstMiddleware->expects($this->once())
95+
->method('handle')
96+
->with($envelope, $this->anything())
97+
->will($this->returnCallback(function ($message, $next) {
98+
return $next($message->with(new AnEnvelopeItem()));
99+
}));
100+
101+
$secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
102+
$secondMiddleware->expects($this->once())
103+
->method('handle')
104+
->with($message, $this->anything())
105+
->will($this->returnCallback(function ($message, $next) {
106+
return $next($message);
107+
}));
108+
109+
$thirdMiddleware = $this->getMockBuilder(array(MiddlewareInterface::class, EnvelopeAwareInterface::class))->getMock();
110+
$thirdMiddleware->expects($this->once())
111+
->method('handle')
112+
->with($envelopeWithAnotherItem, $this->anything())
113+
;
114+
115+
$bus = new MessageBus(array(
116+
$firstMiddleware,
117+
$secondMiddleware,
118+
$thirdMiddleware,
119+
));
120+
121+
$bus->dispatch($envelope);
122+
}
123+
124+
public function testThatAMiddlewareCanUpdateTheMessageWhileKeepingTheEnvelopeItems()
125+
{
126+
$message = new DummyMessage('Hello');
127+
$envelope = new Envelope($message, $items = array(new ReceivedMessage()));
128+
129+
$changedMessage = new DummyMessage('Changed');
130+
$expectedEnvelope = new Envelope($changedMessage, $items);
131+
132+
$firstMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
133+
$firstMiddleware->expects($this->once())
134+
->method('handle')
135+
->with($message, $this->anything())
136+
->will($this->returnCallback(function ($message, $next) use ($changedMessage) {
137+
return $next($changedMessage);
138+
}));
139+
140+
$secondMiddleware = $this->getMockBuilder(array(MiddlewareInterface::class, EnvelopeAwareInterface::class))->getMock();
141+
$secondMiddleware->expects($this->once())
142+
->method('handle')
143+
->with($expectedEnvelope, $this->anything())
144+
;
145+
146+
$bus = new MessageBus(array(
147+
$firstMiddleware,
148+
$secondMiddleware,
149+
));
150+
151+
$bus->dispatch($envelope);
152+
}
153+
}
154+
155+
class AnEnvelopeItem implements EnvelopeItemInterface
156+
{
157+
/**
158+
* {@inheritdoc}
159+
*/
160+
public function serialize()
161+
{
162+
return '';
163+
}
164+
165+
/**
166+
* {@inheritdoc}
167+
*/
168+
public function unserialize($serialized)
169+
{
170+
return new self();
171+
}
55172
}

0 commit comments

Comments
 (0)