psr-discovery/http-factory-implementations
Discovers a PSR-17 HTTP factory at runtime by scanning for well-known implementations and returning the first available instance. Ideal for libraries/SDKs that want PSR-17 support without hard dependencies or user configuration. PHP 8.2+.
Install the package in your Laravel project (preferably as a dev dependency):
composer require --dev psr-discovery/http-factory-implementations
Ensure a PSR-17 implementation is available (e.g., nyholm/psr7 or guzzlehttp/psr7):
composer require nyholm/psr7
First use case: Instantiating a PSR-17 factory in a Laravel service:
use PsrDiscovery\Discover;
$requestFactory = Discover::httpRequestFactory();
$request = $requestFactory->createRequest('GET', '/api/users');
Discover facade: Central entry point for all PSR-17 factories.Dependency Injection: Bind discovered factories in a service provider:
public function register()
{
$this->app->singleton(\Psr\Http\Message\RequestFactoryInterface::class,
fn() => Discover::httpRequestFactory(singleton: true));
}
HTTP Client Integration: Use with Laravel HTTP clients (e.g., Guzzle) or SDKs:
$client = new \GuzzleHttp\Client([
'handler' => \Http\Discovery\Psr18ClientDiscovery::find(),
'request_factory' => Discover::httpRequestFactory(),
]);
Testing: Mock factories automatically in tests (no manual setup):
public function testApiRequest()
{
$requestFactory = Discover::httpRequestFactory();
$request = $requestFactory->createRequest('POST', '/login');
// Test logic...
}
public function handle($request, Closure $next)
{
$psrRequest = Discover::httpRequestFactory()->createRequest(
$request->method(),
$request->url()
);
// ...
}
UploadedFileFactoryInterface for file uploads:
$uploadedFileFactory = Discover::httpUploadedFileFactory();
$uploadedFile = $uploadedFileFactory->createUploadedFile(
'/path/to/file', 'filename.txt', 'text/plain', 1024, UPLOAD_ERR_OK
);
UriFactoryInterface for URI manipulation:
$uriFactory = Discover::httpUriFactory();
$uri = $uriFactory->createUri('https://example.com/api');
Null Returns:
null when no implementation is found:
$factory = Discover::httpRequestFactory();
if (!$factory) {
throw new \RuntimeException('No PSR-17 factory available');
}
nyholm/psr7).Mocking Overrides:
Discover::httpRequestFactory(); // Uses mock if available
Discover::httpRequestFactory(singleton: true); // May bypass mocks
Singleton Behavior:
singleton: true) caches the first discovered instance. Use sparingly in tests to avoid side effects.composer.json for PSR-17 packages (e.g., nyholm/psr7, guzzlehttp/psr7).\PsrDiscovery\Implementations\Psr17\RequestFactories::prefer('nyholm/psr7');
$factory = Discover::httpRequestFactory(); // Logs selected class
Custom Implementations:
Extend the discovery list by modifying the package’s Implementations class or submitting a PR to the upstream repo.
Conditional Discovery: Override discovery logic in a service provider:
Discover::httpRequestFactory(); // Default behavior
// OR
$factory = new \Nyholm\Psr7\Factory\Psr17Factory(); // Hardcoded
Performance: Cache discovered factories in Laravel’s cache:
$factory = cache()->remember('psr17.request_factory', 3600, fn() =>
Discover::httpRequestFactory(singleton: true)
);
$this->app->bind(\Psr\Http\Message\RequestFactoryInterface::class,
fn() => Discover::httpRequestFactory()
);
RefreshDatabase or MigrateFresh traits alongside mock factories for isolated tests.config/services.php:
'psr17' => [
'request_factory' => 'nyholm/psr7',
],
Then access via:
config('services.psr17.request_factory');
How can I help you explore Laravel packages today?