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

Laravel Revaluation Laravel Package

overtrue/laravel-revaluation

A Laravel package for currency revaluation, offering configurable exchange rates and simple helpers to convert and update monetary values, helping keep prices, invoices, and other currency-based data consistent across your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire it up

composer require overtrue/laravel-revaluation

On Laravel 5.5+ package discovery registers the service provider automatically. On older apps add it manually to config/app.php:

'providers' => [
    Overtrue\LaravelRevaluation\RevaluationServiceProvider::class,
],
'aliases' => [
    'Revaluation' => Overtrue\LaravelRevaluation\Revaluation::class,
],

Publish the config and put every credential in .env:

php artisan vendor:publish --provider="Overtrue\LaravelRevaluation\RevaluationServiceProvider"

Where to look first (in this order)

  1. config/revaluation.php — this is the documentation. It tells you the shape of currencies, the default/base currency, the selected rate driver, cache TTL, and the provider credentials key.
  2. RevaluationServiceProvider — shows what is bound as a singleton, whether the manager is a driver manager (extendable) or a single class, and which config keys it reads.
  3. The facade/manager class — the whole public API is usually a handful of methods (convert, rate, revalue, refresh), so read the file end to end rather than guessing.
  4. The rate-provider/driver directory — one small class per exchange-rate source; copy the simplest one when you need your own.

Naming has drifted between releases and the package has no real docs, so treat the class names above as a map, not gospel — a five-minute grep -r "public function" will pin down the exact signatures.

First use case: convert an invoice line

$total = Revaluation::convert(12500, 'USD', 'EUR'); // minor units in, minor units out

Confirm the return type (float vs. int vs. a value object) before writing anything else — the rest of your codebase will be built on that assumption.

Implementation Patterns

Convert at the edges, store one canonical currency

Keep your database in a single base currency (integer minor units) and convert only when rendering or when a foreign-currency document must be issued. Storing converted values permanently creates a second source of truth that silently rots as rates move.

class PricePresenter
{
    public function __construct(private Revaluation $revaluation) {}

    public function forCurrency(int $amountMinor, string $currency): int
    {
        return $this->revaluation->convert($amountMinor, config('app.currency'), $currency);
    }
}

Prefer constructor injection over the facade in services — the facade is convenient in controllers and Tinker, but it makes the rate source untestable.

Snapshot the rate, not just the result

For invoices, orders, and refunds, persist the rate and its timestamp alongside the amount. Revaluation is not idempotent: re-running a conversion a week later produces a different number, and auditors will ask which rate was applied.

$rate = Revaluation::rate('USD', 'EUR');

Invoice::create([
    'amount'            => $amountMinor,
    'currency'          => 'EUR',
    'fx_rate'           => $rate,
    'fx_rate_fetched_at'=> now(),
    'fx_source'         => config('revaluation.driver'),
]);

Cache deliberately and warm it on a schedule

The package-level cache exists to stop you hammering a third-party API. Two habits make it reliable:

  • Set a TTL matched to the provider's update cadence (daily feeds do not need a 60-second TTL).
  • Warm the cache in a scheduled job so the first customer of the day isn't the one paying the latency cost.
// app/Console/Kernel.php
$schedule->call(fn () => Revaluation::refresh())->hourly()->withoutOverlapping();

For batch jobs (monthly reporting over 50k rows), fetch the rate table once into an array and do arithmetic in PHP — calling convert() per row turns a local loop into thousands of cache reads.

Write your own rate provider

This is the package's main extension point and the reason to tolerate its age. Implement the provider contract against your source (ECB XML, an internal treasury service, a rate table in your own DB) and register it in config. For anything but a toy, an internal provider backed by a table you control is the right choice — it removes the external dependency from your request path entirely.

class TreasuryRateProvider implements RateProviderInterface
{
    public function rate(string $from, string $to): float
    {
        return TreasuryRate::query()
            ->where('base', $from)->where('quote', $to)
            ->latest('effective_at')->value('rate')
            ?? throw new RateUnavailableException("$from/$to");
    }
}

Test with a fixed-rate fake

Bind a deterministic provider in the test container so no test touches the network and every assertion has an exact expected value.

$this->app->instance(RateProviderInterface::class, new FixedRateProvider(['USD/EUR' => 0.92]));

$this->assertSame(9200, Revaluation::convert(10000, 'USD', 'EUR'));

Gotchas and Tips

It is archived (last release March 2018). Treat it as vendored code you own. It targets the Laravel 5.x era; expect friction on Laravel 9+/PHP 8 (return types, Str/Arr helpers, container signatures). If you only need conversion arithmetic, a 40-line service class plus your own rate table is often the better trade — the package's value is the provider abstraction and caching, not the maths.

Never do money maths in floats. The underlying conversion almost certainly multiplies floats. Round only at the display boundary and use bcmath/integer minor units for anything that is summed, refunded, or reconciled.

Mind the direction of the rate. "Rate for USD→EUR" can mean 1 USD = 0.92 EUR or 1 EUR = 1.087 USD depending on the provider. One wrong assumption here is a 100× error that only shows up in production. Assert against a known pair in a test.

Missing pairs may return 0 rather than throwing. Check the failure behaviour explicitly — a silent zero becomes a free product. Wrap conversions in a guard that rejects non-positive rates.

Handle provider outages. Add a try/catch that falls back to the last known rate (with its age recorded) or fails the transaction loudly. A checkout that 500s because an exchange API is down is worse than a slightly stale rate.

php artisan config:cache will bite you. Anything read via env() inside a package config file returns null once config is cached. Always reference credentials through config('revaluation.api_key') and ensure the env var is set at deploy time.

Cache keys must include the pair (and possibly the driver). If you switch drivers or add a currency, stale entries can serve rates from the wrong source. Flush the relevant keys in your provider's deploy/refresh routine.

Zero-decimal currencies are a real trap (JPY, KRW). If the config's currency definitions carry a precision/decimals field, use it for formatting; if not, keep your own map — otherwise you will render ¥1000.00.

Debugging: php artisan tinker then dump the manager instance and the resolved config to see which driver is actually active; log the provider HTTP calls at debug level; and check storage/logs for swallowed exceptions in the cache layer. If a conversion looks wrong, log the raw rate before any rounding.

Extend, don't fork. Use the driver manager's extend() (or a container binding for the provider interface) to register custom behaviour. A small wrapper service in your own app/ namespace that owns the package behind an interface means you can swap it out in a day if it finally breaks — which, given the archive date, it eventually will.

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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast