Installation:
composer require egeloen/http-adapter-bundle
Add to config/bundles.php (Symfony 4+):
return [
// ...
Ivory\HttpAdapterBundle\IvoryHttpAdapterBundle::class => ['all' => true],
];
First Use Case: Inject the adapter into a service/controller:
use Ivory\HttpAdapter\AdapterInterface;
use Ivory\HttpAdapter\CurlAdapter;
public function __construct(AdapterInterface $adapter)
{
$this->adapter = $adapter;
}
Make a request:
$response = $this->adapter->request('GET', 'https://api.example.com/data');
$body = $response->getBody();
Where to Look First:
src/Ivory/HttpAdapterBundle/Resources/config/services.xml (default services)src/Ivory/HttpAdapter/AdapterInterface.php (core interface)src/Ivory/HttpAdapter/CurlAdapter.php (default implementation)Dependency Injection:
Configure the adapter in config/packages/ivory_http_adapter.yaml:
ivory_http_adapter:
adapters:
default: ~ # Uses CurlAdapter by default
guzzle: Ivory\HttpAdapter\GuzzleAdapter
Use in services:
public function __construct(Ivory\HttpAdapter\AdapterInterface $adapter)
Request/Response Handling:
// GET request with headers
$response = $adapter->request('GET', 'https://api.example.com', [
'headers' => ['Authorization' => 'Bearer token'],
'timeout' => 10
]);
// POST with JSON body
$response = $adapter->request('POST', 'https://api.example.com', [
'body' => json_encode(['key' => 'value']),
'headers' => ['Content-Type' => 'application/json']
]);
Streaming Responses:
$response = $adapter->request('GET', 'https://large-file.example.com');
while (!$response->isEnd()) {
echo $response->read();
}
Middleware Integration:
Use Symfony’s HttpClient middleware or custom middleware:
$stack = HandlerStack::create();
$stack->push(Middleware::class);
$client = new Client(['handler' => $stack]);
$adapter = new Ivory\HttpAdapter\SymfonyHttpClientAdapter($client);
Testing:
Mock AdapterInterface in tests:
$mockAdapter = $this->createMock(AdapterInterface::class);
$mockAdapter->method('request')->willReturn(new Response(200, [], '{"test": "data"}'));
Deprecation Warning:
php-http. Prefer migrating to php-http/client or symfony/http-client for new projects.Adapter-Specific Quirks:
curl PHP extension. Configure timeouts carefully (default: 30s).
ivory_http_adapter:
adapters:
curl:
timeout: 15
options:
CURLOPT_FOLLOWLOCATION: true
guzzlehttp/guzzle (composer require guzzlehttp/guzzle).Response Handling:
$response->isSuccessful() before parsing:
if (!$response->isSuccessful()) {
throw new \RuntimeException('Request failed: ' . $response->getStatusCode());
}
$response->getBodyAsString() for simplicity (avoids manual streaming).Configuration Overrides:
config/packages/ivory_http_adapter.yaml. Override globally or per-service:
services:
App\Service\ApiClient:
arguments:
$adapter: '@ivory_http_adapter.curl'
Debugging:
ivory_http_adapter:
debug: true
monolog for logs (level: debug).Custom Adapters:
Implement AdapterInterface for new transports (e.g., SwooleAdapter):
class SwooleAdapter implements AdapterInterface {
public function request($method, $url, array $options = []) {
// Implement Swoole-specific logic
}
}
Register in services.yaml:
services:
App\Adapter\SwooleAdapter: ~
Middleware for Adapters: Wrap adapters with custom logic (e.g., retry, logging):
class LoggingAdapter implements AdapterInterface {
private $adapter;
public function __construct(AdapterInterface $adapter) {
$this->adapter = $adapter;
}
public function request($method, $url, array $options = []) {
\Log::debug("Request to $url", $options);
$response = $this->adapter->request($method, $url, $options);
\Log::debug("Response: " . $response->getStatusCode());
return $response;
}
}
Symfony Event Dispatcher: Dispatch events before/after requests:
$dispatcher->dispatch(new HttpRequestEvent($method, $url, $options));
$response = $adapter->request($method, $url, $options);
$dispatcher->dispatch(new HttpResponseEvent($response));
GuzzleAdapter with async clients for non-blocking calls:
$client = new \GuzzleHttp\Client(['async' => true]);
$adapter = new Ivory\HttpAdapter\GuzzleAdapter($client);
$promise = $adapter->requestAsync('GET', 'https://api.example.com');
How can I help you explore Laravel packages today?