florianv/exchanger
PHP exchange-rate provider layer with 31 services behind one ExchangeRateService interface. Supports historical rates, PSR-16 caching, and chainable fallback across providers (commercial APIs, ECB, national banks, exchangerate.host) for fine-grained control.
Installation:
composer require florianv/exchanger symfony/http-client nyholm/psr7
Ensure PHP 8.2+ is used.
Basic Setup:
use Exchanger\Exchanger;
use Exchanger\ExchangeRateQueryBuilder;
use Exchanger\Service\FastForex;
$service = new FastForex(null, null, ['api_key' => env('FASTFOREX_API_KEY')]);
$exchanger = new Exchanger($service);
First Query:
$query = (new ExchangeRateQueryBuilder('USD/EUR'))->build();
$rate = $exchanger->getExchangeRate($query);
$convertedAmount = 100 * $rate->getValue(); // Convert 100 USD to EUR
ExchangeRateQueryBuilder: Construct queries for rates (current/historical).Exchanger class: Core service for fetching rates.Service implementations: Pre-built providers (e.g., FastForex, EuropeanCentralBank).Chain: For fallback logic across multiple providers.Convert an amount with a fallback:
use Exchanger\Service\Chain;
$chain = new Chain([
new FastForex(null, null, ['api_key' => env('FASTFOREX_API_KEY')]),
new EuropeanCentralBank(), // Fallback for EUR-base pairs
]);
$exchanger = new Exchanger($chain);
$rate = $exchanger->getExchangeRate((new ExchangeRateQueryBuilder('EUR/USD'))->build());
Query Construction:
$query = (new ExchangeRateQueryBuilder('USD/JPY'))
->setDate(new DateTime('2023-01-01')) // Historical rate
->build();
Caching Integration (PSR-16):
use Psr\SimpleCache\CacheInterface;
use Exchanger\Cache\Psr16Cache;
$cache = new Psr16Cache(new Symfony\Component\Cache\Adapter\FilesystemAdapter());
$exchanger = new Exchanger($service, $cache);
Middleware Injection (e.g., logging, retries):
use Exchanger\Service\HttpService;
use Symfony\Contracts\HttpClient\HttpClientInterface;
$client = HttpClient::create([
'base_uri' => 'https://api.fastforex.io',
'headers' => ['Authorization' => 'Bearer ' . env('FASTFOREX_API_KEY')],
]);
$service = new HttpService($client, new ExchangeRateQueryBuilder());
florianv/laravel-swap for built-in integration.florianv/symfony-swap for DI and config management.Exchanger\Contract\ExchangeRateService for proprietary APIs.HttpClient with middleware (e.g., Symfony\Contracts\HttpClient\RateLimitingMiddleware).Dynamic Chain Composition:
$chain = new Chain();
$chain->addService(new FastForex(...));
$chain->addService(new EuropeanCentralBank());
Per-Query Options:
$query = (new ExchangeRateQueryBuilder('USD/EUR'))
->setOptions(['timeout' => 5]) // Custom HTTP options
->build();
Bulk Queries (if supported by provider):
$query = (new ExchangeRateQueryBuilder())
->setCurrencyPairs(['USD/EUR', 'USD/GBP'])
->build();
API Key Management:
EuropeanCentralBank) require no key but have rate limits.Fallback Behavior:
Chain skips unsupported currency pairs silently. Use try-catch to handle ChainException:
try {
$rate = $exchanger->getExchangeRate($query);
} catch (ChainException $e) {
// Log or notify: All providers failed.
}
Historical Data:
WebserviceX). Check the provider table in the README.Y-m-d for ECB).Caching Quirks:
ExchangeRateQueryBuilder or override Exchanger\Cache\CacheKeyGenerator for custom logic.PHP 8.2+ Requirements:
composer require php:^8.2
Log Provider Responses:
$service = new FastForex(null, null, ['api_key' => $key], [
'debug' => true, // Enable debug logging
]);
Inspect Exceptions:
ChainException contains a list of failed providers. Check $e->getPrevious() for details.getProviderName() on ExchangeRate to identify the source of a rate.Validate Currency Pairs:
EuropeanCentralBank) only support EUR as the base currency. Test edge cases:
$query = (new ExchangeRateQueryBuilder('JPY/USD'))->build();
// May fail silently or throw if the provider doesn’t support it.
Custom Cache Key Generation:
use Exchanger\Cache\CacheKeyGenerator;
class CustomKeyGenerator implements CacheKeyGenerator {
public function generateKey(ExchangeRateQuery $query): string {
return 'custom_prefix_' . $query->getCurrencyPair();
}
}
$exchanger = new Exchanger($service, $cache, new CustomKeyGenerator());
HTTP Middleware:
use Exchanger\Service\HttpService;
use Symfony\Contracts\HttpClient\HttpClientInterface;
$client = HttpClient::create(['base_uri' => 'https://api.example.com']);
$client->withOptions(['auth_bearer' => env('API_KEY')]);
$service = new HttpService($client, new ExchangeRateQueryBuilder());
Provider-Specific Config:
FastForex supports ['timeout' => 10]).Cache Aggressively:
$cache = new Psr16Cache(new Symfony\Component\Cache\Adapter\FilesystemAdapter('exchange_rates', 0, 3600));
Bulk Queries:
fastFOREX), batch queries to reduce API calls:
$query = (new ExchangeRateQueryBuilder())
->setCurrencyPairs(['USD/EUR', 'USD/GBP', 'USD/JPY'])
->build();
Provider Selection:
EuropeanCentralBank) for EUR-base pairs to avoid API costs.fastFOREX) for non-EUR pairs or higher frequency.How can I help you explore Laravel packages today?