brokeyourbike/money-casts-laravel
Laravel Eloquent casts for monetary values that convert database amounts into Money objects and back, keeping currency handling clean and consistent across your models.
composer require brokeyourbike/money-casts-laravel. The package is a thin Laravel integration around moneyphp/money, so expect that dependency to come along with it.moneyphp/money constraint compatible with your app.src/ cast classes — typically MoneyCast and CurrencyCast. Those are the only public surface you interact with day to day.Money object on an Eloquent model, sourcing the currency from either a fixed code or another column.use BrokeYourBike\MoneyCasts\MoneyCast;
class Order extends Model
{
protected $casts = [
'total' => MoneyCast::class.':currency', // currency column
// or: MoneyCast::class.':USD' // fixed currency
];
}
After that, $order->total is a Money\Money instance; $order->total->getAmount() returns the minor-unit string and $order->total->getCurrency()->getCode() returns the ISO code.
MoneyCast::class.':USD'). Good for domestic-only tables where a currency column would be redundant.MoneyCast::class.':currency'). Keep that column as char(3) with an ISO 4217 code and make it non-nullable.CurrencyCast where you store just a currency code and want a Money\Currency object instead of a string.bigInteger minor units (cents) and currency as char(3). This is the least surprising layout and matches how moneyphp/money represents amounts.Money instance to the attribute where possible. If you accept scalars in forms, convert to Money in a form request or model mutator before assignment, and verify the cast’s set behavior with a test.where('total', ...) still compares against the raw column, so query in minor units, not in formatted decimals.getAmount() and the currency code explicitly, or format with moneyphp/money formatters (DecimalMoneyFormatter, IntlMoneyFormatter) in a resource class rather than relying on default model serialization.string|size:3 (optionally in: a supported list) and amounts as integers in minor units. Reject floats at the boundary.assertInstanceOf(Money::class, $model->total) and compare with $money->equals($other). Factories should create integer amounts.$table->bigInteger('total'); $table->char('currency', 3); keeps the cast’s assumptions explicit.Money is immutable. $model->total->add($x) returns a new instance and does nothing to the model; reassign it explicitly.(float) $money->getAmount() or storing decimals loses precision and introduces off-by-100 errors. Work in minor units and format only at the edges.equals() — == on Money objects can mislead; use $a->equals($b).select('total') without currency).set implementation. Cover create/update paths with tests before relying on scalar assignment.toArray()/toJson() will include the Money object unless you customize it. Use API resources or accessors so responses stay predictable.DB::select hydration paths.moneyphp/money constraint at the same time.CastsAttributes using moneyphp/money rather than fighting the provided cast.composer update brokeyourbike/money-casts-laravel; pin to ^1.0.How can I help you explore Laravel packages today?