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

Swap Laravel Package

florianv/swap

PHP 8.2+ currency exchange rate library with a single API over 30+ providers. Supports conversion, historical rates, PSR-16 caching, and provider fallback. Works with PSR-18 HTTP clients and PSR-17 factories for flexible integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

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

    Ensure your Laravel project uses PHP 8.2+.

  2. Basic Setup:

    use Swap\Builder;
    
    $swap = (new Builder())
        ->add('fastforex', ['api_key' => env('FASTFOREX_API_KEY')])
        ->build();
    
  3. First Use Case: Fetch and use the latest EUR/USD rate:

    $rate = $swap->latest('EUR/USD');
    $amountInUSD = 100.00 * $rate->getValue();
    
  4. Fallback Setup (for production):

    $swap = (new Builder())
        ->add('fastforex', ['api_key' => env('FASTFOREX_API_KEY')])
        ->add('european_central_bank') // Free fallback for EUR pairs
        ->build();
    

Where to Look First

  • README.md: Quickstart guide and provider list.
  • docs/readme.md: Technical reference for caching, HTTP clients, and provider configs.
  • Swap\Builder class: Core configuration and provider registration.
  • Swap\Swap class: Main API for fetching rates.

Implementation Patterns

Core Workflows

  1. Rate Retrieval:

    // Latest rate
    $rate = $swap->latest('USD/JPY');
    
    // Historical rate (e.g., 2023-01-01)
    $rate = $swap->historical('USD/JPY', '2023-01-01');
    
  2. Amount Conversion:

    $amount = 100.00;
    $converted = $amount * $swap->latest('EUR/USD')->getValue();
    
  3. Multi-Currency Pricing (e.g., in a Laravel e-commerce app):

    $prices = collect($products)->map(function ($product) {
        $rate = $swap->latest($product->currency . '/USD');
        return $product->price * $rate->getValue();
    });
    
  4. Caching Integration:

    $swap = (new Builder())
        ->add('fastforex', ['api_key' => env('FASTFOREX_API_KEY')])
        ->useCache(new \Symfony\Component\Cache\Adapter\FilesystemAdapter())
        ->build();
    

Integration Tips

  • Laravel Service Provider: Bind Swap\Swap to the container in AppServiceProvider:

    public function register()
    {
        $this->app->singleton(Swap::class, function ($app) {
            return (new Builder())
                ->add('fastforex', ['api_key' => env('FASTFOREX_API_KEY')])
                ->useCache($app['cache'])
                ->build();
        });
    }
    
  • Dependency Injection: Inject Swap\Swap into controllers/services:

    public function __construct(private Swap $swap) {}
    
  • Rate Validation: Validate rates before conversion (e.g., check getValue() is not null or 0):

    $rate = $swap->latest('EUR/USD');
    if ($rate->getValue() === null) {
        throw new \RuntimeException("Failed to fetch EUR/USD rate");
    }
    
  • Fallback Logic: Use the fallback chain for critical paths (e.g., payment processing):

    try {
        $rate = $swap->latest('USD/GBP');
    } catch (\Swap\Exception\ChainException $e) {
        // Log errors and notify admins
        \Log::error('All FX providers failed', ['errors' => $e->getErrors()]);
        throw new \RuntimeException("Currency conversion unavailable");
    }
    
  • Historical Data: Fetch historical rates for audits/reconciliation:

    $historicalRate = $swap->historical('EUR/USD', '2023-12-31');
    

Advanced Patterns

  1. Dynamic Provider Selection: Use environment variables to switch providers:

    $provider = env('FX_PROVIDER', 'fastforex');
    $swap = (new Builder())
        ->add($provider, ['api_key' => env('FX_API_KEY')])
        ->build();
    
  2. Rate Monitoring: Log provider performance (e.g., response times) for observability:

    $start = microtime(true);
    $rate = $swap->latest('USD/JPY');
    \Log::debug('FX rate fetch time', [
        'pair' => 'USD/JPY',
        'time_ms' => (microtime(true) - $start) * 1000,
        'provider' => $rate->getProviderName()
    ]);
    
  3. Custom Providers: Extend functionality by implementing Exchanger\Contract\ExchangeRateService:

    use Exchanger\Contract\ExchangeRateService;
    
    class CustomProvider implements ExchangeRateService {
        public function getLatest(string $base, string $quote): ?float { /* ... */ }
        public function getHistorical(string $base, string $quote, string $date): ?float { /* ... */ }
    }
    
    $swap = (new Builder())
        ->addExchangeRateService(new CustomProvider())
        ->build();
    

Gotchas and Tips

Pitfalls

  1. API Key Management:

    • Gotcha: Hardcoding API keys in code violates security best practices.
    • Fix: Use Laravel's .env and env() helper:
      ->add('fastforex', ['api_key' => env('FASTFOREX_API_KEY')])
      
    • Tip: Rotate API keys periodically and store them in Laravel Vault or AWS Secrets Manager for production.
  2. Rate Availability:

    • Gotcha: Not all providers support every currency pair (e.g., european_central_bank only supports EUR-base pairs).
    • Fix: Check provider docs or test pairs before relying on them in production.
    • Tip: Use fastforex or apilayer_currency_data for broad coverage.
  3. Caching Quirks:

    • Gotcha: Caching historical rates with a TTL may return stale data if rates change frequently.
    • Fix: Use shorter TTLs (e.g., 5 minutes) for volatile pairs like cryptocurrencies.
    • Tip: Cache keys include the provider name, so ensure consistent provider selection.
  4. Fallback Behavior:

    • Gotcha: Silent skips of unsupported pairs can lead to unexpected null values.
    • Fix: Validate rates post-fetch:
      $rate = $swap->latest('USD/XYZ'); // XYZ may not be supported
      if ($rate === null) {
          throw new \InvalidArgumentException("Unsupported currency pair: USD/XYZ");
      }
      
  5. Rate Precision:

    • Gotcha: Floating-point arithmetic can introduce rounding errors in conversions.
    • Fix: Use bcmath or gmp for high-precision calculations:
      $amountInUSD = bcdiv($amountInEUR, $rate->getValue(), 6);
      
    • Tip: Store converted amounts in a database with sufficient decimal places (e.g., decimal(19,6)).
  6. Rate Freshness:

    • Gotcha: Free providers (e.g., european_central_bank) update less frequently (daily vs. real-time).
    • Fix: Combine free providers with a paid one for critical paths:
      ->add('fastforex', ['api_key' => env('FASTFOREX_API_KEY')])
      ->add('european_central_bank') // Fallback for EUR pairs
      
  7. HTTP Client Conflicts:

    • Gotcha: Mixing symfony/http-client and Guzzle may cause issues if not configured properly.
    • Fix: Stick to one PSR-18 client per project. Example with Guzzle:
      $client = new \GuzzleHttp\Client();
      $swap = (new Builder())
          ->useHttpClient($client)
          ->add('fastforex', ['api_key' => env('FASTFOREX_API_KEY')])
          ->build();
      

Debugging Tips

  1. Enable Debug Logging: Configure Monolog to log Swap requests/responses:

    \Log::debug('FX request', [
        'pair' => 'EUR/USD',
        'provider' => 'fastforex',
        'response' => $rate->getRawData() // If available
    ]);
    
  2. Inspect Provider Errors: Catch ChainException to debug fallback failures:

    try {
        $rate = $swap->latest('USD/JPY');
    } catch (\Swap\Exception\ChainException $e
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
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