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: Add the package via Composer in your Laravel project:
composer require symfony/psr-http-message-bridge
Laravel already includes symfony/http-foundation, so no additional dependencies are required.
First Use Case:
Convert a Laravel Request to a PSR-7 ServerRequest for use with PSR-7 middleware or libraries:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Psr\Http\Message\ServerRequestInterface;
$laravelRequest = request(); // Laravel's Request instance
$psrFactory = new PsrHttpFactory();
$psrRequest = $psrFactory->createRequest($laravelRequest);
Where to Look First:
Illuminate\Http\Request and Illuminate\Http\Response classes for context on conversions.Middleware Integration: Convert Laravel middleware to PSR-15 middleware for use in non-Laravel environments (e.g., Slim, Laminas):
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class LaravelMiddleware implements MiddlewareInterface {
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
$psrFactory = new PsrHttpFactory();
$laravelRequest = $psrFactory->createRequest($request);
$laravelResponse = app()->handle($laravelRequest); // Laravel's handle method
return $psrFactory->createResponse($laravelResponse);
}
}
HTTP Client Abstraction: Use PSR-7 responses with Laravel’s HTTP client (Guzzle-based):
use Illuminate\Support\Facades\Http;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
$response = Http::get('https://api.example.com');
$psrFactory = new PsrHttpFactory();
$psrResponse = $psrFactory->createResponse($response);
Testing: Mock PSR-7 requests/responses in Laravel tests:
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
$psrFactory = new Psr17Factory();
$psrRequest = $psrFactory->createServerRequest('GET', '/test');
$symfonyFactory = new PsrHttpFactory();
$laravelRequest = $symfonyFactory->createRequest($psrRequest);
// Use $laravelRequest in Laravel test cases
Request/Response Conversion Workflow:
Request to PSR-7 ServerRequest for PSR-7 middleware.Response back to Laravel Response for Laravel’s response handling.API Resource Sharing: Share API resources between Laravel and PSR-7-compliant services by converting responses:
$laravelResponse = response()->json(['data' => 'example']);
$psrFactory = new PsrHttpFactory();
$psrResponse = $psrFactory->createResponse($laravelResponse);
// Send $psrResponse to a PSR-7-compliant service
Event-Driven Architectures: Use PSR-7 messages in event-driven workflows (e.g., with Laravel Queues or message brokers):
$psrRequest = $psrFactory->createRequest(request());
// Dispatch $psrRequest to a message broker or queue
Service Provider Binding: Bind the bridge factory in Laravel’s service container for reusable conversions:
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Illuminate\Support\ServiceProvider;
class PsrHttpServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton(PsrHttpFactory::class, function () {
return new PsrHttpFactory();
});
}
}
Then inject PsrHttpFactory into controllers/middleware:
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
public function __construct(private PsrHttpFactory $psrFactory) {}
Middleware Pipeline: Integrate PSR-15 middleware into Laravel’s pipeline by wrapping it in a Laravel-compatible middleware:
use Psr\Http\Server\MiddlewareInterface;
use Closure;
class PsrMiddlewareWrapper {
public function __construct(private MiddlewareInterface $psrMiddleware) {}
public function handle($request, Closure $next) {
$psrFactory = app(PsrHttpFactory::class);
$psrRequest = $psrFactory->createRequest($request);
$psrResponse = $this->psrMiddleware->process($psrRequest, new PsrHandler($next));
return $psrFactory->createResponse($psrResponse);
}
}
Testing Utilities: Create helper methods for test conversions:
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
if (!function_exists('psrRequest')) {
function psrRequest(string $method, string $uri, array $server = []): ServerRequestInterface {
$psrFactory = new PsrHttpFactory();
$laravelRequest = Request::create($uri, $method, [], [], [], $server);
return $psrFactory->createRequest($laravelRequest);
}
}
Cookie Handling:
Cookie class and PSR-7’s CookieJarInterface may handle partitioned cookies differently. Ensure cookie logic is tested after conversion.$psrRequest = $psrFactory->createRequest($laravelRequest);
$cookies = $psrRequest->getCookieParams(); // May differ from Laravel's cookie bag
File Uploads:
UploadedFileInterface and Symfony’s UploadedFile may differ in stream handling. Large file uploads might behave unexpectedly.$uploadedFile = $psrRequest->getUploadedFiles()['file'];
$stream = $uploadedFile->getStream();
// Rewind or process stream as needed
Server Request Attributes:
ServerRequest extends Symfony\Component\HttpFoundation\Request, which is not a PSR-7 ServerRequestInterface. Some PSR-7 middleware may expect strict compliance.$psrRequest = $psrFactory->createRequest($laravelRequest);
$attributes = $psrRequest->getAttributes(); // May not include all Laravel-specific data
Response Status Codes:
Response and PSR-7 ResponseInterface handle status codes similarly, but custom responses might differ. Ensure status codes are preserved:
$laravelResponse = response()->setStatusCode(403);
$psrResponse = $psrFactory->createResponse($laravelResponse);
assert($psrResponse->getStatusCode() === 403);
Server Variables:
$_SERVER variables (e.g., PHP_SELF, REQUEST_METHOD) may not map perfectly to PSR-7’s ServerRequestInterface.$psrRequest = $psrFactory->createRequest($laravelRequest)
->withServerParams(array_merge(
$psrRequest->getServerParams(),
['REQUEST_METHOD' => 'GET']
));
Conversion Validation:
$psrRequest = $psrFactory->createRequest($laravelRequest);
\Log::debug('PSR-7 Server Params:', $psrRequest->getServerParams());
\Log::debug('PSR-7 Headers:', $psrRequest->getHeaders());
Middleware Debugging:
How can I help you explore Laravel packages today?