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

Exchanger Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require florianv/exchanger symfony/http-client nyholm/psr7
    

    Ensure PHP 8.2+ is used.

  2. 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);
    
  3. First Query:

    $query = (new ExchangeRateQueryBuilder('USD/EUR'))->build();
    $rate = $exchanger->getExchangeRate($query);
    $convertedAmount = 100 * $rate->getValue(); // Convert 100 USD to EUR
    

Where to Look First

  • 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.

First Use Case

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());

Implementation Patterns

Core Workflows

  1. Query Construction:

    $query = (new ExchangeRateQueryBuilder('USD/JPY'))
        ->setDate(new DateTime('2023-01-01')) // Historical rate
        ->build();
    
  2. 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);
    
  3. 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());
    

Integration Tips

  • Laravel: Use florianv/laravel-swap for built-in integration.
  • Symfony: Use florianv/symfony-swap for DI and config management.
  • Custom Providers: Implement Exchanger\Contract\ExchangeRateService for proprietary APIs.
  • Rate Limiting: Wrap HttpClient with middleware (e.g., Symfony\Contracts\HttpClient\RateLimitingMiddleware).

Advanced Patterns

  1. Dynamic Chain Composition:

    $chain = new Chain();
    $chain->addService(new FastForex(...));
    $chain->addService(new EuropeanCentralBank());
    
  2. Per-Query Options:

    $query = (new ExchangeRateQueryBuilder('USD/EUR'))
        ->setOptions(['timeout' => 5]) // Custom HTTP options
        ->build();
    
  3. Bulk Queries (if supported by provider):

    $query = (new ExchangeRateQueryBuilder())
        ->setCurrencyPairs(['USD/EUR', 'USD/GBP'])
        ->build();
    

Gotchas and Tips

Pitfalls

  1. API Key Management:

    • Hardcoding keys violates security best practices. Use environment variables or a secrets manager.
    • Some providers (e.g., EuropeanCentralBank) require no key but have rate limits.
  2. Fallback Behavior:

    • The 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.
      }
      
  3. Historical Data:

    • Not all providers support historical rates (e.g., WebserviceX). Check the provider table in the README.
    • Dates must be in a format the provider accepts (e.g., Y-m-d for ECB).
  4. Caching Quirks:

    • Cache keys are generated from the query. Modify ExchangeRateQueryBuilder or override Exchanger\Cache\CacheKeyGenerator for custom logic.
    • PSR-16 cache must be thread-safe if used in concurrent environments.
  5. PHP 8.2+ Requirements:

    • Older PHP versions (e.g., 8.1) will fail. Update dependencies if migrating:
      composer require php:^8.2
      

Debugging Tips

  1. Log Provider Responses:

    $service = new FastForex(null, null, ['api_key' => $key], [
        'debug' => true, // Enable debug logging
    ]);
    
  2. Inspect Exceptions:

    • ChainException contains a list of failed providers. Check $e->getPrevious() for details.
    • Use getProviderName() on ExchangeRate to identify the source of a rate.
  3. Validate Currency Pairs:

    • Some providers (e.g., 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.
      

Extension Points

  1. 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());
    
  2. 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());
    
  3. Provider-Specific Config:

    • Pass options to service constructors (e.g., FastForex supports ['timeout' => 10]).
    • Override default HTTP clients or request factories via dependency injection.

Performance Tips

  1. Cache Aggressively:

    • Exchange rates change infrequently. Use a long TTL (e.g., 1 hour) for non-real-time apps:
      $cache = new Psr16Cache(new Symfony\Component\Cache\Adapter\FilesystemAdapter('exchange_rates', 0, 3600));
      
  2. Bulk Queries:

    • If a provider supports bulk requests (e.g., fastFOREX), batch queries to reduce API calls:
      $query = (new ExchangeRateQueryBuilder())
          ->setCurrencyPairs(['USD/EUR', 'USD/GBP', 'USD/JPY'])
          ->build();
      
  3. Provider Selection:

    • Use free providers (e.g., EuropeanCentralBank) for EUR-base pairs to avoid API costs.
    • Reserve paid providers (e.g., fastFOREX) for non-EUR pairs or higher frequency.
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope