The AsDecimalMoney cast stores monetary values in their major units as decimal numbers (e.g., 10.00 for ten dollars). This approach provides human-readable values in the database but requires careful handling of decimal precision.
AsIntegerMoney is recommended for most use cases. Use AsDecimalMoney only when you specifically need decimal storage for legacy systems or human-readable database values.
How It Works
The cast converts between Money objects in your PHP code and decimal values in your database:
Storage : Money::of(10.00, 'USD') → 10.00 (stored as decimal)
Retrieval : 10.00 → Money::of(10.00, 'USD') (Money object)
Implementation
The AsDecimalMoney class uses the AsMoneyCast trait and implements two key methods:
protected function serializeMoney ( Money $value ) : string
{
return ( string ) $value -> getAmount ();
}
protected function deserializeMoney ( float | int | string $amount , string $currency ) : Money
{
return Money :: of ( $amount , $currency );
}
Usage Patterns
Separate Columns
JSON Column
Custom Column Names
Store amount and currency in separate columns. Model Definition use Devhammed\LaravelBrickMoney\ Money ;
use Devhammed\LaravelBrickMoney\Casts\ AsDecimalMoney ;
use Illuminate\Database\Eloquent\ Model ;
/**
* @property Money $amount
* @property string $currency
*/
class Transaction extends Model
{
protected function casts () : array
{
return [
'amount' => AsDecimalMoney :: of ( 'currency' ),
];
}
}
Migration use Illuminate\Database\Schema\ Blueprint ;
use Illuminate\Support\Facades\ Schema ;
Schema :: create ( 'transactions' , function ( Blueprint $table ) {
$table -> id ();
$table -> decimal ( 'amount' , 36 , 18 ); // e.g., 10.00 = $10.00
$table -> string ( 'currency' , 3 ); // e.g., 'USD'
$table -> timestamps ();
});
Decimal Precision : DECIMAL(36, 18) provides enough precision for cryptocurrencies like Ethereum (18 decimal places). Adjust based on your needs:
Standard currencies: DECIMAL(19, 4) or DECIMAL(13, 2)
High precision: DECIMAL(36, 18)
Usage Example // Create
$transaction = Transaction :: create ([
'amount' => Money :: of ( 10.00 , 'USD' ),
]);
// The database stores:
// amount: 10.00
// currency: "USD"
// Retrieve
$transaction = Transaction :: find ( 1 );
echo $transaction -> amount -> format (); // "$10.00"
echo $transaction -> currency ; // "USD"
Store both amount and currency in a single JSON column. Model Definition use Devhammed\LaravelBrickMoney\ Money ;
use Devhammed\LaravelBrickMoney\Casts\ AsDecimalMoney ;
use Illuminate\Database\Eloquent\ Model ;
/**
* @property Money $price
*/
class Product extends Model
{
protected function casts () : array
{
return [
'price' => AsDecimalMoney :: class ,
];
}
}
Migration use Illuminate\Database\Schema\ Blueprint ;
use Illuminate\Support\Facades\ Schema ;
Schema :: create ( 'products' , function ( Blueprint $table ) {
$table -> id ();
$table -> json ( 'price' ); // {"amount": "10.00", "currency": "USD"}
$table -> timestamps ();
});
Usage Example // Create
$product = Product :: create ([
'price' => Money :: of ( 10.00 , 'USD' ),
]);
// The database stores:
// price: {"amount": "10.00", "currency": "USD"}
// Retrieve
$product = Product :: find ( 1 );
echo $product -> price -> format (); // "$10.00"
Specify custom column names for amount and currency. Model Definition use Devhammed\LaravelBrickMoney\ Money ;
use Devhammed\LaravelBrickMoney\Casts\ AsDecimalMoney ;
use Illuminate\Database\Eloquent\ Model ;
/**
* @property Money $total
*/
class Invoice extends Model
{
protected function casts () : array
{
return [
'total' => AsDecimalMoney :: of ( 'total_currency' , 'total_amount' ),
];
}
}
Migration Schema :: create ( 'invoices' , function ( Blueprint $table ) {
$table -> id ();
$table -> decimal ( 'total_amount' , 19 , 4 );
$table -> string ( 'total_currency' , 3 );
$table -> timestamps ();
});
Decimal Precision Guide
Choosing the right decimal precision is critical:
Use Case Precision Explanation Standard currencies (USD, EUR) DECIMAL(13, 2)2 decimal places, handles up to $99 billion High-value transactions DECIMAL(19, 4)4 decimal places, handles larger amounts Cryptocurrencies DECIMAL(36, 18)18 decimal places for ETH and similar Scientific/custom DECIMAL(65, 30)Maximum MySQL precision
Examples
// Standard currency - 2 decimal places
$table -> decimal ( 'price' , 13 , 2 ); // Max: 99,999,999,999.99
// High precision - 4 decimal places
$table -> decimal ( 'price' , 19 , 4 ); // Max: 999,999,999,999,999.9999
// Cryptocurrency - 18 decimal places
$table -> decimal ( 'amount' , 36 , 18 ); // Handles Ethereum precision
Complete Example
use Devhammed\LaravelBrickMoney\ Money ;
use Devhammed\LaravelBrickMoney\Casts\ AsDecimalMoney ;
use Illuminate\Database\Eloquent\ Model ;
class Order extends Model
{
protected function casts () : array
{
return [
'subtotal' => AsDecimalMoney :: of ( 'currency' ),
'tax' => AsDecimalMoney :: of ( 'currency' ),
'total' => AsDecimalMoney :: of ( 'currency' ),
];
}
public function calculateTotal () : void
{
$this -> total = $this -> subtotal -> plus ( $this -> tax );
}
}
Querying
Querying decimal amounts is straightforward since values are stored in major units:
// Find orders over $100
$expensiveOrders = Order :: where ( 'total' , '>' , 100 ) -> get ();
// Find orders between $50 and $200
$midRangeOrders = Order :: whereBetween ( 'total' , [ 50 , 200 ]) -> get ();
// Sum all orders in USD
$totalRevenue = Order :: where ( 'currency' , 'USD' ) -> sum ( 'total' );
echo Money :: of ( $totalRevenue , 'USD' ) -> format ();
// Average order value
$avgOrder = Order :: where ( 'currency' , 'USD' ) -> avg ( 'total' );
echo Money :: of ( $avgOrder , 'USD' ) -> format ();
Use Cases
Legacy Database Integration
When working with existing databases that store amounts as decimals: // Existing database has decimal columns
class LegacyOrder extends Model
{
protected function casts () : array
{
return [
'price' => AsDecimalMoney :: of ( 'currency_code' ),
];
}
}
When business intelligence tools expect decimal values: // BI tools can read decimal values directly
SELECT AVG ( amount ) as avg_transaction
FROM transactions
WHERE currency = 'USD' ;
When exporting data for non-technical users: // CSV export shows: 10.00 instead of 1000
$transactions = Transaction :: all ();
// Export to CSV with readable amounts
When external APIs send/expect decimal amounts: // External API sends: {"amount": 10.50, "currency": "USD"}
$transaction = Transaction :: create ([
'amount' => Money :: of ( $apiData [ 'amount' ], $apiData [ 'currency' ]),
]);
Important Considerations
Floating-Point Precision : Be aware that decimal arithmetic can introduce precision errors. The Brick\Money library handles this internally, but database aggregations may not.// This could have precision issues in pure SQL:
DB :: table ( 'orders' ) -> sum ( 'total' ); // Use with caution
// Better approach:
$orders = Order :: all ();
$total = $orders -> reduce (
fn ( $carry , $order ) => $carry ?-> plus ( $order -> total ) ?? $order -> total
);
Best Practices
Choose appropriate decimal precision
Match your decimal precision to your use case: // Too little precision
$table -> decimal ( 'amount' , 10 , 2 ); // ⚠️ Only $99,999,999.99 max
// Good for standard currencies
$table -> decimal ( 'amount' , 19 , 4 ); // ✅ Handles most cases
// Required for crypto
$table -> decimal ( 'amount' , 36 , 18 ); // ✅ Handles high precision
Use separate columns for flexibility
'amount' => AsDecimalMoney :: of ( 'currency' ) // ✅ Recommended
Add indexes for performance
$table -> decimal ( 'amount' , 19 , 4 ) -> index ();
$table -> string ( 'currency' , 3 ) -> index ();
Document precision requirements
/**
* @property Money $amount Stored with 4 decimal places
* @property string $currency ISO 4217 currency code
*/
class Transaction extends Model { }
Comparison: Decimal vs Integer Storage
Aspect AsDecimalMoney AsIntegerMoney Readability High - human-readable Low - requires conversion Precision Depends on DECIMAL size Exact for supported range Performance Slower decimal arithmetic Faster integer arithmetic Storage More space (decimal) Less space (integer) Compatibility Better with BI tools Industry standard Recommendation Legacy/reporting only ✅ Preferred
Migration from Integer Storage
If you’re migrating from AsIntegerMoney to AsDecimalMoney:
use Illuminate\Database\Migrations\ Migration ;
use Illuminate\Database\Schema\ Blueprint ;
use Illuminate\Support\Facades\ Schema ;
use Illuminate\Support\Facades\ DB ;
class ConvertAmountToDecimal extends Migration
{
public function up ()
{
// Add temporary decimal column
Schema :: table ( 'orders' , function ( Blueprint $table ) {
$table -> decimal ( 'amount_decimal' , 19 , 4 ) -> nullable ();
});
// Convert: divide by 100 for 2-decimal currencies
DB :: statement ( ' UPDATE orders SET amount_decimal = amount / 100 ' );
// Drop old column and rename
Schema :: table ( 'orders' , function ( Blueprint $table ) {
$table -> dropColumn ( 'amount' );
$table -> renameColumn ( 'amount_decimal' , 'amount' );
});
}
public function down ()
{
// Reverse the migration
Schema :: table ( 'orders' , function ( Blueprint $table ) {
$table -> bigInteger ( 'amount_integer' ) -> nullable ();
});
DB :: statement ( ' UPDATE orders SET amount_integer = amount * 100 ' );
Schema :: table ( 'orders' , function ( Blueprint $table ) {
$table -> dropColumn ( 'amount' );
$table -> renameColumn ( 'amount_integer' , 'amount' );
});
}
}
Next Steps
AsIntegerMoney Cast Learn about the recommended integer storage
AsCurrency Cast Cast currency codes to Currency objects