Weave 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

Open Exchange Rates Bundle Laravel Package

mrzard/open-exchange-rates-bundle

A Symfony bundle that integrates the Open Exchange Rates API, giving your app currency conversion and live exchange rate lookups through a simple, configurable service.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony2 bundle, not a Laravel package. Before writing any integration code, confirm framework fit:

  • If the target app is Laravel, do not install mrzard/open-exchange-rates-bundle directly. It registers a Symfony bundle and expects Symfony's DI/configuration stack. Use the underlying mrzard/open-exchange-rates client directly, or a maintained Laravel-friendly client, and wire it through a Laravel service provider.
  • If the target app is Symfony2, install with Composer, register Mrzard\OpenExchangeRatesBundle\MrzardOpenExchangeRatesBundle in AppKernel, and import the bundle configuration.

Minimal Symfony2 setup:

// app/AppKernel.php
$bundles = [
    // ...
    new Mrzard\OpenExchangeRatesBundle\MrzardOpenExchangeRatesBundle(),
];
# app/config/config.yml
mrzard_open_exchange_rates:
    app_id: "%open_exchange_rates_app_id%"
# app/config/parameters.yml
parameters:
    open_exchange_rates_app_id: "%env(OPEN_EXCHANGE_RATES_APP_ID)%"

Where to look first:

  1. DependencyInjection/Configuration.php — the authoritative list of supported config keys.
  2. Resources/config/services.xml — the exact service ID/alias to inject. Do not guess it; confirm it with php app/console debug:container | grep -i exchange.
  3. The bundle README and the underlying mrzard/open-exchange-rates client API for available methods.

First use case: inject the bundle's client into a controller or console command, fetch latest USD-based rates, and convert a known amount. Wrap it in your own service immediately rather than calling the vendor client throughout the app.

// src/AppBundle/Service/CurrencyConverter.php
namespace AppBundle\Service;

class CurrencyConverter
{
    private $ratesClient;

    public function __construct($ratesClient)
    {
        $this->ratesClient = $ratesClient;
    }

    public function convert($amount, $from, $to)
    {
        $rates = $this->ratesClient->getLatest(); // confirm exact method name
        $fromRate = $rates['rates'][$from] ?? null;
        $toRate = $rates['rates'][$to] ?? null;

        if ($fromRate === null || $toRate === null) {
            throw new \InvalidArgumentException('Unsupported currency pair.');
        }

        return $amount * ($toRate / $fromRate);
    }
}

Implementation Patterns

Wrap the vendor client in an application service. This is the most important pattern. Do not scatter getLatest()/convert() calls across controllers, templates, and commands. A single CurrencyConverter or ExchangeRateRepository service gives you one place to add caching, error handling, logging, and retries.

Inject, don't container-pull. In Symfony2, define your wrapper as a service and inject the bundle client by its confirmed service ID. In Laravel, bind the underlying client as a singleton in a service provider and inject your wrapper into controllers/jobs.

Cache aggressively. OpenExchangeRates free-tier quotas are low and the API is a network dependency:

  • Latest rates: cache for 1 hour or longer depending on business needs.
  • Historical rates: cache indefinitely; they do not change.
  • Currencies list: cache for days/weeks.
  • Store rates with the fetch timestamp so you can reason about staleness.

A common pattern is a scheduled console command or Laravel queued job that refreshes rates into Redis/database, with the request path reading only from cache.

Use cross-rates correctly. The free OpenExchangeRates plan is typically USD-base only. To convert EUR → GBP, fetch USD-based rates and compute amount * (rate_GBP / rate_EUR). Do not assume the API accepts arbitrary base currencies unless your plan supports it.

Capture historical rates at transaction time. For invoices, orders, refunds, or accounting entries, persist the rate/date used for the conversion. Do not recompute historical conversions later from “latest” rates.

Use historical endpoints for backfills and reporting. For month-end reporting, fetch historical/YYYY-MM-DD once per required date and store it. Avoid requesting the same historical date repeatedly.

Test against a fake client. Never call the live API in unit tests. Type-hint your wrapper service, mock it in tests, and assert conversion math and error handling. Keep a small fixture of representative API responses.

Prefer integer minor units or BCMath for money. The API returns floats; convert to cents or use arbitrary-precision math at the boundaries of your domain. Round only at presentation/persistence boundaries, not midway through calculations.

Laravel integration sketch. Since the bundle itself does not fit Laravel:

// config/services.php
'open_exchange_rates' => [
    'app_id' => env('OPEN_EXCHANGE_RATES_APP_ID'),
],

// AppServiceProvider::register()
$this->app->singleton(ExchangeRateClient::class, function ($app) {
    return new ExchangeRateClient(config('services.open_exchange_rates.app_id'));
});

Then inject your own CurrencyConverter wrapper into controllers, jobs, and commands.

Gotchas and Tips

Framework mismatch is the biggest gotcha. This bundle is Symfony2-era. It will not plug into Laravel, and modern Symfony versions may reject it due to outdated bundle conventions and dependency constraints. Treat it as a reference implementation for wiring the underlying client, not as a reusable cross-framework package.

It is effectively abandoned. Last release was 2017; Symfony2 is long EOL. Expect no fixes for PHP 8, modern Symfony, or API changes. Audit the source before relying on it in production.

The OpenExchangeRates API itself has changed over time. Confirm the current authentication parameter (app_id), plan limits, base-currency restrictions, and endpoint behavior directly against the provider's docs. A 2017 wrapper may not surface rate-limit or plan-error responses cleanly.

Configuration quirks. If the app_id is supplied via an environment variable, clear the Symfony cache after changing it. Double-check whether the bundle expects app_id, app_key, or another key by reading Configuration.php; do not trust examples from old blog posts.

Service ID uncertainty. Bundle service IDs are easy to misremember. Use debug:container in Symfony2 or inspect services.xml. If the bundle exposes an alias, prefer the alias in your code and decorate/wrap it so you can swap implementations later.

Caching is your responsibility. Do not assume the bundle caches API responses. Without your own cache layer, every page view or conversion can burn quota and add latency. Add a cache decorator around the client rather than modifying vendor code.

Error handling is thin. Network failures, invalid app IDs, quota exhaustion, and malformed currency codes may surface as generic exceptions or null values. Normalize these into domain exceptions in your wrapper so controllers and jobs can handle them predictably.

Historical date formatting. Use the API's expected YYYY-MM-DD format and be explicit about UTC. Off-by-one date bugs around time zones are common when generating historical requests from user-local dates.

Monetary precision. Floats plus repeated conversions produce drift. Store original amount, source currency, target currency, rate, and rate date. Reconcile using stored values, not recomputed ones.

Security. Never expose the app_id in frontend JavaScript or public API responses. Keep all OpenExchangeRates calls server-side.

Extension points are limited. The cleanest extension approach is to decorate or wrap the bundle's client service in your own application service. Avoid forking the bundle unless you are prepared to maintain it; for Laravel, skip the bundle entirely and integrate the underlying client directly.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin