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

Skip to content

[PsrHttpMessageBridge] Support php-http/discovery for auto-detecting PSR-17 factories #51197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Symfony/Bridge/PsrHttpMessage/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CHANGELOG

* Import the bridge into the Symfony monorepo and synchronize releases
* Remove `ArgumentValueResolverInterface` from `PsrServerRequestResolver`
* Support `php-http/discovery` for auto-detecting PSR-17 factories

2.3.1
-----
Expand Down
32 changes: 28 additions & 4 deletions src/Symfony/Bridge/PsrHttpMessage/Factory/PsrHttpFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Bridge\PsrHttpMessage\Factory;

use Http\Discovery\Psr17Factory as DiscoveryPsr17Factory;
use Nyholm\Psr7\Factory\Psr17Factory as NyholmPsr17Factory;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestFactoryInterface;
Expand All @@ -33,12 +35,34 @@
*/
class PsrHttpFactory implements HttpMessageFactoryInterface
{
private readonly ServerRequestFactoryInterface $serverRequestFactory;
private readonly StreamFactoryInterface $streamFactory;
private readonly UploadedFileFactoryInterface $uploadedFileFactory;
private readonly ResponseFactoryInterface $responseFactory;

public function __construct(
private readonly ServerRequestFactoryInterface $serverRequestFactory,
private readonly StreamFactoryInterface $streamFactory,
private readonly UploadedFileFactoryInterface $uploadedFileFactory,
private readonly ResponseFactoryInterface $responseFactory,
ServerRequestFactoryInterface $serverRequestFactory = null,
StreamFactoryInterface $streamFactory = null,
UploadedFileFactoryInterface $uploadedFileFactory = null,
ResponseFactoryInterface $responseFactory = null,
) {
if (null === $serverRequestFactory || null === $streamFactory || null === $uploadedFileFactory || null === $responseFactory) {
$psr17Factory = match (true) {
class_exists(DiscoveryPsr17Factory::class) => new DiscoveryPsr17Factory(),
class_exists(NyholmPsr17Factory::class) => new NyholmPsr17Factory(),
default => throw new \LogicException(sprintf('You cannot use the "%s" as no PSR-17 factories have been provided. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', self::class)),
};

$serverRequestFactory ??= $psr17Factory;
$streamFactory ??= $psr17Factory;
$uploadedFileFactory ??= $psr17Factory;
$responseFactory ??= $psr17Factory;
}

$this->serverRequestFactory = $serverRequestFactory;
$this->streamFactory = $streamFactory;
$this->uploadedFileFactory = $uploadedFileFactory;
$this->responseFactory = $responseFactory;
}

public function createRequest(Request $symfonyRequest): ServerRequestInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Nyholm\Psr7\Factory\Psr17Factory;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\File\UploadedFile;
Expand All @@ -29,23 +28,17 @@
*/
class PsrHttpFactoryTest extends TestCase
{
private HttpMessageFactoryInterface $factory;
private string $tmpDir;

protected function buildHttpMessageFactory(): HttpMessageFactoryInterface
{
$factory = new Psr17Factory();

return new PsrHttpFactory($factory, $factory, $factory, $factory);
}

protected function setUp(): void
{
$this->factory = $this->buildHttpMessageFactory();
$this->tmpDir = sys_get_temp_dir();
}

public function testCreateRequest()
/**
* @dataProvider provideFactories
*/
public function testCreateRequest(PsrHttpFactory $factory)
{
$stdClass = new \stdClass();
$request = new Request(
Expand Down Expand Up @@ -83,7 +76,7 @@ public function testCreateRequest()
);
$request->headers->set(' X-Broken', 'abc');

$psrRequest = $this->factory->createRequest($request);
$psrRequest = $factory->createRequest($request);

$this->assertSame('Content', $psrRequest->getBody()->__toString());

Expand Down Expand Up @@ -130,7 +123,7 @@ public function testGetContentCanBeCalledAfterRequestCreation()
$header = ['HTTP_HOST' => 'dunglas.fr'];
$request = new Request([], [], [], [], [], $header, 'Content');

$psrRequest = $this->factory->createRequest($request);
$psrRequest = self::buildHttpMessageFactory()->createRequest($request);

$this->assertSame('Content', $psrRequest->getBody()->__toString());
$this->assertSame('Content', $request->getContent());
Expand All @@ -144,7 +137,10 @@ private function createUploadedFile(string $content, string $originalName, strin
return new UploadedFile($path, $originalName, $mimeType, $error, true);
}

public function testCreateResponse()
/**
* @dataProvider provideFactories
*/
public function testCreateResponse(PsrHttpFactory $factory)
{
$response = new Response(
'Response content.',
Expand All @@ -156,7 +152,7 @@ public function testCreateResponse()
);
$response->headers->setCookie(new Cookie('city', 'Lille', new \DateTime('Wed, 13 Jan 2021 22:23:01 GMT'), '/', null, false, true, false, 'lax'));

$psrResponse = $this->factory->createResponse($response);
$psrResponse = $factory->createResponse($response);
$this->assertSame('Response content.', $psrResponse->getBody()->__toString());
$this->assertSame(202, $psrResponse->getStatusCode());
$this->assertSame(['3.4'], $psrResponse->getHeader('x-symfony'));
Expand All @@ -179,7 +175,7 @@ public function testCreateResponseFromStreamed()
flush();
});

$psrResponse = $this->factory->createResponse($response);
$psrResponse = self::buildHttpMessageFactory()->createResponse($response);

$this->assertSame("Line 1\nLine 2\n", $psrResponse->getBody()->__toString());
}
Expand All @@ -191,7 +187,7 @@ public function testCreateResponseFromBinaryFile()

$response = new BinaryFileResponse($path);

$psrResponse = $this->factory->createResponse($response);
$psrResponse = self::buildHttpMessageFactory()->createResponse($response);

$this->assertSame('Binary', $psrResponse->getBody()->__toString());
}
Expand All @@ -207,7 +203,7 @@ public function testCreateResponseFromBinaryFileWithRange()
$response = new BinaryFileResponse($path, 200, ['Content-Type' => 'plain/text']);
$response->prepare($request);

$psrResponse = $this->factory->createResponse($response);
$psrResponse = self::buildHttpMessageFactory()->createResponse($response);

$this->assertSame('inar', $psrResponse->getBody()->__toString());
$this->assertSame('bytes 1-4/6', $psrResponse->getHeaderLine('Content-Range'));
Expand Down Expand Up @@ -237,7 +233,7 @@ public function testUploadErrNoFile()
'Content'
);

$psrRequest = $this->factory->createRequest($request);
$psrRequest = self::buildHttpMessageFactory()->createRequest($request);

$uploadedFiles = $psrRequest->getUploadedFiles();

Expand All @@ -256,7 +252,7 @@ public function testJsonContent()
'CONTENT_TYPE' => 'application/json',
];
$request = new Request([], [], [], [], [], $headers, '{"city":"Paris","country":"France"}');
$psrRequest = $this->factory->createRequest($request);
$psrRequest = self::buildHttpMessageFactory()->createRequest($request);

$this->assertSame(['city' => 'Paris', 'country' => 'France'], $psrRequest->getParsedBody());
}
Expand All @@ -272,7 +268,7 @@ public function testEmptyJsonContent()
'CONTENT_TYPE' => 'application/json',
];
$request = new Request([], [], [], [], [], $headers, '{}');
$psrRequest = $this->factory->createRequest($request);
$psrRequest = self::buildHttpMessageFactory()->createRequest($request);

$this->assertSame([], $psrRequest->getParsedBody());
}
Expand All @@ -288,8 +284,22 @@ public function testWrongJsonContent()
'CONTENT_TYPE' => 'application/json',
];
$request = new Request([], [], [], [], [], $headers, '{"city":"Paris"');
$psrRequest = $this->factory->createRequest($request);
$psrRequest = self::buildHttpMessageFactory()->createRequest($request);

$this->assertNull($psrRequest->getParsedBody());
}

public static function provideFactories(): \Generator
{
yield 'Discovery' => [new PsrHttpFactory()];
yield 'incomplete dependencies' => [new PsrHttpFactory(responseFactory: new Psr17Factory())];
yield 'Nyholm' => [self::buildHttpMessageFactory()];
}

private static function buildHttpMessageFactory(): PsrHttpFactory
{
$factory = new Psr17Factory();

return new PsrHttpFactory($factory, $factory, $factory, $factory);
}
}
8 changes: 6 additions & 2 deletions src/Symfony/Bridge/PsrHttpMessage/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@
"symfony/framework-bundle": "^6.2|^7.0",
"symfony/http-kernel": "^6.2|^7.0",
"nyholm/psr7": "^1.1",
"php-http/discovery": "^1.15",
"psr/log": "^1.1.4|^2|^3"
},
"conflict": {
"php-http/discovery": "<1.15",
"symfony/http-kernel": "<6.2"
},
"suggest": {
"nyholm/psr7": "For a super lightweight PSR-7/17 implementation"
"config": {
"allow-plugins": {
"php-http/discovery": false
}
},
"autoload": {
"psr-4": { "Symfony\\Bridge\\PsrHttpMessage\\": "" },
Expand Down