From 527ddd25883f035b162c42644487875989fbabef Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 30 Oct 2023 01:02:38 +0100 Subject: [PATCH] [FrameworkBundle] Integrate PsrHttpMessageBridge --- .../DependencyInjection/Configuration.php | 23 +++++++++ .../FrameworkExtension.php | 13 +++++ .../config/psr_http_message_bridge.php | 49 +++++++++++++++++++ .../DependencyInjection/ConfigurationTest.php | 8 ++- .../Controller/PsrHttpMessageController.php | 37 ++++++++++++++ .../TestBundle/Resources/config/routing.yml | 4 ++ .../Functional/PsrHttpMessageBridgeTest.php | 32 ++++++++++++ .../app/PsrHttpMessageBridge/bundles.php | 18 +++++++ .../app/PsrHttpMessageBridge/config.yml | 9 ++++ .../app/PsrHttpMessageBridge/routing.yml | 2 + .../app/PsrHttpMessageBridge/services.yml | 7 +++ .../Bundle/FrameworkBundle/composer.json | 2 + 12 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/config/psr_http_message_bridge.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/PsrHttpMessageController.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PsrHttpMessageBridgeTest.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/bundles.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/config.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/routing.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/services.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index dc5290c098438..8c939f8d5a5db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -15,6 +15,8 @@ use Doctrine\DBAL\Connection; use Psr\Log\LogLevel; use Seld\JsonLint\JsonParser; +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; +use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; use Symfony\Bundle\FullStack; use Symfony\Component\Asset\Package; use Symfony\Component\AssetMapper\AssetMapper; @@ -192,6 +194,7 @@ public function getConfigTreeBuilder(): TreeBuilder $this->addHtmlSanitizerSection($rootNode, $enableIfStandalone); $this->addWebhookSection($rootNode, $enableIfStandalone); $this->addRemoteEventSection($rootNode, $enableIfStandalone); + $this->addPsrHttpMessageBridgeSection($rootNode, $willBeAvailable); return $treeBuilder; } @@ -2584,4 +2587,24 @@ private function addHtmlSanitizerSection(ArrayNodeDefinition $rootNode, callable ->end() ; } + + private function addPsrHttpMessageBridgeSection(ArrayNodeDefinition $rootNode, callable $willBeAvailable): void + { + $enableMode = 'canBeEnabled'; + if (!class_exists(FullStack::class) + && $willBeAvailable('symfony/psr-http-message-bridge', HttpFoundationFactoryInterface::class) + && 0 === (new \ReflectionClass(PsrHttpFactory::class))->getConstructor()->getNumberOfRequiredParameters() + ) { + $enableMode = 'canBeDisabled'; + } + + $rootNode + ->children() + ->arrayNode('psr_http_message_bridge') + ->info('PSR HTTP message bridge configuration') + ->{$enableMode}() + ->end() + ->end() + ; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 132904c303f1d..7f5129eeaf132 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -25,6 +25,8 @@ use Psr\Http\Client\ClientInterface; use Psr\Log\LoggerAwareInterface; use Symfony\Bridge\Monolog\Processor\DebugProcessor; +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; +use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; use Symfony\Bridge\Twig\Extension\CsrfExtension; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Routing\RouteLoaderInterface; @@ -576,6 +578,17 @@ public function load(array $configs, ContainerBuilder $container) $this->registerHtmlSanitizerConfiguration($config['html_sanitizer'], $container, $loader); } + if ($this->readConfigEnabled('psr_http_message_bridge', $container, $config['psr_http_message_bridge'])) { + if (!interface_exists(HttpFoundationFactoryInterface::class)) { + throw new LogicException('PSR HTTP Message support cannot be enabled as the bridge is not installed. Try running "composer require symfony/psr-http-message-bridge".'); + } + if ((new \ReflectionClass(PsrHttpFactory::class))->getConstructor()->getNumberOfRequiredParameters() > 0) { + throw new LogicException('PSR HTTP Message support cannot be enabled for version 2 or earlier. Please update symfony/psr-http-message-bridge to 6.4 or wire all services manually.'); + } + + $loader->load('psr_http_message_bridge.php'); + } + $this->addAnnotatedClassesToCompile([ '**\\Controller\\', '**\\Entity\\', diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/psr_http_message_bridge.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/psr_http_message_bridge.php new file mode 100644 index 0000000000000..80f16d14d50a2 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/psr_http_message_bridge.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Loader\Configurator; + +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ServerRequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\UploadedFileFactoryInterface; +use Symfony\Bridge\PsrHttpMessage\ArgumentValueResolver\PsrServerRequestResolver; +use Symfony\Bridge\PsrHttpMessage\EventListener\PsrResponseListener; +use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; +use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; +use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; + +return static function (ContainerConfigurator $container) { + $container->services() + ->set('psr_http_message_bridge.http_foundation_factory', HttpFoundationFactory::class) + ->alias(HttpFoundationFactoryInterface::class, 'psr_http_message_bridge.http_foundation_factory') + + ->set('psr_http_message_bridge.psr_http_factory', PsrHttpFactory::class) + ->args([ + service(ServerRequestFactoryInterface::class)->nullOnInvalid(), + service(StreamFactoryInterface::class)->nullOnInvalid(), + service(UploadedFileFactoryInterface::class)->nullOnInvalid(), + service(ResponseFactoryInterface::class)->nullOnInvalid(), + ]) + ->alias(HttpMessageFactoryInterface::class, 'psr_http_message_bridge.psr_http_factory') + + ->set('psr_http_message_bridge.psr_server_request_resolver', PsrServerRequestResolver::class) + ->args([service('psr_http_message_bridge.psr_http_factory')]) + ->tag('controller.argument_value_resolver', ['priority' => -100]) + + ->set('psr_http_message_bridge.psr_response_listener', PsrResponseListener::class) + ->args([ + service('psr_http_message_bridge.http_foundation_factory'), + ]) + ->tag('kernel.event_subscriber') + ; +}; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index ab08f47655a8b..2acde15627f00 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Connection; use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Configuration; use Symfony\Bundle\FullStack; use Symfony\Component\Cache\Adapter\DoctrineAdapter; @@ -46,7 +47,7 @@ public function testDefaultConfig() $this->assertEquals(self::getBundleDefaultConfig(), $config); } - public function getTestValidSessionName() + public function getTestValidSessionName(): array { return [ [null], @@ -529,7 +530,7 @@ public function testEnabledLockNeedsResources() ]); } - protected static function getBundleDefaultConfig() + protected static function getBundleDefaultConfig(): array { return [ 'http_method_override' => false, @@ -787,6 +788,9 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'remote-event' => [ 'enabled' => false, ], + 'psr_http_message_bridge' => [ + 'enabled' => !class_exists(FullStack::class) && 0 === (new \ReflectionClass(PsrHttpFactory::class))->getConstructor()->getNumberOfRequiredParameters(), + ], ]; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/PsrHttpMessageController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/PsrHttpMessageController.php new file mode 100644 index 0000000000000..08dbd5c35eff8 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/PsrHttpMessageController.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller; + +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamFactoryInterface; + +final class PsrHttpMessageController +{ + public function __construct( + private readonly ResponseFactoryInterface&StreamFactoryInterface $factory, + ) { + } + + public function __invoke(ServerRequestInterface $request): ResponseInterface + { + $responsePayload = json_encode([ + 'message' => sprintf('Hello %s!', $request->getQueryParams()['name'] ?? 'World'), + ], \JSON_THROW_ON_ERROR); + + return $this->factory->createResponse() + ->withHeader('Content-Type', 'application/json') + ->withBody($this->factory->createStream($responsePayload)) + ; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml index 9ed8ebe7f648c..1462efa5acd9b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml @@ -65,6 +65,10 @@ http_client_call: path: /http_client_call defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\HttpClientController::index } +psr_http_message_bridge: + path: /psr_http + controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\PsrHttpMessageController + uid: resource: "../../Controller/UidController.php" type: "attribute" diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PsrHttpMessageBridgeTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PsrHttpMessageBridgeTest.php new file mode 100644 index 0000000000000..60fa65c8958c1 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PsrHttpMessageBridgeTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; + +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; + +class PsrHttpMessageBridgeTest extends AbstractWebTestCase +{ + public function testBridgeIntegration() + { + if ((new \ReflectionClass(PsrHttpFactory::class))->getConstructor()->getNumberOfRequiredParameters() > 0) { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('PSR HTTP Message support cannot be enabled for version 2 or earlier. Please update symfony/psr-http-message-bridge to 6.4 or wire all services manually.'); + } + + $client = $this->createClient(['test_case' => 'PsrHttpMessageBridge', 'root_config' => 'config.yml', 'debug' => true]); + $client->request('GET', '/psr_http?name=Symfony'); + + $this->assertResponseIsSuccessful(); + $this->assertResponseHeaderSame('content-type', 'application/json'); + $this->assertJsonStringEqualsJsonString('{"message":"Hello Symfony!"}', $client->getResponse()->getContent()); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/bundles.php new file mode 100644 index 0000000000000..15ff182c6fed5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/bundles.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle; + +return [ + new FrameworkBundle(), + new TestBundle(), +]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/config.yml new file mode 100644 index 0000000000000..71876ec28d26e --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/config.yml @@ -0,0 +1,9 @@ +imports: + - { resource: ../config/default.yml } + - { resource: services.yml } + +framework: + http_method_override: false + profiler: ~ + psr_http_message_bridge: + enabled: true diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/routing.yml new file mode 100644 index 0000000000000..4fb9a95400e97 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/routing.yml @@ -0,0 +1,2 @@ +_emailtest_bundle: + resource: '@TestBundle/Resources/config/routing.yml' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/services.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/services.yml new file mode 100644 index 0000000000000..72716cb30fa35 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/PsrHttpMessageBridge/services.yml @@ -0,0 +1,7 @@ +services: + nyholm_psr7_factory: + class: Nyholm\Psr7\Factory\Psr17Factory + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\PsrHttpMessageController: + public: true + arguments: ['@nyholm_psr7_factory'] diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index e63a672e8c40b..7147342f4040e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -36,6 +36,7 @@ "doctrine/annotations": "^1.13.1|^2", "doctrine/persistence": "^1.3|^2|^3", "dragonmantank/cron-expression": "^3.1", + "nyholm/psr7": "^1", "seld/jsonlint": "^1.10", "symfony/asset": "^5.4|^6.0|^7.0", "symfony/asset-mapper": "^6.4|^7.0", @@ -56,6 +57,7 @@ "symfony/mime": "^6.4|^7.0", "symfony/notifier": "^5.4|^6.0|^7.0", "symfony/process": "^5.4|^6.0|^7.0", + "symfony/psr-http-message-bridge": "^2.3|^6.4|^7.0", "symfony/rate-limiter": "^5.4|^6.0|^7.0", "symfony/scheduler": "^6.4|^7.0", "symfony/security-bundle": "^5.4|^6.0|^7.0", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy