elegantly/laravel-money
Seamlessly integrate Brick/Money with Laravel using expressive value objects. MoneyCast automatically casts Eloquent attributes to Money, MoneyParser safely converts strings, integers, and floats, and the ValidMoney rule validates input with min/max boundaries and nullable support.
brick/money, a mature, widely used library. This package is a thin Laravel adapter (cast + parser + validation rule). That makes the real decision "do we adopt brick/money and write ~200 lines of glue, or take the glue off the shelf?" Frame it as: adopting brick/money is the architectural decision; this package is a convenience layer on top.bigInteger amount in minor units + string(3) ISO currency) is a durable, precision-safe schema. Adopting this package effectively locks in that decision early, which is exactly the kind of cheap-to-decide-now, expensive-to-change-later call a PM should force during greenfield design.MoneyCast::of('currency') (currency per row) vs. MoneyCast::of('USD') (fixed currency) is a concrete fork in the roadmap. Choosing the column-based cast costs almost nothing today and preserves the option to sell into EU/UK/JPY markets later without a migration. If multi-currency is on the 12-month roadmap, this is the cheap option-preserving move.MoneyParser and ValidMoney rule let you decide, per surface, whether float input is tolerated at the edge (forms, CSV imports, third-party APIs) and normalized to exact values at the boundary—rather than scattering round() calls through checkout, invoicing, refunds, and payouts.ValidMoney(nullable, min, max) turns business rules (no negative refunds, max order value for fraud review, optional price fields) into declarative constraints in Form Requests and Livewire components—cheaper to audit than scattered controller conditionals.Adopt when most of these hold:
bigInteger + currency from day one.Money objects) without a broader DDD refactor.Look elsewhere or build it yourself when:
decimal/float. Migration to minor-unit integers is a data-migration project with rounding-policy and reconciliation work—not a package-adoption task. The package will work, but the cost is in the migration, not the dependency."USD 100.00"). Note the v2.0.0 breaking change: serialization now returns a float (100.00) instead of a string. Floats at a JSON boundary are a precision and contract hazard; if your clients consume money as strings, you must override serialization deliberately.Finller\Money → Elegantly\Money at v2.0.0) that already forced a search-and-replace migration. Treat this as a thin, replaceable utility, not infrastructure. If procurement requires a supported vendor or SLAs, this fails that bar.brick/money covers a lot, but display formatting is usually a presentation-layer concern you'll own anyway.To executives (one paragraph): Money bugs are expensive and visible—wrong totals, mismatched invoices, refund discrepancies, and failed audits. This package is a small, MIT-licensed adapter that makes Laravel store and handle money exactly (integers in minor units, explicit currency codes) instead of approximately (floats). The underlying math library is mature and widely used; what we're adopting is the Laravel glue, roughly a day of work we don't have to write or maintain. It costs nothing, it's removable, and it preserves our option to sell in multiple currencies later. The risk is that it's a small open-source project with a single maintainer, so we'll isolate it behind our own internal type and pin the version—meaning if it's ever abandoned, we replace one file rather than refactor the product.
To engineering (the ask):
elegantly/laravel-money as a pinned dependency; standardize money columns as bigInteger (minor units) + string(3) ISO currency.MoneyCast::of('currency') by default—even for single-currency tables—so multi-currency is a data change, not a schema migration.Money objects reach JSON directly. The default cast serializes to float; define an explicit API representation (string amount + currency code, or integer minor units + currency) in a Resource/DTO layer and test it.MoneyParser; apply ValidMoney with explicit min/max/nullable in Form Requests and Livewire.App\Support\Money) around the cast and parser so the package is swappable if the project stalls.MoneyParser since v2.3.2), and legacy rows with missing or invalid currency codes.Scope boundary to state explicitly: this package handles storage, casting, parsing, and validation. It does not handle FX conversion, rate history, ledgers, or financial reporting. If those appear in the roadmap, they are separate decisions with separate budgets—don't let this adoption imply they're solved.
How can I help you explore Laravel packages today?