-
-
Notifications
You must be signed in to change notification settings - Fork 57
Create PSR-7 messages using PSR-17 factories #43
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ env: | |
global: | ||
- PHPUNIT_FLAGS="-v" | ||
- SYMFONY_PHPUNIT_DIR="$HOME/symfony-bridge/.phpunit" | ||
- DEPENDENCIES="zendframework/zend-diactoros:^1.4.1" | ||
- DEPENDENCIES="zendframework/zend-diactoros:^1.4.1 http-interop/http-factory-diactoros:^1.0" | ||
|
||
matrix: | ||
fast_finish: true | ||
|
@@ -26,8 +26,11 @@ matrix: | |
dist: 'precise' | ||
env: DEPENDENCIES="" | ||
- php: 5.4 | ||
env: DEPENDENCIES="zendframework/zend-diactoros:^1.4.1" | ||
- php: 5.5 | ||
env: DEPENDENCIES="zendframework/zend-diactoros:^1.4.1" | ||
- php: 5.6 | ||
env: DEPENDENCIES="zendframework/zend-diactoros:^1.4.1" | ||
- php: 7.0 | ||
- php: 7.1 | ||
- php: 7.2 | ||
|
@@ -36,9 +39,9 @@ matrix: | |
# Test LTS versions. This makes sure we do not use Symfony packages with version greater | ||
# than 2 or 3 respectively. | ||
- php: 7.2 | ||
env: DEPENDENCIES="symfony/lts:^2 symfony/force-lowest:~2.8.0 zendframework/zend-diactoros:^1.4.1" | ||
env: DEPENDENCIES="$DEPENDENCIES symfony/lts:^2 symfony/force-lowest:~2.8.0" | ||
- php: 7.2 | ||
env: DEPENDENCIES="symfony/lts:^3 symfony/force-lowest:~3.4.0 zendframework/zend-diactoros:^1.4.1" | ||
env: DEPENDENCIES="$DEPENDENCIES symfony/lts:^3 symfony/force-lowest:~3.4.0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these two changes needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I needed to add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But http-interop/http-factory-diactoros is already in the global. Right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But if we overwrite the dependencies here without including the previous value, this configuration will mark There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hehe. I’ve been reviewing this PR multiple times but I’ve always read this change wrong. Thank you for you explanation and your patience. Of course, this change is valid. |
||
|
||
# Latest commit to master | ||
- php: 7.2 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bridge\PsrHttpMessage\Factory; | ||
|
||
use Psr\Http\Message\ResponseFactoryInterface; | ||
use Psr\Http\Message\ServerRequestFactoryInterface; | ||
use Psr\Http\Message\StreamFactoryInterface; | ||
use Psr\Http\Message\UploadedFileFactoryInterface; | ||
use Psr\Http\Message\UploadedFileInterface; | ||
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; | ||
use Symfony\Component\HttpFoundation\BinaryFileResponse; | ||
use Symfony\Component\HttpFoundation\File\UploadedFile; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\HttpFoundation\StreamedResponse; | ||
|
||
/** | ||
* Builds Psr\HttpMessage instances using a PSR-17 implementation. | ||
* | ||
* @author Antonio J. García Lagar <[email protected]> | ||
*/ | ||
class PsrHttpFactory implements HttpMessageFactoryInterface | ||
{ | ||
private $serverRequestFactory; | ||
private $streamFactory; | ||
private $uploadedFileFactory; | ||
private $responseFactory; | ||
|
||
public function __construct(ServerRequestFactoryInterface $serverRequestFactory, StreamFactoryInterface $streamFactory, UploadedFileFactoryInterface $uploadedFileFactory, ResponseFactoryInterface $responseFactory) | ||
{ | ||
$this->serverRequestFactory = $serverRequestFactory; | ||
$this->streamFactory = $streamFactory; | ||
$this->uploadedFileFactory = $uploadedFileFactory; | ||
$this->responseFactory = $responseFactory; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function createRequest(Request $symfonyRequest) | ||
{ | ||
$request = $this->serverRequestFactory->createServerRequest( | ||
$symfonyRequest->getMethod(), | ||
$symfonyRequest->getSchemeAndHttpHost().$symfonyRequest->getRequestUri(), | ||
$symfonyRequest->server->all() | ||
); | ||
|
||
foreach ($symfonyRequest->headers->all() as $name => $value) { | ||
$request = $request->withHeader($name, $value); | ||
} | ||
|
||
if (PHP_VERSION_ID < 50600) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the constant should be fully qualified, to allow the compiler to optimize this condition There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and do we even care about PHP 5.5 here ? AFAICT, the PSR factory does not support it |
||
$body = $this->streamFactory->createStreamFromFile('php://temp', 'wb+'); | ||
$body->write($symfonyRequest->getContent()); | ||
} else { | ||
$body = $this->streamFactory->createStreamFromResource($symfonyRequest->getContent(true)); | ||
} | ||
|
||
$request = $request | ||
->withBody($body) | ||
->withUploadedFiles($this->getFiles($symfonyRequest->files->all())) | ||
->withCookieParams($symfonyRequest->cookies->all()) | ||
->withQueryParams($symfonyRequest->query->all()) | ||
->withParsedBody($symfonyRequest->request->all()) | ||
; | ||
|
||
foreach ($symfonyRequest->attributes->all() as $key => $value) { | ||
$request = $request->withAttribute($key, $value); | ||
} | ||
|
||
return $request; | ||
} | ||
|
||
/** | ||
* Converts Symfony uploaded files array to the PSR one. | ||
* | ||
* @param array $uploadedFiles | ||
* | ||
* @return array | ||
*/ | ||
private function getFiles(array $uploadedFiles) | ||
{ | ||
$files = array(); | ||
|
||
foreach ($uploadedFiles as $key => $value) { | ||
if (null === $value) { | ||
$files[$key] = $this->uploadedFileFactory->createUploadedFile($this->streamFactory->createStream(), 0, UPLOAD_ERR_NO_FILE); | ||
continue; | ||
} | ||
if ($value instanceof UploadedFile) { | ||
$files[$key] = $this->createUploadedFile($value); | ||
} else { | ||
$files[$key] = $this->getFiles($value); | ||
} | ||
} | ||
|
||
return $files; | ||
} | ||
|
||
/** | ||
* Creates a PSR-7 UploadedFile instance from a Symfony one. | ||
* | ||
* @param UploadedFile $symfonyUploadedFile | ||
* | ||
* @return UploadedFileInterface | ||
*/ | ||
private function createUploadedFile(UploadedFile $symfonyUploadedFile) | ||
{ | ||
return $this->uploadedFileFactory->createUploadedFile( | ||
$this->streamFactory->createStreamFromFile( | ||
$symfonyUploadedFile->getRealPath() | ||
), | ||
(int) $symfonyUploadedFile->getSize(), | ||
$symfonyUploadedFile->getError(), | ||
$symfonyUploadedFile->getClientOriginalName(), | ||
$symfonyUploadedFile->getClientMimeType() | ||
); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function createResponse(Response $symfonyResponse) | ||
{ | ||
$response = $this->responseFactory->createResponse($symfonyResponse->getStatusCode()); | ||
|
||
if ($symfonyResponse instanceof BinaryFileResponse) { | ||
$stream = $this->streamFactory->createStreamFromFile( | ||
$symfonyResponse->getFile()->getPathname() | ||
); | ||
} else { | ||
$stream = $this->streamFactory->createStreamFromFile('php://temp', 'wb+'); | ||
if ($symfonyResponse instanceof StreamedResponse) { | ||
ob_start(function ($buffer) use ($stream) { | ||
$stream->write($buffer); | ||
|
||
return ''; | ||
}); | ||
|
||
$symfonyResponse->sendContent(); | ||
ob_end_clean(); | ||
} else { | ||
$stream->write($symfonyResponse->getContent()); | ||
} | ||
} | ||
|
||
$response = $response->withBody($stream); | ||
|
||
$headers = $symfonyResponse->headers->all(); | ||
$cookies = $symfonyResponse->headers->getCookies(); | ||
if (!empty($cookies)) { | ||
$headers['Set-Cookie'] = array(); | ||
|
||
foreach ($cookies as $cookie) { | ||
$headers['Set-Cookie'][] = $cookie->__toString(); | ||
} | ||
} | ||
|
||
foreach ($headers as $name => $value) { | ||
$response = $response->withHeader($name, $value); | ||
} | ||
|
||
$protocolVersion = $symfonyResponse->getProtocolVersion(); | ||
$response = $response->withProtocolVersion($protocolVersion); | ||
|
||
return $response; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these three lines needed? Global value is fine, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Global value now includes
http-interop/http-factory-diactoros:^1.0
which requirespsr/http-factory:^1.0
which requires PHP >= 7.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okey. Good