loophp/psr-http-message-bridge-bundle
Symfony bundle that bridges PSR-7 HTTP messages with Symfony’s HttpFoundation, enabling smooth interop between PSR-7 libraries and Symfony apps. Provides converters/adapters to translate requests and responses in both directions.
Symfony v8 Dependency Impact:
symfony/http-foundation:^8.0), which may conflict with Laravel’s default symfony/http-foundation:^6.3 (as of Laravel 10.x).symfony/http-foundation (v6.x) is not backward-compatible with Symfony 8.x’s breaking changes (e.g., HttpFoundation API adjustments, Stream interface changes).symfony/http-foundation:^6.3 for Laravel core while injecting Symfony 8.x for the bundle), increasing complexity.PSR-15/17 Stability:
RequestFactory, StreamFactory) are stable, but Laravel’s native Illuminate\Http may diverge in future versions.UploadedFile methods), or is this a version lock-in risk?Use Case Fit (Unchanged):
Request/Response suffice or if php-http/message-factory is sufficient.Core Dependencies (Updated):
symfony/http-foundation:^8.0 replaces v6.x, requiring:
composer require symfony/http-foundation:^8.0 --with-all-dependencies in a separate namespace or via path aliases.AppServiceProvider must explicitly bind Symfony 8.x factories to avoid conflicts with Laravel’s v6.x dependencies.
$this->app->bind(\Symfony\Component\HttpFoundation\RequestFactory::class, function () {
return new \Symfony\Component\HttpFoundation\RequestFactory(); // Symfony 8.x
});
Key Challenges (Amplified):
symfony/http-foundation in the same app introduces:
Stream or FileBag changes may break existing Laravel middleware.HttpFoundation may fail if Laravel’s Illuminate\Http objects are passed (e.g., UploadedFile differences).HttpFoundation will fail; mocking must account for v8.x changes.| Risk Area | Severity (Updated) | Mitigation Strategy |
|---|---|---|
| Dependency Conflict | Critical | Isolate Symfony 8.x in a child namespace or use composer.json aliases. |
| API Breaking Changes | High | Test with Symfony 8.x’s HttpFoundation early; patch Laravel middleware. |
| Middleware Gaps | Medium | Implement dual-adapter middleware (handles both Laravel and Symfony objects). |
| Long-Term Maintenance | High | Monitor for Laravel 11+ or Symfony 8.x support in the bundle. |
| Composer Complexity | Medium | Use config.platform in composer.json to enforce version constraints. |
Stream improvements, UploadedFile changes), or is this a version lock-in?Request objects? If the latter, a dual-adapter layer is mandatory.php-http/message-factory (PSR-17, Symfony-agnostic) a viable alternative?symfony/http-foundation?Laravel + Symfony 8.x Compatibility Matrix:
| Laravel Version | Symfony HTTP Foundation | Conflict Level | Notes |
|---|---|---|---|
| 10.x | v6.x (default) | High | Symfony 8.x requires manual isolation. |
| 10.x | v8.x (bundle) | Critical | Dependency collision without namespacing. |
| 11.x (future) | v7.x/v8.x? | Unknown | Laravel may align with Symfony 8.x. |
Key Components to Replace/Extend:
HttpFoundationFactory: Must be explicitly bound in Laravel’s container.Request and Symfony Request objects.UploadedFile API differs from Laravel’s; middleware must normalize.Phase 0: Dependency Isolation
composer.json with a child namespace or config.platform:
"config": {
"platform": {
"symfony/http-foundation": "8.0.0"
}
},
"extra": {
"symfony-8": {
"directory": "vendor/symfony-8",
"require": {
"symfony/http-foundation": "^8.0"
}
}
}
composer require symfony/http-foundation:^8.0 --with-all-dependencies --ignore-platform-reqs.Phase 1: Service Binding
AppServiceProvider:
use Symfony\Component\HttpFoundation\RequestFactory;
use Symfony\Component\HttpFoundation\StreamedResponse;
public function register() {
$this->app->singleton(\Psr\Http\Message\RequestFactoryInterface::class, function () {
return new RequestFactory(); // Symfony 8.x
});
$this->app->bind(StreamedResponse::class, function () {
return new StreamedResponse(); // Symfony 8.x
});
}
Phase 2: Dual Middleware Adapter
use Psr\Http\Server\RequestHandlerInterface;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Illuminate\Http\Request as LaravelRequest;
class DualRequestHandler implements RequestHandlerInterface {
public function handle(SymfonyRequest|LaravelRequest $request, RequestHandlerInterface $handler) {
$symfonyRequest = $request instanceof LaravelRequest
? $this->toSymfonyRequest($request)
: $request;
$response = $handler->handle($symfonyRequest, $handler);
return $response;
}
protected function toSymfonyRequest(LaravelRequest $request) {
// Convert Laravel Request to Symfony 8.x Request
return RequestFactory::createFromGlobals()
->duplicate([], [], $request->query->all(), $request->request->all(), $request->files->all(), $request->server->all());
}
}
Phase 3: Testing
$symfonyRequest = $this->createMock(SymfonyRequest::class);
$symfonyRequest->method('getContent')->willReturn('test');
UploadedFile, Stream).JsonResponse changes).Request/Response (PSR-7) or `php-How can I help you explore Laravel packages today?