Skip to content

Commit b13bb37

Browse files
jderussenicolas-grekas
authored andcommitted
[Messenger] Added RouterContextMiddleware
1 parent a12db94 commit b13bb37

File tree

6 files changed

+225
-0
lines changed

6 files changed

+225
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
* Added the `dispatcher` option to `debug:event-dispatcher`
1111
* Added the `event_dispatcher.dispatcher` tag
1212
* Added `assertResponseFormatSame()` in `BrowserKitAssertionsTrait`
13+
* Added the `RouterContextMiddleware` to restore the original router context when handling a message
1314

1415
5.2.0
1516
-----

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,7 @@ private function registerRouterConfiguration(array $config, ContainerBuilder $co
944944
if (!$this->isConfigEnabled($container, $config)) {
945945
$container->removeDefinition('console.command.router_debug');
946946
$container->removeDefinition('console.command.router_match');
947+
$container->removeDefinition('messenger.middleware.router_context');
947948

948949
return;
949950
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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\Bundle\FrameworkBundle\Messenger;
13+
14+
use Symfony\Component\Messenger\Envelope;
15+
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
16+
use Symfony\Component\Messenger\Middleware\StackInterface;
17+
use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp;
18+
use Symfony\Component\Routing\RequestContext;
19+
use Symfony\Component\Routing\RequestContextAwareInterface;
20+
21+
/**
22+
* Restore the Router context when processing the message.
23+
*
24+
* @author Jérémy Derussé <jeremy@derusse.com>
25+
*/
26+
class RouterContextMiddleware implements MiddlewareInterface
27+
{
28+
private $router;
29+
30+
public function __construct(RequestContextAwareInterface $router)
31+
{
32+
$this->router = $router;
33+
}
34+
35+
public function handle(Envelope $envelope, StackInterface $stack): Envelope
36+
{
37+
if (!$envelope->last(ConsumedByWorkerStamp::class) || !$contextStamp = $envelope->last(RouterContextStamp::class)) {
38+
$context = $this->router->getContext();
39+
$envelope = $envelope->with(new RouterContextStamp(
40+
$context->getBaseUrl(),
41+
$context->getMethod(),
42+
$context->getHost(),
43+
$context->getScheme(),
44+
$context->getHttpPort(),
45+
$context->getHttpsPort(),
46+
$context->getPathInfo(),
47+
$context->getQueryString()
48+
));
49+
50+
return $stack->next()->handle($envelope, $stack);
51+
}
52+
53+
$currentContext = $this->router->getContext();
54+
55+
/* @var RouterContextStamp $contextStamp */
56+
$this->router->setContext(new RequestContext(
57+
$contextStamp->getBaseUrl(),
58+
$contextStamp->getMethod(),
59+
$contextStamp->getHost(),
60+
$contextStamp->getScheme(),
61+
$contextStamp->getHttpPort(),
62+
$contextStamp->getHttpsPort(),
63+
$contextStamp->getPathInfo(),
64+
$contextStamp->getQueryString()
65+
));
66+
67+
try {
68+
return $stack->next()->handle($envelope, $stack);
69+
} finally {
70+
$this->router->setContext($currentContext);
71+
}
72+
}
73+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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\Bundle\FrameworkBundle\Messenger;
13+
14+
use Symfony\Component\Messenger\Stamp\StampInterface;
15+
16+
/**
17+
* @author Jérémy Derussé <jeremy@derusse.com>
18+
*/
19+
class RouterContextStamp implements StampInterface
20+
{
21+
private $baseUrl;
22+
private $method;
23+
private $host;
24+
private $scheme;
25+
private $httpPort;
26+
private $httpsPort;
27+
private $pathInfo;
28+
private $queryString;
29+
30+
public function __construct(string $baseUrl, string $method, string $host, string $scheme, int $httpPort, int $httpsPort, string $pathInfo, string $queryString)
31+
{
32+
$this->baseUrl = $baseUrl;
33+
$this->method = $method;
34+
$this->host = $host;
35+
$this->scheme = $scheme;
36+
$this->httpPort = $httpPort;
37+
$this->httpsPort = $httpsPort;
38+
$this->pathInfo = $pathInfo;
39+
$this->queryString = $queryString;
40+
}
41+
42+
public function getBaseUrl(): string
43+
{
44+
return $this->baseUrl;
45+
}
46+
47+
public function getMethod(): string
48+
{
49+
return $this->method;
50+
}
51+
52+
public function getHost(): string
53+
{
54+
return $this->host;
55+
}
56+
57+
public function getScheme(): string
58+
{
59+
return $this->scheme;
60+
}
61+
62+
public function getHttpPort(): int
63+
{
64+
return $this->httpPort;
65+
}
66+
67+
public function getHttpsPort(): int
68+
{
69+
return $this->httpsPort;
70+
}
71+
72+
public function getPathInfo(): string
73+
{
74+
return $this->pathInfo;
75+
}
76+
77+
public function getQueryString(): string
78+
{
79+
return $this->queryString;
80+
}
81+
}

src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php

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

1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

14+
use Symfony\Bundle\FrameworkBundle\Messenger\RouterContextMiddleware;
1415
use Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsTransportFactory;
1516
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpTransportFactory;
1617
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdTransportFactory;
@@ -100,6 +101,11 @@
100101
service('debug.stopwatch'),
101102
])
102103

104+
->set('messenger.middleware.router_context', RouterContextMiddleware::class)
105+
->args([
106+
service('router'),
107+
])
108+
103109
// Discovery
104110
->set('messenger.receiver_locator')
105111
->args([
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\Tests\Routing;
4+
5+
use Symfony\Bundle\FrameworkBundle\Messenger\RouterContextMiddleware;
6+
use Symfony\Bundle\FrameworkBundle\Messenger\RouterContextStamp;
7+
use Symfony\Component\Messenger\Envelope;
8+
use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp;
9+
use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase;
10+
use Symfony\Component\Routing\RequestContext;
11+
use Symfony\Component\Routing\RequestContextAwareInterface;
12+
13+
class RouterContextMiddlewareTest extends MiddlewareTestCase
14+
{
15+
public function testMiddlewareStoreContext()
16+
{
17+
$context = RequestContext::fromUri('https://symfony.com');
18+
19+
$router = $this->createMock(RequestContextAwareInterface::class);
20+
$router
21+
->expects($this->once())
22+
->method('getContext')
23+
->willReturn($context);
24+
25+
$middleware = new RouterContextMiddleware($router);
26+
27+
$envelope = new Envelope(new \stdClass());
28+
$envelope = $middleware->handle($envelope, $this->getStackMock());
29+
30+
$this->assertNotNull($stamp = $envelope->last(RouterContextStamp::class));
31+
$this->assertSame('symfony.com', $stamp->getHost());
32+
}
33+
34+
public function testMiddlewareRestoreContext()
35+
{
36+
$router = $this->createMock(RequestContextAwareInterface::class);
37+
$originalContext = new RequestContext();
38+
39+
$router
40+
->expects($this->once())
41+
->method('getContext')
42+
->willReturn($originalContext);
43+
44+
$router
45+
->expects($this->exactly(2))
46+
->method('setContext')
47+
->withConsecutive(
48+
[$this->callback(function ($context) {
49+
$this->assertSame('symfony.com', $context->getHost());
50+
51+
return true;
52+
})],
53+
[$originalContext]
54+
);
55+
56+
$middleware = new RouterContextMiddleware($router);
57+
$envelope = new Envelope(new \stdClass(), [
58+
new ConsumedByWorkerStamp(),
59+
new RouterContextStamp('', 'GET', 'symfony.com', 'https', 80, 443, '/', ''),
60+
]);
61+
$middleware->handle($envelope, $this->getStackMock());
62+
}
63+
}

0 commit comments

Comments
 (0)