Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 38326a7

Browse files
[Messenger] Add StackInterface, allowing to unstack the call stack
1 parent 5ae0e89 commit 38326a7

21 files changed

+234
-155
lines changed

src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Doctrine\ORM\EntityManagerInterface;
1616
use Symfony\Component\Messenger\Envelope;
1717
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
18+
use Symfony\Component\Messenger\Middleware\StackInterface;
1819

1920
/**
2021
* Wraps all handlers in a single doctrine transaction.
@@ -35,7 +36,7 @@ public function __construct(ManagerRegistry $managerRegistry, ?string $entityMan
3536
/**
3637
* {@inheritdoc}
3738
*/
38-
public function handle(Envelope $envelope, callable $next): void
39+
public function handle(Envelope $envelope, StackInterface $stack): void
3940
{
4041
$entityManager = $this->managerRegistry->getManager($this->entityManagerName);
4142

@@ -45,7 +46,7 @@ public function handle(Envelope $envelope, callable $next): void
4546

4647
$entityManager->getConnection()->beginTransaction();
4748
try {
48-
$next($envelope);
49+
$stack->next()->handle($envelope, $stack);
4950
$entityManager->flush();
5051
$entityManager->getConnection()->commit();
5152
} catch (\Throwable $exception) {

src/Symfony/Component/Messenger/CHANGELOG.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ CHANGELOG
77
* The component is not experimental anymore
88
* All the changes below are BC BREAKS
99
* `MessageBusInterface::dispatch()` and `MiddlewareInterface::handle()` now return `void`
10-
* `MiddlewareInterface::handle()` now require an `Envelope` as first argument
10+
* `MiddlewareInterface::handle()` now require an `Envelope` as first argument and a `StackInterface` as second
1111
* `EnvelopeAwareInterface` has been removed
1212
* The signature of `Amqp*` classes changed to take a `Connection` as a first argument and an optional
1313
`Serializer` as a second argument.
@@ -16,7 +16,6 @@ CHANGELOG
1616
Instead, it accepts the sender instance itself instead of its identifier in the container.
1717
* `MessageSubscriberInterface::getHandledMessages()` return value has changed. The value of an array item
1818
needs to be an associative array or the method name.
19-
* `ValidationMiddleware::handle()` and `SendMessageMiddleware::handle()` now require an `Envelope` object
2019
* `StampInterface` replaces `EnvelopeItemInterface` and doesn't extend `Serializable` anymore
2120
* The `ConsumeMessagesCommand` class now takes an instance of `Psr\Container\ContainerInterface`
2221
as first constructor argument

src/Symfony/Component/Messenger/MessageBus.php

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

1414
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
15+
use Symfony\Component\Messenger\Middleware\StackMiddleware;
1516

1617
/**
1718
* @author Samuel Roze <[email protected]>
@@ -64,14 +65,8 @@ public function dispatch($message): void
6465
if (!$middlewareIterator->valid()) {
6566
return;
6667
}
67-
$next = static function (Envelope $envelope) use ($middlewareIterator, &$next) {
68-
$middlewareIterator->next();
68+
$stack = new StackMiddleware($middlewareIterator);
6969

70-
if ($middlewareIterator->valid()) {
71-
$middlewareIterator->current()->handle($envelope, $next);
72-
}
73-
};
74-
75-
$middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $next);
70+
$middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $stack);
7671
}
7772
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ public function __construct(MiddlewareInterface $inner, $activated)
3535
/**
3636
* {@inheritdoc}
3737
*/
38-
public function handle(Envelope $envelope, callable $next): void
38+
public function handle(Envelope $envelope, StackInterface $stack): void
3939
{
4040
if (\is_callable($this->activated) ? ($this->activated)($envelope) : $this->activated) {
41-
$this->inner->handle($envelope, $next);
41+
$this->inner->handle($envelope, $stack);
4242
} else {
43-
$next($envelope);
43+
$stack->next()->handle($envelope, $stack);
4444
}
4545
}
4646
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ public function __construct(HandlerLocatorInterface $messageHandlerLocator, bool
3434
*
3535
* @throws NoHandlerForMessageException When no handler is found and $allowNoHandlers is false
3636
*/
37-
public function handle(Envelope $envelope, callable $next): void
37+
public function handle(Envelope $envelope, StackInterface $stack): void
3838
{
3939
if (null !== $handler = $this->messageHandlerLocator->getHandler($envelope)) {
4040
$handler($envelope->getMessage());
41-
$next($envelope);
41+
$stack->next()->handle($envelope, $stack);
4242
} elseif (!$this->allowNoHandlers) {
4343
throw new NoHandlerForMessageException(sprintf('No handler for message "%s".', \get_class($envelope->getMessage())));
4444
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function __construct(LoggerInterface $logger)
2929
/**
3030
* {@inheritdoc}
3131
*/
32-
public function handle(Envelope $envelope, callable $next): void
32+
public function handle(Envelope $envelope, StackInterface $stack): void
3333
{
3434
$message = $envelope->getMessage();
3535
$context = array(
@@ -39,7 +39,7 @@ public function handle(Envelope $envelope, callable $next): void
3939
$this->logger->debug('Starting handling message {name}', $context);
4040

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

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

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,5 @@
1818
*/
1919
interface MiddlewareInterface
2020
{
21-
/**
22-
* @param callable|NextInterface $next
23-
*/
24-
public function handle(Envelope $envelope, callable $next): void;
25-
}
26-
27-
/**
28-
* @internal
29-
*/
30-
interface NextInterface
31-
{
32-
public function __invoke(Envelope $envelope): void;
21+
public function handle(Envelope $envelope, StackInterface $stack): void;
3322
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ public function __construct(SenderLocatorInterface $senderLocator, array $messag
3434
/**
3535
* {@inheritdoc}
3636
*/
37-
public function handle(Envelope $envelope, callable $next): void
37+
public function handle(Envelope $envelope, StackInterface $stack): void
3838
{
3939
if ($envelope->get(ReceivedStamp::class)) {
4040
// It's a received message. Do not send it back:
41-
$next($envelope);
41+
$stack->next()->handle($envelope, $stack);
4242

4343
return;
4444
}
@@ -54,6 +54,6 @@ public function handle(Envelope $envelope, callable $next): void
5454
}
5555
}
5656

57-
$next($envelope);
57+
$stack->next()->handle($envelope, $stack);
5858
}
5959
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Middleware;
13+
14+
use Symfony\Component\Messenger\Envelope;
15+
16+
/**
17+
* @author Nicolas Grekas <[email protected]>
18+
*/
19+
interface StackInterface
20+
{
21+
/**
22+
* Returns the next middleware to process a message.
23+
*/
24+
public function next(): MiddlewareInterface;
25+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Middleware;
13+
14+
use Symfony\Component\Messenger\Envelope;
15+
16+
/**
17+
* @author Nicolas Grekas <[email protected]>
18+
*/
19+
class StackMiddleware implements MiddlewareInterface, StackInterface
20+
{
21+
private $middlewareIterator;
22+
23+
public function __construct(\Iterator $middlewareIterator = null)
24+
{
25+
$this->middlewareIterator = $middlewareIterator;
26+
}
27+
28+
public function next(): MiddlewareInterface
29+
{
30+
if (null === $iterator = $this->middlewareIterator) {
31+
return $this;
32+
}
33+
$iterator->next();
34+
35+
if (!$iterator->valid()) {
36+
$this->middlewareIterator = null;
37+
38+
return $this;
39+
}
40+
41+
return $iterator->current();
42+
}
43+
44+
public function handle(Envelope $envelope, StackInterface $stack): void
45+
{
46+
// no-op
47+
}
48+
}

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

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function __construct(MiddlewareInterface $inner, Stopwatch $stopwatch, st
3737
/**
3838
* {@inheritdoc}
3939
*/
40-
public function handle(Envelope $envelope, callable $next): void
40+
public function handle(Envelope $envelope, StackInterface $stack): void
4141
{
4242
$class = \get_class($this->inner);
4343
$eventName = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
@@ -49,15 +49,52 @@ public function handle(Envelope $envelope, callable $next): void
4949
$this->stopwatch->start($eventName, $this->eventCategory);
5050

5151
try {
52-
$this->inner->handle($envelope, function (Envelope $envelope) use ($next, $eventName) {
53-
$this->stopwatch->stop($eventName);
54-
$next($envelope);
55-
$this->stopwatch->start($eventName, $this->eventCategory);
56-
});
52+
$this->inner->handle($envelope, new TraceableInnerMiddleware($stack, $this->stopwatch, $eventName, $this->eventCategory));
5753
} finally {
5854
if ($this->stopwatch->isStarted($eventName)) {
5955
$this->stopwatch->stop($eventName);
6056
}
6157
}
6258
}
6359
}
60+
61+
/**
62+
* @internal
63+
*/
64+
class TraceableInnerMiddleware implements MiddlewareInterface, StackInterface
65+
{
66+
private $stack;
67+
private $stopwatch;
68+
private $eventName;
69+
private $eventCategory;
70+
71+
public function __construct(StackInterface $stack, Stopwatch $stopwatch, string $eventName, string $eventCategory)
72+
{
73+
$this->stack = $stack;
74+
$this->stopwatch = $stopwatch;
75+
$this->eventName = $eventName;
76+
$this->eventCategory = $eventCategory;
77+
}
78+
79+
/**
80+
* {@inheritdoc}
81+
*/
82+
public function handle(Envelope $envelope, StackInterface $stack): void
83+
{
84+
$this->stopwatch->stop($this->eventName);
85+
if ($this === $stack) {
86+
$this->stack->next()->handle($envelope, $this->stack);
87+
} else {
88+
$this->stack->next()->handle($envelope, $stack);
89+
}
90+
$this->stopwatch->start($this->eventName, $this->eventCategory);
91+
}
92+
93+
/**
94+
* {@inheritdoc}
95+
*/
96+
public function next(): MiddlewareInterface
97+
{
98+
return $this;
99+
}
100+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function __construct(ValidatorInterface $validator)
3131
/**
3232
* {@inheritdoc}
3333
*/
34-
public function handle(Envelope $envelope, callable $next): void
34+
public function handle(Envelope $envelope, StackInterface $stack): void
3535
{
3636
$message = $envelope->getMessage();
3737
$groups = null;
@@ -45,6 +45,6 @@ public function handle(Envelope $envelope, callable $next): void
4545
throw new ValidationFailedException($message, $violations);
4646
}
4747

48-
$next($envelope);
48+
$stack->next()->handle($envelope, $stack);
4949
}
5050
}

src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Symfony\Component\Messenger\MessageBusInterface;
3030
use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware;
3131
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
32+
use Symfony\Component\Messenger\Middleware\StackInterface;
3233
use Symfony\Component\Messenger\Tests\Fixtures\DummyCommand;
3334
use Symfony\Component\Messenger\Tests\Fixtures\DummyCommandHandler;
3435
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
@@ -846,8 +847,8 @@ public function dummyMethodForSomeBus()
846847

847848
class UselessMiddleware implements MiddlewareInterface
848849
{
849-
public function handle(Envelope $message, callable $next): void
850+
public function handle(Envelope $message, StackInterface $stack): void
850851
{
851-
$next($message);
852+
$stack->next()->handle($message, $stack);
852853
}
853854
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ public function testItCallsMiddleware()
4848
$firstMiddleware->expects($this->once())
4949
->method('handle')
5050
->with($envelope, $this->anything())
51-
->will($this->returnCallback(function ($envelope, $next) {
52-
$next($envelope);
51+
->will($this->returnCallback(function ($envelope, $stack) {
52+
$stack->next()->handle($envelope, $stack);
5353
}));
5454

5555
$secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
@@ -76,16 +76,16 @@ public function testThatAMiddlewareCanAddSomeStampsToTheEnvelope()
7676
$firstMiddleware->expects($this->once())
7777
->method('handle')
7878
->with($envelope, $this->anything())
79-
->will($this->returnCallback(function ($envelope, $next) {
80-
$next($envelope->with(new AnEnvelopeStamp()));
79+
->will($this->returnCallback(function ($envelope, $stack) {
80+
$stack->next()->handle($envelope->with(new AnEnvelopeStamp()), $stack);
8181
}));
8282

8383
$secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
8484
$secondMiddleware->expects($this->once())
8585
->method('handle')
8686
->with($envelopeWithAnotherStamp, $this->anything())
87-
->will($this->returnCallback(function ($envelope, $next) {
88-
$next($envelope);
87+
->will($this->returnCallback(function ($envelope, $stack) {
88+
$stack->next()->handle($envelope, $stack);
8989
}));
9090

9191
$thirdMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
@@ -115,8 +115,8 @@ public function testThatAMiddlewareCanUpdateTheMessageWhileKeepingTheEnvelopeSta
115115
$firstMiddleware->expects($this->once())
116116
->method('handle')
117117
->with($envelope, $this->anything())
118-
->will($this->returnCallback(function ($message, $next) use ($expectedEnvelope) {
119-
$next($expectedEnvelope);
118+
->will($this->returnCallback(function ($envelope, $stack) use ($expectedEnvelope) {
119+
$stack->next()->handle($expectedEnvelope, $stack);
120120
}));
121121

122122
$secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();

0 commit comments

Comments
 (0)