mibo/currency-rates
mibo/currency-rates is a Laravel/PHP package for working with currency exchange rates, offering a simple API to fetch rates and convert amounts between currencies. Lightweight and easy to configure within your existing Laravel application.
mibo/currency-rates is a small, single-maintainer Laravel package (MIT, last tagged 2024-08-03). It is not widely adopted — zero stars and zero dependents at time of review — so treat it as a utility you evaluate before committing, not a drop-in dependency you assume is battle-tested.
Install and inspect before wiring it into anything real:
composer require mibo/currency-rates
composer show mibo/currency-rates # check Laravel/PHP constraints, autoload, files
Then read the package source in vendor/mibo/currency-rates/ in this order:
composer.json — Laravel version range and whether it depends on Guzzle, illuminate/support, etc.config/*.php — the base currency, default provider, API credentials, and cache TTL are almost certainly here. Publish it if a service provider registers it:
php artisan vendor:publish --provider="Mibo\CurrencyRates\CurrencyRatesServiceProvider"
(Confirm the exact provider/tag from the repo — small packages often publish under a short tag like currency-rates.)src/ — look for the service class, facade, and any contract/interface. The interface is the seam you will code against.README.md — the only authoritative usage example; assume it is the source of truth over any guess here.First use case: converting a single amount for display. Something along the lines of resolving the rate service from the container and calling a convert/latest method, then formatting the result. Prove that path end-to-end against one provider before you design around it.
Wrap it, don't sprinkle it. Because the package is unmaintained-risk, put your own ExchangeRateService interface in front of it and bind the package behind that. If the package dies or the provider changes, you swap one adapter rather than grepping the codebase.
interface ExchangeRateService {
public function rate(string $from, string $to, ?Carbon $date = null): string;
}
Return rates as strings or integer minor units — not floats — and do rounding at the presentation edge only.
Cache aggressively, refresh on a schedule. Rates move on the order of minutes to hours, not per-request. Cache per (base, quote, date) with a TTL matched to the provider's update cadence, and refresh out-of-band:
// app/Console/Kernel.php
$schedule->call(fn () => app(ExchangeRateService::class)->refresh())->hourly();
Prefer a scheduled warm-up plus a cache read on the request path over a live API call during checkout or page render.
Persist a snapshot for anything financial. If rates affect invoices, orders, or payouts, store the exact rate and timestamp used on the row (rate, rate_at, rate_source). Never recompute historical totals from "current" rates.
Test with a fake. Bind a deterministic stub in your test suite rather than hitting the provider:
$this->app->instance(ExchangeRateService::class, new FakeRates(['USD' => '1', 'EUR' => '0.92']));
Use it for display, not accounting. Round-tripping through a third-party rate is fine for a price hint; it is not a settlement rate. Keep the two code paths separate.
composer.json, vendor the lockfile, and keep the adapter boundary described above. Have a fallback provider in mind before you ship.rates key will leak one tenant's base currency into another's response. If you support per-user base currencies, namespace the key.1.0 is the classic bug — never do it.config(), which breaks under config:cache. Grep the source for env( and, if found, mirror the values into a published config file.driver-style config — that is your hook for swapping providers without forking. If there isn't one, your own adapter is the extension point.How can I help you explore Laravel packages today?