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

Money Laravel Package

archtechx/money

A Laravel package for safe money handling. Its Eloquent cast, backed by brick/money, stores amounts as integers to avoid floating-point errors, with currency support, formatting helpers, and Blade components for displaying prices cleanly.

View on GitHub
Deep Wiki
Context7

Getting Started

archtechx/money is a thin, Laravel-friendly wrapper around brick/money that gives you a Money value object, an Eloquent cast, and locale-aware formatting — without you hand-rolling integer-minor-unit math.

composer require archtechx/money
php artisan vendor:publish --tag=money   # config/money.php

Set your app-wide defaults in config/money.php (default_currency, locale/format defaults) and put the currency in .env so staging/prod don't drift:

// config/money.php
'default_currency' => env('MONEY_CURRENCY', 'USD'),

The first use case is almost always a price column. Store money as an integer minor amount (cents) in the database and cast it on the model:

use Archtechx\Money\Casts\AsMoney;

class Product extends Model
{
    protected $casts = [
        'price' => AsMoney::class.':USD',   // column stores 1999, you get $19.99
    ];
}
$product->price->format();      // "$19.99"
$product->price->getMinorAmount(); // 1999

Release note (v0.5.4): this release only adds Laravel 13 support (PR #30). There are no API changes, deprecations, or new features — it's a composer.json constraint bump. If you're on ^0.5, composer update picks it up; if you're pinned to 0.5.3 exactly, bump the pin. Nothing in your application code needs to change. On Laravel 13, confirm your PHP version matches what the framework requires before upgrading, and re-run your suite once after the jump.

Implementation Patterns

Two ways in, one way out. Use Money::fromMinor() when reading from the database or an API that already speaks cents, and Money::fromDecimal() at the boundary where a human typed 19.99. Never mix the two in the same layer.

use Archtechx\Money\Money;

$price = Money::fromDecimal($request->input('price'), 'USD');
$product->price = $price;      // cast writes 1999 to the column

Multi-currency rows. When currency varies per record, keep a currency column next to the amount and pass the column name to the cast so each row resolves its own currency, rather than baking a single currency into the cast string.

Arithmetic belongs in the value object. Don't reach for + on floats. Use the Money API and let brick/money handle rounding, and use allocation/splitting when dividing an amount across line items — this is where naive division produces off-by-one-cent totals.

$total = $lineA->price->plus($lineB->price);
$shares = $total->allocate([1, 1, 1]); // splits without losing cents

API output is a decision, not a default. Pick one and be consistent:

  • ->getMinorAmount() for machine consumers (integers survive JSON and JS safely),
  • ->format() for display surfaces only.

Don't let a raw Money object reach toArray()/json() and surprise you — wrap it in your API Resource and choose explicitly.

Blade. The package ships a directive, so views stay clean:

@money($product->price)

Testing. Build fixtures with Money::fromMinor() so expectations are exact, and assert on getMinorAmount() rather than formatted strings — formatting is locale-dependent and will make tests flaky across environments.

Gotchas and Tips

  • Don't store decimals in the DB. decimal(8,2) plus a cast invites double-rounding. Integer minor units in a bigInteger column is the whole point of the cast.
  • Never convert floats by hand. (int) ($amount * 100) fails on values like 19.99. Always go through fromDecimal().
  • Null casts. A nullable price column will hand back null, not Money — guard before calling ->format() in Blade, or use ?->.
  • Currency mismatches throw. Adding USD to EUR raises an exception in brick/money. If you support multiple currencies, validate compatibility before arithmetic rather than around it.
  • Config caching. After changing default_currency or format settings, run php artisan config:cache (and clear it) — a stale cached config is the usual cause of "it still shows the old symbol."
  • Locale is environmental. Formatted output depends on the locale in play; if you show per-user locales, set it per request and don't cache rendered strings across users.
  • Upgrading from 0.5.3. v0.5.4 changes only framework constraints. If your app is on Laravel 10–12 and you're not ready to move, no action needed. If you're moving to Laravel 13, do the framework upgrade and this package bump together, then run your money-related tests — the risk sits in the framework jump, not this release.
  • Extension points. Custom formatting behaviour goes in config/money.php and in your own accessors/API resources rather than by subclassing the cast. Keep presentation logic in resources and view components; keep storage as integers.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource