symfony/psr-http-message-bridge
Symfony PSR-7 Bridge integrates PSR-7 HTTP messages with Symfony’s HttpFoundation. Convert requests and responses between PSR-7 implementations and Symfony components to ease interoperability with middleware and libraries.
Installation:
composer require symfony/psr-http-message-bridge
No additional configuration is required—this is a zero-config package.
First Use Case:
Convert between Symfony’s HttpFoundation (e.g., Request, Response) and PSR-7 (Psr\Http\Message\* interfaces).
Example:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Psr\Http\Message\ServerRequestInterface;
$request = Request::createFromGlobals();
$psrFactory = new PsrHttpFactory();
$psrRequest = $psrFactory->createRequest($request); // PSR-7 Request
Where to Look First:
src/Factory/ for core conversion logic (PsrHttpFactory, HttpFoundationFactory).tests/ for edge-case examples (e.g., handling cookies, headers, or streams).Bidirectional Conversion:
Use PsrHttpFactory (PSR-7 → Symfony) and HttpFoundationFactory (Symfony → PSR-7) for seamless integration.
$psrFactory = new PsrHttpFactory();
$symfonyFactory = new HttpFoundationFactory();
// PSR-7 → Symfony
$symfonyRequest = $symfonyFactory->createRequest($psrRequest);
// Symfony → PSR-7
$psrResponse = $psrFactory->createResponse($symfonyResponse);
Middleware Integration:
Bridge PSR-15 middleware (e.g., from zend-stratigility or league/plates) with Laravel’s middleware stack.
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
$psrMiddleware = new Psr15Middleware();
$handler = new class implements RequestHandlerInterface {
public function handle(ServerRequestInterface $request): ResponseInterface {
return new Response();
}
};
$psrResponse = $psrMiddleware->process($psrRequest, $handler);
$symfonyResponse = $symfonyFactory->createResponse($psrResponse);
Stream Handling:
Convert Symfony’s StreamInterface (e.g., file uploads) to PSR-7 StreamInterface:
$symfonyStream = $request->getClientOriginalExtension('file');
$psrStream = $psrFactory->createStream($symfonyStream);
Laravel-Specific Patterns:
Illuminate\Http\Request/Response with PSR-7 methods via traits or decorators.
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
class Psr7Request extends Request {
protected $psrFactory;
public function __construct(Request $request) {
$this->psrFactory = new PsrHttpFactory();
}
public function toPsr7(): ServerRequestInterface {
return $this->psrFactory->createRequest($this);
}
}
Kernel.php:
protected function psrMiddleware(): array {
return [
\Symfony\Component\HttpKernel\Middleware\CheckReferer::class,
];
}
public function boot() {
$this->app->make(\Illuminate\Contracts\Http\Kernel::class)->push(
app()->make(\Symfony\Component\HttpKernel\HttpKernel::class)
);
}
Header Case Sensitivity:
PSR-7 headers are case-insensitive, but Symfony’s HttpFoundation preserves original case. Use normalizeHeaderName() if consistency is critical:
$psrRequest->getHeaderLine('Content-Type'); // Normalized
Stream Detachment: PSR-7 streams must not be detached after conversion. Symfony’s streams may behave differently:
// ❌ Avoid detaching PSR-7 streams post-conversion
$psrStream->detach(); // May break Symfony's internal state
Cookie Handling:
Symfony’s Cookie class differs from PSR-7’s Cookie interface. Use PsrHttpFactory::createCookie() for explicit conversion:
$symfonyCookie = new Cookie('name', 'value');
$psrCookie = $psrFactory->createCookie($symfonyCookie);
Uploaded Files:
PSR-7’s UploadedFileInterface is a subset of Symfony’s UploadedFile. Ensure all methods (e.g., moveTo()) are handled:
$symfonyFile = $request->file('upload');
$psrFile = $psrFactory->createUploadedFile($symfonyFile);
// $psrFile->moveTo() may not work; use Symfony's original methods if needed.
Validate PSR-7 Compliance:
Use Psr\Http\Message\MessageInterface::getBody() to inspect streams/headers:
$psrRequest->getBody()->rewind();
$headers = iterator_to_array($psrRequest->getHeaders());
Logging Conversions: Log before/after conversion to catch silent failures:
\Log::debug('Symfony Request', [
'method' => $request->getMethod(),
'uri' => $request->getUri(),
]);
Extension Points:
PsrHttpFactory to customize conversions (e.g., modify headers):
class CustomPsrHttpFactory extends PsrHttpFactory {
public function createRequest(Request $request): ServerRequestInterface {
$psrRequest = parent::createRequest($request);
$psrRequest = $psrRequest->withHeader('X-Custom', 'value');
return $psrRequest;
}
}
HttpFoundationFactory::createResponse() to inject PSR-7-specific logic.$psrRequest = app()->bound('psr.request')
?? app()->instance('psr.request', $psrFactory->createRequest(request()));
$stream = $psrRequest->getBody();
$streamCopy = fopen('php://temp', 'r+');
stream_copy_to_stream($stream, $streamCopy);
$streamCopy->rewind();
How can I help you explore Laravel packages today?