Installation:
composer require sylius/currency
Add the service to your Laravel container (e.g., in config/app.php or a service provider):
$this->app->bind(CurrencyConverterInterface::class, function ($app) {
return new CurrencyConverter();
});
Define Currencies:
Register supported currencies in your config (e.g., config/currencies.php):
'currencies' => [
'USD' => ['code' => 'USD', 'name' => 'US Dollar', 'symbol' => '$'],
'EUR' => ['code' => 'EUR', 'name' => 'Euro', 'symbol' => '€'],
],
First Use Case: Convert a value from one currency to another:
$converter = app(CurrencyConverterInterface::class);
$amount = $converter->convert(100, 'USD', 'EUR'); // Returns ~82.61 (using default exchange rates)
src/CurrencyConverter.php for core logic.src/Exception/ for error handling (e.g., UnsupportedCurrencyException).Currency Conversion:
// Convert a fixed amount (e.g., for pricing)
$priceInEur = $converter->convert(100, 'USD', 'EUR');
// Convert with precision control (e.g., for financial calculations)
$converter->convert(100, 'USD', 'EUR', 4); // Round to 4 decimal places
Dynamic Exchange Rates:
Extend CurrencyConverter to fetch real-time rates from an API (e.g., ExchangeRate-API):
class ApiCurrencyConverter extends CurrencyConverter
{
public function getRate(string $from, string $to): float
{
$response = Http::get("https://api.exchangerate-api.com/v4/latest/{$from}");
return $response['rates'][$to];
}
}
Context-Aware Conversion:
Attach conversion logic to domain objects (e.g., Order, Product):
class Order
{
public function getTotalInCurrency(string $currency): float
{
return app(CurrencyConverterInterface::class)
->convert($this->total, $this->currency, $currency);
}
}
Fallback Rates: Define fallback rates in config for unsupported pairs:
'fallback_rates' => [
'USD' => ['EUR' => 0.8261, 'GBP' => 0.7346],
],
return response()->json([
'price' => [
'amount' => $product->price,
'currency' => $product->currency,
],
]);
Precision Loss: Floating-point arithmetic can cause rounding errors. Always specify precision:
$converter->convert(100, 'USD', 'EUR', 6); // Avoids 0.0001 discrepancies
Unsupported Currencies:
The package throws UnsupportedCurrencyException if a currency isn’t registered. Validate input early:
if (!$converter->supports('XYZ')) {
throw new InvalidArgumentException('Unsupported currency: XYZ');
}
Circular Dependencies:
Avoid recursive conversions (e.g., USD → EUR → USD). Cache rates or use a directed graph to detect cycles.
Static Exchange Rates:
The default implementation uses hardcoded rates. For production, always override getRate() to fetch live data.
Rate Calculation:
Override getRate() to log intermediate values:
public function getRate(string $from, string $to): float
{
$rate = parent::getRate($from, $to);
\Log::debug("Rate {$from}→{$to}: {$rate}");
return $rate;
}
Precision Issues:
Use PHP’s bcmath or gmp extensions for high-precision calculations:
$converter->convert(100, 'USD', 'EUR', 10, 'bcmath');
Custom Rate Providers:
Implement RateProviderInterface for external APIs or databases:
class DatabaseRateProvider implements RateProviderInterface
{
public function getRate(string $from, string $to): float
{
return DB::table('exchange_rates')
->where('from', $from)
->where('to', $to)
->value('rate');
}
}
Currency Formatting:
Extend CurrencyConverter to add locale-aware formatting:
class LocalizedCurrencyConverter extends CurrencyConverter
{
public function format(float $amount, string $currency, string $locale = 'en_US'): string
{
$formatter = NumberFormatter::create($locale, NumberFormatter::CURRENCY);
return $formatter->formatCurrency($amount, $currency);
}
}
Event-Driven Updates:
Dispatch events when rates change (e.g., CurrencyRateUpdated):
event(new CurrencyRateUpdated($from, $to, $newRate));
USD, eur) are case-sensitive by default. Normalize them in your config:
'currencies' => [
strtoupper('usd') => [...],
],
null issues:
'default_currency' => 'USD',
How can I help you explore Laravel packages today?