Skip to content

Commit 6933508

Browse files
committed
Ensure the server negotiator has a response factory
1 parent 8faac7f commit 6933508

5 files changed

Lines changed: 103 additions & 0 deletions

File tree

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"doctrine/dbal": "^3.4 || ^4.0",
2929
"doctrine/doctrine-bundle": "^2.7",
3030
"fig/log-test": "^1.1",
31+
"guzzlehttp/psr7": "^2.4",
3132
"matthiasnoback/symfony-config-test": "^5.1",
3233
"matthiasnoback/symfony-dependency-injection-test": "^5.1",
3334
"phpstan/extension-installer": "^1.2",
@@ -37,6 +38,7 @@
3738
"phpunit/phpunit": "9.6.22",
3839
"psr/cache": "^1.0 || ^2.0 || ^3.0",
3940
"psr/container": "^1.0 || ^2.0",
41+
"psr/http-message": "^1.0 || ^2.0",
4042
"psr/log": "^1.0 || ^2.0 || ^3.0",
4143
"ratchet/rfc6455": "^0.4",
4244
"react/event-loop": "^1.5",
@@ -50,6 +52,7 @@
5052
"doctrine/doctrine-bundle": "<2.7 || >=3.0",
5153
"psr/cache": ">=4.0",
5254
"psr/container": ">=3.0",
55+
"psr/http-message": ">=3.0",
5356
"psr/log": ">=4.0",
5457
"ratchet/rfc6455": "<0.4 || >=0.5",
5558
"react/event-loop": "<1.5 || >=2.0",

config/services.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
$services->set('babdev_websocket_server.rfc6455.server_negotiator', ServerNegotiator::class)
165165
->args([
166166
inline_service(RequestVerifier::class),
167+
abstract_arg('response factory'),
167168
])
168169
;
169170

src/BabDevWebSocketBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use BabDev\WebSocketBundle\DependencyInjection\BabDevWebSocketExtension;
66
use BabDev\WebSocketBundle\DependencyInjection\Compiler\BuildMiddlewareStackCompilerPass;
7+
use BabDev\WebSocketBundle\DependencyInjection\Compiler\ConfigureHttpFactoriesCompilerPass;
78
use BabDev\WebSocketBundle\DependencyInjection\Compiler\PingDBALConnectionsCompilerPass;
89
use BabDev\WebSocketBundle\DependencyInjection\Compiler\RoutingResolverCompilerPass;
910
use BabDev\WebSocketBundle\DependencyInjection\Factory\Authentication\SessionAuthenticationProviderFactory;
@@ -16,6 +17,7 @@ final class BabDevWebSocketBundle extends Bundle
1617
public function build(ContainerBuilder $container): void
1718
{
1819
$container->addCompilerPass(new BuildMiddlewareStackCompilerPass());
20+
$container->addCompilerPass(new ConfigureHttpFactoriesCompilerPass());
1921
$container->addCompilerPass(new PingDBALConnectionsCompilerPass());
2022
$container->addCompilerPass(new RoutingResolverCompilerPass());
2123

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace BabDev\WebSocketBundle\DependencyInjection\Compiler;
4+
5+
use GuzzleHttp\Psr7\HttpFactory;
6+
use Psr\Http\Message\ResponseFactoryInterface;
7+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
8+
use Symfony\Component\DependencyInjection\ContainerBuilder;
9+
use Symfony\Component\DependencyInjection\Reference;
10+
11+
/**
12+
* Configures PSR-17 factories for services which require one.
13+
*
14+
* @internal
15+
*/
16+
final class ConfigureHttpFactoriesCompilerPass implements CompilerPassInterface
17+
{
18+
public function process(ContainerBuilder $container): void
19+
{
20+
$this->processServerNegotiator($container);
21+
}
22+
23+
private function processServerNegotiator(ContainerBuilder $container): void
24+
{
25+
if (!$container->hasDefinition('babdev_websocket_server.rfc6455.server_negotiator')) {
26+
return;
27+
}
28+
29+
// Based on the Flex recipes, if the application already has a response factory service, we'll prefer that
30+
if ($container->has(ResponseFactoryInterface::class)) {
31+
$container->getDefinition('babdev_websocket_server.rfc6455.server_negotiator')
32+
->replaceArgument(1, new Reference(ResponseFactoryInterface::class));
33+
34+
return;
35+
}
36+
37+
// Since the `guzzle/psr7` package is a hard requirement of the server library, we'll use that as a fallback
38+
$container->getDefinition('babdev_websocket_server.rfc6455.server_negotiator')
39+
->replaceArgument(1, $container->register('.babdev_websocket_server.psr17_response_factory', HttpFactory::class));
40+
}
41+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace BabDev\WebSocketBundle\Tests\DependencyInjection\Compiler;
4+
5+
use BabDev\WebSocketBundle\DependencyInjection\Compiler\ConfigureHttpFactoriesCompilerPass;
6+
use GuzzleHttp\Psr7\HttpFactory;
7+
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractCompilerPassTestCase;
8+
use Psr\Http\Message\ResponseFactoryInterface;
9+
use Ratchet\RFC6455\Handshake\RequestVerifier;
10+
use Ratchet\RFC6455\Handshake\ServerNegotiator;
11+
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
12+
use Symfony\Component\DependencyInjection\ContainerBuilder;
13+
use Symfony\Component\DependencyInjection\Definition;
14+
use Symfony\Component\DependencyInjection\Reference;
15+
16+
final class ConfigureHttpFactoriesCompilerPassTest extends AbstractCompilerPassTestCase
17+
{
18+
/**
19+
* @testdox Uses the PSR-17 factory defined by the application
20+
*/
21+
public function testUsesThePsr17FactoryDefinedByTheApplication(): void
22+
{
23+
$this->container->register('babdev_websocket_server.rfc6455.server_negotiator', ServerNegotiator::class)
24+
->setArguments([
25+
new Definition(RequestVerifier::class),
26+
new AbstractArgument('response factory'),
27+
])
28+
;
29+
30+
$this->container->setAlias(ResponseFactoryInterface::class, HttpFactory::class);
31+
32+
$this->compile();
33+
34+
$this->assertContainerBuilderHasServiceDefinitionWithArgument('babdev_websocket_server.rfc6455.server_negotiator', 1, new Reference(ResponseFactoryInterface::class));
35+
}
36+
37+
public function testUsesTheGuzzleFactoryWhenNoFactoryIsDefinedByTheApplication(): void
38+
{
39+
$this->container->register('babdev_websocket_server.rfc6455.server_negotiator', ServerNegotiator::class)
40+
->setArguments([
41+
new Definition(RequestVerifier::class),
42+
new AbstractArgument('response factory'),
43+
])
44+
;
45+
46+
$this->compile();
47+
48+
$this->assertContainerBuilderHasService('.babdev_websocket_server.psr17_response_factory');
49+
$this->assertContainerBuilderHasServiceDefinitionWithArgument('babdev_websocket_server.rfc6455.server_negotiator', 1, $this->container->getDefinition('.babdev_websocket_server.psr17_response_factory'));
50+
}
51+
52+
protected function registerCompilerPass(ContainerBuilder $container): void
53+
{
54+
$container->addCompilerPass(new ConfigureHttpFactoriesCompilerPass());
55+
}
56+
}

0 commit comments

Comments
 (0)