├── ArgumentValueResolver └── PsrServerRequestResolver.php ├── CHANGELOG.md ├── EventListener └── PsrResponseListener.php ├── Factory ├── HttpFoundationFactory.php ├── PsrHttpFactory.php └── UploadedFile.php ├── HttpFoundationFactoryInterface.php ├── HttpMessageFactoryInterface.php ├── LICENSE ├── README.md └── composer.json /ArgumentValueResolver/PsrServerRequestResolver.php: -------------------------------------------------------------------------------- 1 | 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\ArgumentValueResolver; 13 | 14 | use Psr\Http\Message\MessageInterface; 15 | use Psr\Http\Message\RequestInterface; 16 | use Psr\Http\Message\ServerRequestInterface; 17 | use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; 18 | use Symfony\Component\HttpFoundation\Request; 19 | use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; 20 | use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; 21 | 22 | /** 23 | * Injects the RequestInterface, MessageInterface or ServerRequestInterface when requested. 24 | * 25 | * @author Iltar van der Berg 26 | * @author Alexander M. Turek 27 | */ 28 | final class PsrServerRequestResolver implements ValueResolverInterface 29 | { 30 | private const SUPPORTED_TYPES = [ 31 | ServerRequestInterface::class => true, 32 | RequestInterface::class => true, 33 | MessageInterface::class => true, 34 | ]; 35 | 36 | public function __construct( 37 | private readonly HttpMessageFactoryInterface $httpMessageFactory, 38 | ) { 39 | } 40 | 41 | public function resolve(Request $request, ArgumentMetadata $argument): \Traversable 42 | { 43 | if (!isset(self::SUPPORTED_TYPES[$argument->getType()])) { 44 | return; 45 | } 46 | 47 | yield $this->httpMessageFactory->createRequest($request); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | 6.4 5 | --- 6 | 7 | * Import the bridge into the Symfony monorepo and synchronize releases 8 | * Remove `ArgumentValueResolverInterface` from `PsrServerRequestResolver` 9 | * Support `php-http/discovery` for auto-detecting PSR-17 factories 10 | 11 | 2.3.1 12 | ----- 13 | 14 | * Don't rely on `Request::getPayload()` to populate the parsed body 15 | 16 | 2.3.0 17 | ----- 18 | 19 | * Leverage `Request::getPayload()` to populate the parsed body of PSR-7 requests 20 | * Implement `ValueResolverInterface` introduced with Symfony 6.2 21 | 22 | 2.2.0 23 | ----- 24 | 25 | * Drop support for Symfony 4 26 | * Bump minimum version of PHP to 7.2 27 | * Support version 2 of the psr/http-message contracts 28 | 29 | 2.1.3 30 | ----- 31 | 32 | * Ignore invalid HTTP headers when creating PSR7 objects 33 | * Fix for wrong type passed to `moveTo()` 34 | 35 | 2.1.2 36 | ----- 37 | 38 | * Allow Symfony 6 39 | 40 | 2.1.0 41 | ----- 42 | 43 | * Added a `PsrResponseListener` to automatically convert PSR-7 responses returned by controllers 44 | * Added a `PsrServerRequestResolver` that allows injecting PSR-7 request objects into controllers 45 | 46 | 2.0.2 47 | ----- 48 | 49 | * Fix populating server params from URI in HttpFoundationFactory 50 | * Create cookies as raw in HttpFoundationFactory 51 | * Fix BinaryFileResponse with Content-Range PsrHttpFactory 52 | 53 | 2.0.1 54 | ----- 55 | 56 | * Don't normalize query string in PsrHttpFactory 57 | * Fix conversion for HTTPS requests 58 | * Fix populating default port and headers in HttpFoundationFactory 59 | 60 | 2.0.0 61 | ----- 62 | 63 | * Remove DiactorosFactory 64 | 65 | 1.3.0 66 | ----- 67 | 68 | * Added support for streamed requests 69 | * Added support for Symfony 5.0+ 70 | * Fixed bridging UploadedFile objects 71 | * Bumped minimum version of Symfony to 4.4 72 | 73 | 1.2.0 74 | ----- 75 | 76 | * Added new documentation links 77 | * Bumped minimum version of PHP to 7.1 78 | * Added support for streamed responses 79 | 80 | 1.1.2 81 | ----- 82 | 83 | * Fixed createResponse 84 | 85 | 1.1.1 86 | ----- 87 | 88 | * Deprecated DiactorosFactory, use PsrHttpFactory instead 89 | * Removed triggering of deprecation 90 | 91 | 1.1.0 92 | ----- 93 | 94 | * Added support for creating PSR-7 messages using PSR-17 factories 95 | 96 | 1.0.2 97 | ----- 98 | 99 | * Fixed request target in PSR7 Request (mtibben) 100 | 101 | 1.0.1 102 | ----- 103 | 104 | * Added support for Symfony 4 (dunglas) 105 | 106 | 1.0.0 107 | ----- 108 | 109 | * Initial release 110 | -------------------------------------------------------------------------------- /EventListener/PsrResponseListener.php: -------------------------------------------------------------------------------- 1 | 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\EventListener; 13 | 14 | use Psr\Http\Message\ResponseInterface; 15 | use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; 16 | use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; 17 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 18 | use Symfony\Component\HttpKernel\Event\ViewEvent; 19 | use Symfony\Component\HttpKernel\KernelEvents; 20 | 21 | /** 22 | * Converts PSR-7 Response to HttpFoundation Response using the bridge. 23 | * 24 | * @author Kévin Dunglas 25 | * @author Alexander M. Turek 26 | */ 27 | final class PsrResponseListener implements EventSubscriberInterface 28 | { 29 | private readonly HttpFoundationFactoryInterface $httpFoundationFactory; 30 | 31 | public function __construct(?HttpFoundationFactoryInterface $httpFoundationFactory = null) 32 | { 33 | $this->httpFoundationFactory = $httpFoundationFactory ?? new HttpFoundationFactory(); 34 | } 35 | 36 | /** 37 | * Do the conversion if applicable and update the response of the event. 38 | */ 39 | public function onKernelView(ViewEvent $event): void 40 | { 41 | $controllerResult = $event->getControllerResult(); 42 | 43 | if (!$controllerResult instanceof ResponseInterface) { 44 | return; 45 | } 46 | 47 | $event->setResponse($this->httpFoundationFactory->createResponse($controllerResult)); 48 | } 49 | 50 | public static function getSubscribedEvents(): array 51 | { 52 | return [ 53 | KernelEvents::VIEW => 'onKernelView', 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Factory/HttpFoundationFactory.php: -------------------------------------------------------------------------------- 1 | 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\ResponseInterface; 15 | use Psr\Http\Message\ServerRequestInterface; 16 | use Psr\Http\Message\StreamInterface; 17 | use Psr\Http\Message\UploadedFileInterface; 18 | use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; 19 | use Symfony\Component\HttpFoundation\Cookie; 20 | use Symfony\Component\HttpFoundation\Request; 21 | use Symfony\Component\HttpFoundation\Response; 22 | use Symfony\Component\HttpFoundation\StreamedResponse; 23 | 24 | /** 25 | * @author Kévin Dunglas 26 | */ 27 | class HttpFoundationFactory implements HttpFoundationFactoryInterface 28 | { 29 | /** 30 | * @param int $responseBufferMaxLength The maximum output buffering size for each iteration when sending the response 31 | */ 32 | public function __construct( 33 | private readonly int $responseBufferMaxLength = 16372, 34 | ) { 35 | } 36 | 37 | public function createRequest(ServerRequestInterface $psrRequest, bool $streamed = false): Request 38 | { 39 | $server = []; 40 | $uri = $psrRequest->getUri(); 41 | 42 | $server['SERVER_NAME'] = $uri->getHost(); 43 | $server['SERVER_PORT'] = $uri->getPort() ?: ('https' === $uri->getScheme() ? 443 : 80); 44 | $server['REQUEST_URI'] = $uri->getPath(); 45 | $server['QUERY_STRING'] = $uri->getQuery(); 46 | 47 | if ('' !== $server['QUERY_STRING']) { 48 | $server['REQUEST_URI'] .= '?'.$server['QUERY_STRING']; 49 | } 50 | 51 | if ('https' === $uri->getScheme()) { 52 | $server['HTTPS'] = 'on'; 53 | } 54 | 55 | $server['REQUEST_METHOD'] = $psrRequest->getMethod(); 56 | 57 | $server = array_replace($psrRequest->getServerParams(), $server); 58 | 59 | $parsedBody = $psrRequest->getParsedBody(); 60 | $parsedBody = \is_array($parsedBody) ? $parsedBody : []; 61 | 62 | $request = new Request( 63 | $psrRequest->getQueryParams(), 64 | $parsedBody, 65 | $psrRequest->getAttributes(), 66 | $psrRequest->getCookieParams(), 67 | $this->getFiles($psrRequest->getUploadedFiles()), 68 | $server, 69 | $streamed ? $psrRequest->getBody()->detach() : $psrRequest->getBody()->__toString() 70 | ); 71 | $request->headers->add($psrRequest->getHeaders()); 72 | 73 | return $request; 74 | } 75 | 76 | /** 77 | * Converts to the input array to $_FILES structure. 78 | */ 79 | private function getFiles(array $uploadedFiles): array 80 | { 81 | $files = []; 82 | 83 | foreach ($uploadedFiles as $key => $value) { 84 | if ($value instanceof UploadedFileInterface) { 85 | $files[$key] = $this->createUploadedFile($value); 86 | } else { 87 | $files[$key] = $this->getFiles($value); 88 | } 89 | } 90 | 91 | return $files; 92 | } 93 | 94 | /** 95 | * Creates Symfony UploadedFile instance from PSR-7 ones. 96 | */ 97 | private function createUploadedFile(UploadedFileInterface $psrUploadedFile): UploadedFile 98 | { 99 | return new UploadedFile($psrUploadedFile, function () { return $this->getTemporaryPath(); }); 100 | } 101 | 102 | /** 103 | * Gets a temporary file path. 104 | */ 105 | protected function getTemporaryPath(): string 106 | { 107 | return tempnam(sys_get_temp_dir(), 'symfony'); 108 | } 109 | 110 | public function createResponse(ResponseInterface $psrResponse, bool $streamed = false): Response 111 | { 112 | $cookies = $psrResponse->getHeader('Set-Cookie'); 113 | $psrResponse = $psrResponse->withoutHeader('Set-Cookie'); 114 | 115 | if ($streamed) { 116 | $response = new StreamedResponse( 117 | $this->createStreamedResponseCallback($psrResponse->getBody()), 118 | $psrResponse->getStatusCode(), 119 | $psrResponse->getHeaders() 120 | ); 121 | } else { 122 | $response = new Response( 123 | $psrResponse->getBody()->__toString(), 124 | $psrResponse->getStatusCode(), 125 | $psrResponse->getHeaders() 126 | ); 127 | } 128 | 129 | $response->setProtocolVersion($psrResponse->getProtocolVersion()); 130 | 131 | foreach ($cookies as $cookie) { 132 | $response->headers->setCookie(Cookie::fromString($cookie)); 133 | } 134 | 135 | return $response; 136 | } 137 | 138 | private function createStreamedResponseCallback(StreamInterface $body): callable 139 | { 140 | return function () use ($body) { 141 | if ($body->isSeekable()) { 142 | $body->rewind(); 143 | } 144 | 145 | if (!$body->isReadable()) { 146 | echo $body; 147 | 148 | return; 149 | } 150 | 151 | while (!$body->eof()) { 152 | echo $body->read($this->responseBufferMaxLength); 153 | } 154 | }; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Factory/PsrHttpFactory.php: -------------------------------------------------------------------------------- 1 | 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 Http\Discovery\Psr17Factory as DiscoveryPsr17Factory; 15 | use Nyholm\Psr7\Factory\Psr17Factory as NyholmPsr17Factory; 16 | use Psr\Http\Message\ResponseFactoryInterface; 17 | use Psr\Http\Message\ResponseInterface; 18 | use Psr\Http\Message\ServerRequestFactoryInterface; 19 | use Psr\Http\Message\ServerRequestInterface; 20 | use Psr\Http\Message\StreamFactoryInterface; 21 | use Psr\Http\Message\UploadedFileFactoryInterface; 22 | use Psr\Http\Message\UploadedFileInterface; 23 | use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; 24 | use Symfony\Component\HttpFoundation\BinaryFileResponse; 25 | use Symfony\Component\HttpFoundation\File\UploadedFile; 26 | use Symfony\Component\HttpFoundation\Request; 27 | use Symfony\Component\HttpFoundation\Response; 28 | use Symfony\Component\HttpFoundation\StreamedResponse; 29 | 30 | /** 31 | * Builds Psr\HttpMessage instances using a PSR-17 implementation. 32 | * 33 | * @author Antonio J. García Lagar 34 | * @author Aurélien Pillevesse 35 | */ 36 | class PsrHttpFactory implements HttpMessageFactoryInterface 37 | { 38 | private readonly ServerRequestFactoryInterface $serverRequestFactory; 39 | private readonly StreamFactoryInterface $streamFactory; 40 | private readonly UploadedFileFactoryInterface $uploadedFileFactory; 41 | private readonly ResponseFactoryInterface $responseFactory; 42 | 43 | public function __construct( 44 | ?ServerRequestFactoryInterface $serverRequestFactory = null, 45 | ?StreamFactoryInterface $streamFactory = null, 46 | ?UploadedFileFactoryInterface $uploadedFileFactory = null, 47 | ?ResponseFactoryInterface $responseFactory = null, 48 | ) { 49 | if (null === $serverRequestFactory || null === $streamFactory || null === $uploadedFileFactory || null === $responseFactory) { 50 | $psr17Factory = match (true) { 51 | class_exists(DiscoveryPsr17Factory::class) => new DiscoveryPsr17Factory(), 52 | class_exists(NyholmPsr17Factory::class) => new NyholmPsr17Factory(), 53 | 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)), 54 | }; 55 | 56 | $serverRequestFactory ??= $psr17Factory; 57 | $streamFactory ??= $psr17Factory; 58 | $uploadedFileFactory ??= $psr17Factory; 59 | $responseFactory ??= $psr17Factory; 60 | } 61 | 62 | $this->serverRequestFactory = $serverRequestFactory; 63 | $this->streamFactory = $streamFactory; 64 | $this->uploadedFileFactory = $uploadedFileFactory; 65 | $this->responseFactory = $responseFactory; 66 | } 67 | 68 | public function createRequest(Request $symfonyRequest): ServerRequestInterface 69 | { 70 | $uri = $symfonyRequest->server->get('QUERY_STRING', ''); 71 | $uri = $symfonyRequest->getSchemeAndHttpHost().$symfonyRequest->getBaseUrl().$symfonyRequest->getPathInfo().('' !== $uri ? '?'.$uri : ''); 72 | 73 | $request = $this->serverRequestFactory->createServerRequest( 74 | $symfonyRequest->getMethod(), 75 | $uri, 76 | $symfonyRequest->server->all() 77 | ); 78 | 79 | foreach ($symfonyRequest->headers->all() as $name => $value) { 80 | try { 81 | $request = $request->withHeader($name, $value); 82 | } catch (\InvalidArgumentException $e) { 83 | // ignore invalid header 84 | } 85 | } 86 | 87 | $body = $this->streamFactory->createStreamFromResource($symfonyRequest->getContent(true)); 88 | $format = $symfonyRequest->getContentTypeFormat(); 89 | 90 | if ('json' === $format) { 91 | $parsedBody = json_decode($symfonyRequest->getContent(), true, 512, \JSON_BIGINT_AS_STRING); 92 | 93 | if (!\is_array($parsedBody)) { 94 | $parsedBody = null; 95 | } 96 | } else { 97 | $parsedBody = $symfonyRequest->request->all(); 98 | } 99 | 100 | $request = $request 101 | ->withBody($body) 102 | ->withUploadedFiles($this->getFiles($symfonyRequest->files->all())) 103 | ->withCookieParams($symfonyRequest->cookies->all()) 104 | ->withQueryParams($symfonyRequest->query->all()) 105 | ->withParsedBody($parsedBody) 106 | ; 107 | 108 | foreach ($symfonyRequest->attributes->all() as $key => $value) { 109 | $request = $request->withAttribute($key, $value); 110 | } 111 | 112 | return $request; 113 | } 114 | 115 | /** 116 | * Converts Symfony uploaded files array to the PSR one. 117 | */ 118 | private function getFiles(array $uploadedFiles): array 119 | { 120 | $files = []; 121 | 122 | foreach ($uploadedFiles as $key => $value) { 123 | if (null === $value) { 124 | $files[$key] = $this->uploadedFileFactory->createUploadedFile($this->streamFactory->createStream(), 0, \UPLOAD_ERR_NO_FILE); 125 | continue; 126 | } 127 | if ($value instanceof UploadedFile) { 128 | $files[$key] = $this->createUploadedFile($value); 129 | } else { 130 | $files[$key] = $this->getFiles($value); 131 | } 132 | } 133 | 134 | return $files; 135 | } 136 | 137 | /** 138 | * Creates a PSR-7 UploadedFile instance from a Symfony one. 139 | */ 140 | private function createUploadedFile(UploadedFile $symfonyUploadedFile): UploadedFileInterface 141 | { 142 | return $this->uploadedFileFactory->createUploadedFile( 143 | $this->streamFactory->createStreamFromFile( 144 | $symfonyUploadedFile->getRealPath() 145 | ), 146 | (int) $symfonyUploadedFile->getSize(), 147 | $symfonyUploadedFile->getError(), 148 | $symfonyUploadedFile->getClientOriginalName(), 149 | $symfonyUploadedFile->getClientMimeType() 150 | ); 151 | } 152 | 153 | public function createResponse(Response $symfonyResponse): ResponseInterface 154 | { 155 | $response = $this->responseFactory->createResponse($symfonyResponse->getStatusCode(), Response::$statusTexts[$symfonyResponse->getStatusCode()] ?? ''); 156 | 157 | if ($symfonyResponse instanceof BinaryFileResponse && !$symfonyResponse->headers->has('Content-Range')) { 158 | $stream = $this->streamFactory->createStreamFromFile( 159 | $symfonyResponse->getFile()->getPathname() 160 | ); 161 | } else { 162 | $stream = $this->streamFactory->createStreamFromFile('php://temp', 'wb+'); 163 | if ($symfonyResponse instanceof StreamedResponse || $symfonyResponse instanceof BinaryFileResponse) { 164 | ob_start(function ($buffer) use ($stream) { 165 | $stream->write($buffer); 166 | 167 | return ''; 168 | }, 1); 169 | 170 | $symfonyResponse->sendContent(); 171 | ob_end_clean(); 172 | } else { 173 | $stream->write($symfonyResponse->getContent()); 174 | } 175 | } 176 | 177 | $response = $response->withBody($stream); 178 | 179 | $headers = $symfonyResponse->headers->all(); 180 | $cookies = $symfonyResponse->headers->getCookies(); 181 | if ($cookies) { 182 | $headers['Set-Cookie'] = []; 183 | 184 | foreach ($cookies as $cookie) { 185 | $headers['Set-Cookie'][] = $cookie->__toString(); 186 | } 187 | } 188 | 189 | foreach ($headers as $name => $value) { 190 | try { 191 | $response = $response->withHeader($name, $value); 192 | } catch (\InvalidArgumentException $e) { 193 | // ignore invalid header 194 | } 195 | } 196 | 197 | $protocolVersion = $symfonyResponse->getProtocolVersion(); 198 | 199 | return $response->withProtocolVersion($protocolVersion); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /Factory/UploadedFile.php: -------------------------------------------------------------------------------- 1 | 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\UploadedFileInterface; 15 | use Symfony\Component\HttpFoundation\File\Exception\FileException; 16 | use Symfony\Component\HttpFoundation\File\File; 17 | use Symfony\Component\HttpFoundation\File\UploadedFile as BaseUploadedFile; 18 | 19 | /** 20 | * @author Nicolas Grekas 21 | */ 22 | class UploadedFile extends BaseUploadedFile 23 | { 24 | private bool $test = false; 25 | 26 | public function __construct( 27 | private readonly UploadedFileInterface $psrUploadedFile, 28 | callable $getTemporaryPath, 29 | ) { 30 | $error = $psrUploadedFile->getError(); 31 | $path = ''; 32 | 33 | if (\UPLOAD_ERR_NO_FILE !== $error) { 34 | $path = $psrUploadedFile->getStream()->getMetadata('uri') ?? ''; 35 | 36 | if ($this->test = !\is_string($path) || !is_uploaded_file($path)) { 37 | $path = $getTemporaryPath(); 38 | $psrUploadedFile->moveTo($path); 39 | } 40 | } 41 | 42 | parent::__construct( 43 | $path, 44 | (string) $psrUploadedFile->getClientFilename(), 45 | $psrUploadedFile->getClientMediaType(), 46 | $psrUploadedFile->getError(), 47 | $this->test 48 | ); 49 | } 50 | 51 | public function move(string $directory, ?string $name = null): File 52 | { 53 | if (!$this->isValid() || $this->test) { 54 | return parent::move($directory, $name); 55 | } 56 | 57 | $target = $this->getTargetFile($directory, $name); 58 | 59 | try { 60 | $this->psrUploadedFile->moveTo((string) $target); 61 | } catch (\RuntimeException $e) { 62 | throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, $e->getMessage()), 0, $e); 63 | } 64 | 65 | @chmod($target, 0666 & ~umask()); 66 | 67 | return $target; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /HttpFoundationFactoryInterface.php: -------------------------------------------------------------------------------- 1 | 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; 13 | 14 | use Psr\Http\Message\ResponseInterface; 15 | use Psr\Http\Message\ServerRequestInterface; 16 | use Symfony\Component\HttpFoundation\Request; 17 | use Symfony\Component\HttpFoundation\Response; 18 | 19 | /** 20 | * Creates Symfony Request and Response instances from PSR-7 ones. 21 | * 22 | * @author Kévin Dunglas 23 | */ 24 | interface HttpFoundationFactoryInterface 25 | { 26 | /** 27 | * Creates a Symfony Request instance from a PSR-7 one. 28 | */ 29 | public function createRequest(ServerRequestInterface $psrRequest, bool $streamed = false): Request; 30 | 31 | /** 32 | * Creates a Symfony Response instance from a PSR-7 one. 33 | */ 34 | public function createResponse(ResponseInterface $psrResponse, bool $streamed = false): Response; 35 | } 36 | -------------------------------------------------------------------------------- /HttpMessageFactoryInterface.php: -------------------------------------------------------------------------------- 1 | 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; 13 | 14 | use Psr\Http\Message\ResponseInterface; 15 | use Psr\Http\Message\ServerRequestInterface; 16 | use Symfony\Component\HttpFoundation\Request; 17 | use Symfony\Component\HttpFoundation\Response; 18 | 19 | /** 20 | * Creates PSR HTTP Request and Response instances from Symfony ones. 21 | * 22 | * @author Kévin Dunglas 23 | */ 24 | interface HttpMessageFactoryInterface 25 | { 26 | /** 27 | * Creates a PSR-7 Request instance from a Symfony one. 28 | */ 29 | public function createRequest(Request $symfonyRequest): ServerRequestInterface; 30 | 31 | /** 32 | * Creates a PSR-7 Response instance from a Symfony one. 33 | */ 34 | public function createResponse(Response $symfonyResponse): ResponseInterface; 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-present Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PSR-7 Bridge 2 | ============ 3 | 4 | Provides integration for PSR7. 5 | 6 | Resources 7 | --------- 8 | 9 | * [Documentation](https://symfony.com/doc/current/components/psr7.html) 10 | * [Contributing](https://symfony.com/doc/current/contributing/index.html) 11 | * [Report issues](https://github.com/symfony/symfony/issues) and 12 | [send Pull Requests](https://github.com/symfony/symfony/pulls) 13 | in the [main Symfony repository](https://github.com/symfony/symfony) 14 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/psr-http-message-bridge", 3 | "type": "symfony-bridge", 4 | "description": "PSR HTTP message bridge", 5 | "keywords": ["http", "psr-7", "psr-17", "http-message"], 6 | "homepage": "https://symfony.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Fabien Potencier", 11 | "email": "fabien@symfony.com" 12 | }, 13 | { 14 | "name": "Symfony Community", 15 | "homepage": "https://symfony.com/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=8.2", 20 | "psr/http-message": "^1.0|^2.0", 21 | "symfony/http-foundation": "^6.4|^7.0" 22 | }, 23 | "require-dev": { 24 | "symfony/browser-kit": "^6.4|^7.0", 25 | "symfony/config": "^6.4|^7.0", 26 | "symfony/event-dispatcher": "^6.4|^7.0", 27 | "symfony/framework-bundle": "^6.4|^7.0", 28 | "symfony/http-kernel": "^6.4|^7.0", 29 | "nyholm/psr7": "^1.1", 30 | "php-http/discovery": "^1.15", 31 | "psr/log": "^1.1.4|^2|^3" 32 | }, 33 | "conflict": { 34 | "php-http/discovery": "<1.15", 35 | "symfony/http-kernel": "<6.4" 36 | }, 37 | "config": { 38 | "allow-plugins": { 39 | "php-http/discovery": false 40 | } 41 | }, 42 | "autoload": { 43 | "psr-4": { "Symfony\\Bridge\\PsrHttpMessage\\": "" }, 44 | "exclude-from-classmap": [ 45 | "/Tests/" 46 | ] 47 | }, 48 | "minimum-stability": "dev" 49 | } 50 | --------------------------------------------------------------------------------