Skip to content

Commit 75dc839

Browse files
committed
Create PSR-7 messages using PSR-17 factories
1 parent f11f173 commit 75dc839

File tree

6 files changed

+461
-204
lines changed

6 files changed

+461
-204
lines changed

.travis.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ env:
99
global:
1010
- PHPUNIT_FLAGS="-v"
1111
- SYMFONY_PHPUNIT_DIR="$HOME/symfony-bridge/.phpunit"
12-
- DEPENDENCIES="zendframework/zend-diactoros:^1.4.1"
12+
- DEPENDENCIES="zendframework/zend-diactoros:^1.4.1 http-interop/http-factory-diactoros:^1.0"
1313

1414
matrix:
1515
fast_finish: true
@@ -26,8 +26,11 @@ matrix:
2626
dist: 'precise'
2727
env: DEPENDENCIES=""
2828
- php: 5.4
29+
env: DEPENDENCIES="zendframework/zend-diactoros:^1.4.1"
2930
- php: 5.5
31+
env: DEPENDENCIES="zendframework/zend-diactoros:^1.4.1"
3032
- php: 5.6
33+
env: DEPENDENCIES="zendframework/zend-diactoros:^1.4.1"
3134
- php: 7.0
3235
- php: 7.1
3336
- php: 7.2
@@ -36,9 +39,9 @@ matrix:
3639
# Test LTS versions. This makes sure we do not use Symfony packages with version greater
3740
# than 2 or 3 respectively.
3841
- php: 7.2
39-
env: DEPENDENCIES="symfony/lts:^2 symfony/force-lowest:~2.8.0 zendframework/zend-diactoros:^1.4.1"
42+
env: DEPENDENCIES="$DEPENDENCIES symfony/lts:^2 symfony/force-lowest:~2.8.0"
4043
- php: 7.2
41-
env: DEPENDENCIES="symfony/lts:^3 symfony/force-lowest:~3.4.0 zendframework/zend-diactoros:^1.4.1"
44+
env: DEPENDENCIES="$DEPENDENCIES symfony/lts:^3 symfony/force-lowest:~3.4.0"
4245

4346
# Latest commit to master
4447
- php: 7.2

Factory/PsrHttpFactory.php

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Bridge\PsrHttpMessage\Factory;
13+
14+
use Psr\Http\Message\ResponseFactoryInterface;
15+
use Psr\Http\Message\ServerRequestFactoryInterface;
16+
use Psr\Http\Message\StreamFactoryInterface;
17+
use Psr\Http\Message\UploadedFileFactoryInterface;
18+
use Psr\Http\Message\UploadedFileInterface;
19+
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
20+
use Symfony\Component\HttpFoundation\BinaryFileResponse;
21+
use Symfony\Component\HttpFoundation\File\UploadedFile;
22+
use Symfony\Component\HttpFoundation\Request;
23+
use Symfony\Component\HttpFoundation\Response;
24+
use Symfony\Component\HttpFoundation\StreamedResponse;
25+
26+
/**
27+
* Builds Psr\HttpMessage instances using a PSR-17 implementation.
28+
*
29+
* @author Antonio J. García Lagar <[email protected]>
30+
*/
31+
class PsrHttpFactory implements HttpMessageFactoryInterface
32+
{
33+
private $serverRequestFactory;
34+
private $streamFactory;
35+
private $uploadedFileFactory;
36+
private $responseFactory;
37+
38+
public function __construct(
39+
ServerRequestFactoryInterface $serverRequestFactory,
40+
StreamFactoryInterface $streamFactory,
41+
UploadedFileFactoryInterface $uploadedFileFactory,
42+
ResponseFactoryInterface $responseFactory
43+
) {
44+
$this->serverRequestFactory = $serverRequestFactory;
45+
$this->streamFactory = $streamFactory;
46+
$this->uploadedFileFactory = $uploadedFileFactory;
47+
$this->responseFactory = $responseFactory;
48+
}
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
public function createRequest(Request $symfonyRequest)
54+
{
55+
$request = $this->serverRequestFactory->createServerRequest(
56+
$symfonyRequest->getMethod(),
57+
$symfonyRequest->getSchemeAndHttpHost().$symfonyRequest->getRequestUri(),
58+
$symfonyRequest->server->all()
59+
);
60+
61+
foreach ($symfonyRequest->headers->all() as $name => $value) {
62+
$request = $request->withHeader($name, $value);
63+
}
64+
65+
if (PHP_VERSION_ID < 50600) {
66+
$body = $this->streamFactory->createStreamFromFile('php://temp', 'wb+');
67+
$body->write($symfonyRequest->getContent());
68+
} else {
69+
$body = $this->streamFactory->createStreamFromResource($symfonyRequest->getContent(true));
70+
}
71+
72+
$request = $request
73+
->withBody($body)
74+
->withUploadedFiles($this->getFiles($symfonyRequest->files->all()))
75+
->withCookieParams($symfonyRequest->cookies->all())
76+
->withQueryParams($symfonyRequest->query->all())
77+
->withParsedBody($symfonyRequest->request->all())
78+
->withRequestTarget($symfonyRequest->getRequestUri())
79+
;
80+
81+
foreach ($symfonyRequest->attributes->all() as $key => $value) {
82+
$request = $request->withAttribute($key, $value);
83+
}
84+
85+
return $request;
86+
}
87+
88+
/**
89+
* Converts Symfony uploaded files array to the PSR one.
90+
*
91+
* @param array $uploadedFiles
92+
*
93+
* @return array
94+
*/
95+
private function getFiles(array $uploadedFiles)
96+
{
97+
$files = array();
98+
99+
foreach ($uploadedFiles as $key => $value) {
100+
if (null === $value) {
101+
$files[$key] = $this->uploadedFileFactory->createUploadedFile(
102+
$this->streamFactory->createStream(),
103+
0,
104+
UPLOAD_ERR_NO_FILE
105+
);
106+
continue;
107+
}
108+
if ($value instanceof UploadedFile) {
109+
$files[$key] = $this->createUploadedFile($value);
110+
} else {
111+
$files[$key] = $this->getFiles($value);
112+
}
113+
}
114+
115+
return $files;
116+
}
117+
118+
/**
119+
* Creates a PSR-7 UploadedFile instance from a Symfony one.
120+
*
121+
* @param UploadedFile $symfonyUploadedFile
122+
*
123+
* @return UploadedFileInterface
124+
*/
125+
private function createUploadedFile(UploadedFile $symfonyUploadedFile)
126+
{
127+
return $this->uploadedFileFactory->createUploadedFile(
128+
$this->streamFactory->createStreamFromFile(
129+
$symfonyUploadedFile->getRealPath()
130+
),
131+
$symfonyUploadedFile->getClientSize(),
132+
$symfonyUploadedFile->getError(),
133+
$symfonyUploadedFile->getClientOriginalName(),
134+
$symfonyUploadedFile->getClientMimeType()
135+
);
136+
}
137+
138+
/**
139+
* {@inheritdoc}
140+
*/
141+
public function createResponse(Response $symfonyResponse)
142+
{
143+
$response = $this->responseFactory->createResponse($symfonyResponse->getStatusCode());
144+
145+
if ($symfonyResponse instanceof BinaryFileResponse) {
146+
$stream = $this->streamFactory->createStreamFromFile(
147+
$symfonyResponse->getFile()->getPathname()
148+
);
149+
} else {
150+
$stream = $this->streamFactory->createStreamFromFile('php://temp', 'wb+');
151+
if ($symfonyResponse instanceof StreamedResponse) {
152+
ob_start(function ($buffer) use ($stream) {
153+
$stream->write($buffer);
154+
155+
return false;
156+
});
157+
158+
$symfonyResponse->sendContent();
159+
ob_end_clean();
160+
} else {
161+
$stream->write($symfonyResponse->getContent());
162+
}
163+
}
164+
165+
$response = $response->withBody($stream);
166+
167+
$headers = $symfonyResponse->headers->all();
168+
$cookies = $symfonyResponse->headers->getCookies();
169+
if (!empty($cookies)) {
170+
$headers['Set-Cookie'] = array();
171+
172+
foreach ($cookies as $cookie) {
173+
$headers['Set-Cookie'][] = $cookie->__toString();
174+
}
175+
}
176+
177+
foreach ($headers as $name => $value) {
178+
$response = $response->withHeader($name, $value);
179+
}
180+
181+
$protocolVersion = $symfonyResponse->getProtocolVersion();
182+
$response = $response->withProtocolVersion($protocolVersion);
183+
184+
return $response;
185+
}
186+
}

0 commit comments

Comments
 (0)