Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Currency Laravel Package

dotdev/currency

PHP currency conversion component for objects, originally from the Sylius ecosystem. Provides a lightweight engine for converting between currencies in your applications. See Sylius docs for usage, contributions, and issue tracking.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require dotdev/currency
    

    Publish the configuration (if available):

    php artisan vendor:publish --tag="currency-config"
    
  2. Basic Usage: Register the service provider in config/app.php:

    Dotdev\Currency\CurrencyServiceProvider::class,
    

    Use the currency converter in a controller or service:

    use Dotdev\Currency\Converter\CurrencyConverterInterface;
    
    class PaymentController extends Controller
    {
        public function __construct(private CurrencyConverterInterface $converter)
        {
        }
    
        public function convert()
        {
            $amount = $this->converter->convert(100, 'USD', 'EUR');
            return response()->json(['amount' => $amount]);
        }
    }
    
  3. First Use Case: Convert a fixed amount between currencies (e.g., for a product price display):

    $priceInUSD = 100;
    $priceInEUR = $this->converter->convert($priceInUSD, 'USD', 'EUR');
    

Where to Look First

  • Documentation: Sylius Currency Component Docs
  • Source Code: Focus on src/Converter/CurrencyConverter.php for core logic.
  • Configuration: Check config/currency.php (if published) for default settings like base currency or rate sources.

Implementation Patterns

Usage Patterns

  1. Service Integration: Bind the CurrencyConverterInterface to a concrete implementation in Laravel’s service container:

    $this->app->bind(
        CurrencyConverterInterface::class,
        function ($app) {
            return new CurrencyConverter(
                $app->make(RateProviderInterface::class),
                $app->make(CurrencyRepositoryInterface::class)
            );
        }
    );
    
  2. Dynamic Rate Providers: Implement a custom RateProviderInterface to fetch rates from an external API (e.g., ECB):

    class EcbRateProvider implements RateProviderInterface
    {
        public function getRate(string $baseCurrency, string $targetCurrency): float
        {
            $response = Http::get("https://api.example.com/rates", [
                'base' => $baseCurrency,
                'target' => $targetCurrency,
            ]);
            return $response->object()->rate;
        }
    }
    
  3. Model Integration: Attach currency conversion to Eloquent models (e.g., Product):

    class Product extends Model
    {
        public function getPriceInCurrency(string $currency): float
        {
            return $this->converter->convert($this->price, $this->currency, $currency);
        }
    }
    
  4. Request-Based Conversion: Convert amounts based on user-selected currency (e.g., from session/locale):

    $userCurrency = session('currency', 'USD');
    $productPrice = $product->getPriceInCurrency($userCurrency);
    

Workflows

  1. Checkout Flow:

    • Convert cart total to user’s preferred currency before payment processing.
    • Store original and converted amounts for audit trails.
  2. API Responses:

    • Dynamically format monetary values in API responses:
      return response()->json([
          'price' => $this->converter->format($amount, $currency),
      ]);
      
  3. Admin Dashboard:

    • Display multi-currency reports (e.g., revenue by currency).

Integration Tips

  • Laravel Localization: Use Laravel’s App::setLocale() to ensure currency symbols/formatters align with user locale:

    App::setLocale($userLocale);
    $formattedPrice = $this->converter->format($amount, $currency);
    
  • Caching Rates: Cache API-fetched rates in Redis to reduce latency:

    $rate = Cache::remember(
        "currency_rate_{$base}_{$target}",
        now()->addHours(1),
        fn() => $this->rateProvider->getRate($base, $target)
    );
    
  • Fallback Rates: Provide fallback rates for unsupported currencies to avoid runtime errors:

    try {
        $rate = $this->rateProvider->getRate($base, $target);
    } catch (UnsupportedCurrencyException $e) {
        $rate = $this->fallbackRateProvider->getRate($base, $target);
    }
    
  • Testing: Mock the RateProviderInterface in tests to avoid external dependencies:

    $this->mock(RateProviderInterface::class)
         ->shouldReceive('getRate')
         ->with('USD', 'EUR')
         ->andReturn(0.85);
    

Gotchas and Tips

Pitfalls

  1. Precision Loss:

    • Avoid floating-point arithmetic for financial calculations. Use bcmath or gmp for high precision:
      $rate = bcdiv($amount, $rate, 6); // 6 decimal places
      
  2. Unsupported Currencies:

    • Always validate currencies before conversion to prevent exceptions:
      if (!$this->currencyRepository->isSupported($currency)) {
          throw new UnsupportedCurrencyException($currency);
      }
      
  3. Rate Source Dependencies:

    • If relying on external APIs, handle rate unavailability gracefully (e.g., fallback to cached rates or manual override).
  4. Time Zone Sensitivity:

    • Exchange rates may change daily. Ensure your rate provider accounts for the effective date/time of the conversion.
  5. Archived Package Risks:

    • The package is unmaintained. Fork it if you need long-term support or critical fixes.

Debugging

  • Log Conversions: Log conversion operations for auditability:

    \Log::debug('Currency conversion', [
        'amount' => $amount,
        'from' => $fromCurrency,
        'to' => $toCurrency,
        'rate' => $rate,
        'result' => $convertedAmount,
    ]);
    
  • Check Rate Sources: Verify rates are being fetched from the expected source (e.g., API, database):

    \Log::info('Fetched rate', [
        'base' => $baseCurrency,
        'target' => $targetCurrency,
        'rate' => $rate,
        'source' => method_exists($provider, 'getSource') ? $provider->getSource() : 'unknown',
    ]);
    
  • Test Edge Cases:

    • Zero amounts.
    • Extremely large amounts (overflow risk).
    • Invalid or malformed input (e.g., null, non-numeric strings).

Config Quirks

  • Default Currency: Ensure the default_currency in config matches your application’s primary currency to avoid silent failures.

  • Rate Update Frequency: If using a database-backed rate provider, schedule regular updates (e.g., via Laravel tasks):

    // app/Console/Commands/UpdateCurrencyRates.php
    public function handle()
    {
        $this->rateProvider->updateRates();
    }
    

    Register the command in app/Console/Kernel.php:

    protected function commands()
    {
        $this->load(__DIR__.'/Commands');
        $this->call('update:currency-rates');
    }
    

Extension Points

  1. Custom Formatters: Extend the CurrencyFormatterInterface to add locale-specific formatting:

    class CustomCurrencyFormatter implements CurrencyFormatterInterface
    {
        public function format(float $amount, string $currency): string
        {
            return number_format($amount, 2, ',', ' ') . ' ' . $currency;
        }
    }
    
  2. Bulk Conversions: Add a method to convert multiple amounts at once (e.g., for batch processing):

    public function convertBatch(array $amounts, string $fromCurrency, string $toCurrency): array
    {
        $rate = $this->getRate($fromCurrency, $toCurrency);
        return array_map(fn($amount) => $amount * $rate, $amounts);
    }
    
  3. Currency-Specific Logic: Implement currency-specific rules (e.g., tax calculations) via strategy pattern:

    class CurrencyStrategyFactory
    {
        public function create(string $currency): CurrencyStrategyInterface
        {
            return match ($currency) {
                'USD' => new UsdTaxStrategy(),
                'EUR' => new EurTaxStrategy(),
                default => new DefaultTaxStrategy(),
            };
        }
    }
    
  4. Event Dispatching: Dispatch events for currency conversions (e.g., CurrencyConverted) to trigger side effects:

    event(new CurrencyConverted(
        $amount,
        $fromCurrency,
        $toCurrency,
        $convertedAmount
    ));
    

Performance Tips

  • Avoid Repeated Rate Lookups: Cache rates for the duration of a request or user session:
    $rate = Cache::remember("user_{$userId}_rate_{$base}_{$target}", now()->
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky