benjaminmal/exchangeratehost-bundle
Unofficial Symfony bundle for the free exchangerate.host API. PSR-7/17/18 compatible so you can choose your HTTP client and message factories, with built-in Symfony Cache support for faster, fewer requests. PHP 8.1+ and Symfony 6.2+.
Installation:
composer require benjaminmal/exchangeratehost-bundle nyholm/psr7 symfony/http-client
Add to config/app.php under providers:
Benjaminmal\ExchangeRateHostBundle\ExchangeRateHostBundle::class,
Configure API Key:
Add to .env:
EXCHANGERATEHOST_API_KEY=your_api_key_here
First Use Case: Inject the client into a service and fetch latest rates:
use Benjaminmal\ExchangeRateHostBundle\Client\ExchangeRateHostClientInterface;
class CurrencyService {
public function __construct(private ExchangeRateHostClientInterface $client) {}
public function getUsdRate() {
$rates = $this->client->getLatestRates(['symbols' => ['USD']]);
return $rates['USD'] ?? 0;
}
}
Currency Conversion:
$converted = $this->client->convertCurrency(
fromCurrency: 'EUR',
toCurrency: 'USD',
amount: 100.00
);
Historical Data:
$historical = $this->client->getHistoricalRates(
date: new DateTimeImmutable('-1 day')
);
Time-Series Analysis:
$series = $this->client->getTimeSeriesRates(
startDate: new DateTimeImmutable('-30 days'),
endDate: new DateTimeImmutable('-1 day')
);
Dependency Injection:
Prefer constructor injection for ExchangeRateHostClientInterface over facades for testability.
Cache Layer: Extend the default cache pool for granular control:
# config/cache.php
pools:
exchangeratehost.cache:
adapter: cache.adapter.redis
provider: 'redis://localhost'
Error Handling: Wrap API calls in try-catch blocks:
try {
$rates = $this->client->getLatestRates();
} catch (\RuntimeException $e) {
// Log or retry logic
}
Batch Processing:
Use getSupportedCurrencies() to pre-fetch all symbols before bulk operations.
Cache Invalidation:
6 0 * * * php artisan cache:clear exchangeratehost.cache
6 0 * * * for UTC+1).Rate Limits:
exchangerate_host:
cache:
enabled: true
pools:
latest_rates: 'exchangeratehost.cache'
Floating-Point Precision:
places option in LatestRatesOption to control decimal places (default: 4):
$rates = $this->client->getLatestRates([
'places' => 2,
]);
Type Safety:
convertCurrency() method returns int|float. Explicitly cast results:
$amount = (float) $this->client->convertCurrency(...);
Enable API Tracing:
Decorate the client with TraceableExchangeRateHostClient (built-in decorator) to log requests:
$this->client->withTrace(function ($request, $response) {
\Log::debug("API Call: {$request->getUri()}", [
'response' => $response->getBody()->getContents()
]);
});
Validate API Key: Test connectivity with a simple call:
$this->client->getLatestRates(['symbols' => ['USD']]);
If this fails, verify .env and API key permissions.
Custom Responses:
Override the default response parser by extending ExchangeRateHostClient:
class CustomClient extends ExchangeRateHostClient {
protected function parseResponse(ResponseInterface $response): array {
// Custom logic
}
}
Mocking for Tests: Use Symfony’s HTTP client mock:
$client = $this->createMock(ClientInterface::class);
$this->client->setHttpClient($client);
Async Processing: Offload heavy time-series requests to a queue:
dispatch(new ProcessTimeSeries($startDate, $endDate));
How can I help you explore Laravel packages today?