Laravel cast for handling decimal values as base-100 integers (cents/centesimals)
aichadigital/lara100 is a Laravel package for laravel cast for handling decimal values as base-100 integers (cents/centesimals).
It currently has 0 GitHub stars and 349 downloads on Packagist (latest version v1.2.1).
Install it with composer require aichadigital/lara100.
Discover more Laravel packages by aichadigital
or browse all Laravel packages to compare alternatives.
Last updated
A Laravel package that provides a custom Eloquent cast for handling monetary/decimal values by storing them as integers (cents) in the database while working with decimals in your PHP code, eliminating floating-point precision errors.
Floating-point arithmetic in PHP (and most programming languages) can lead to precision errors:
0.1 + 0.2 === 0.3 // false! 😱
// Result: 0.30000000000000004
This is particularly problematic when dealing with:
Lara100 solves this by storing values as integers (cents) in the database, while letting you work with familiar decimal values in your code.
// In your database: 1999 (integer - cents)
// In your application: 19.99 (decimal - dollars/euros)
You can install the package via Composer:
composer require aichadigital/lara100
You can optionally publish the configuration file:
php artisan vendor:publish --tag="lara100-config"
This will create a config/lara100.php file where you can configure:
PHP_ROUND_HALF_UP)false)Alternatively, you can set these via environment variables in your .env:
# Rounding mode (default: 2 = PHP_ROUND_HALF_UP)
# 1 = PHP_ROUND_HALF_UP (standard for Spain/EU)
# 2 = PHP_ROUND_HALF_DOWN
# 3 = PHP_ROUND_HALF_EVEN (Banker's rounding for accounting)
# 4 = PHP_ROUND_HALF_ODD
LARA100_ROUNDING_MODE=1
# Enable BCMath for arbitrary precision (requires bcmath extension)
LARA100_USE_BCMATH=false
Apply the Base100 cast to your model attributes:
use AichaDigital\Lara100\Casts\Base100;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected function casts(): array
{
return [
'price' => Base100::class,
'cost' => Base100::class,
'tax' => Base100::class,
];
}
}
Now you can work with decimals in your application while storing integers in the database:
$product = new Product;
$product->price = 19.99; // You set: 19.99 (decimal)
$product->save(); // DB stores: 1999 (integer cents)
echo $product->price; // You get: 19.99 (decimal)
// Arithmetic operations work perfectly with decimals
$total = $product->price + $product->tax; // 19.99 + 2.50 = 22.49 ✅
For convenience, you can use the HasBase100 trait to apply the cast to multiple attributes at once:
use AichaDigital\Lara100\Concerns\HasBase100;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasBase100;
protected function base100Attributes(): array
{
return ['price', 'cost', 'tax', 'discount'];
}
}
The trait automatically applies the Base100 cast to all specified attributes.
// Database stores: 1999 (INTEGER cents)
// Cast converts to: 19.99 (DECIMAL)
$product->price; // 19.99
// Application receives: 19.99 (DECIMAL)
// Cast converts to: 1999 (INTEGER cents)
$product->price = 19.99;
$product->save(); // Stores 1999 in DB
By default, the cast uses Round Half Up (PHP_ROUND_HALF_UP):
0.555 → 0.56 (rounds up when exactly halfway)0.554 → 0.55This is the standard rounding mode used in Spain, the EU, and most countries.
You can configure the rounding mode globally via config or per-attribute:
Global configuration (affects all casts):
# In .env
LARA100_ROUNDING_MODE=1 # PHP_ROUND_HALF_UP (default)
Per-attribute override (in your model):
use AichaDigital\Lara100\Casts\Base100;
protected function casts(): array
{
return [
'price' => Base100::class, // Uses config default
'tax' => new Base100(PHP_ROUND_HALF_EVEN), // Banker's rounding
'discount' => new Base100(PHP_ROUND_HALF_DOWN), // Always round down
];
}
| Mode | Constant | Behavior | Use Case |
|------|----------|----------|----------|
| Half Up | PHP_ROUND_HALF_UP (1) | 0.555→0.56, 0.545→0.55 | Spain/EU standard |
| Half Even | PHP_ROUND_HALF_EVEN (3) | 0.555→0.56, 0.545→0.54 | Accounting (Banker's) |
| Half Down | PHP_ROUND_HALF_DOWN (2) | 0.555→0.55, 0.545→0.54 | Conservative rounding |
| Half Odd | PHP_ROUND_HALF_ODD (4) | 0.555→0.55, 0.545→0.55 | Specialized cases |
For maximum precision with very large amounts, enable BCMath:
LARA100_USE_BCMATH=true
Or per-attribute:
'balance' => new Base100(useBcmath: true),
Note: Requires the bcmath PHP extension to be installed.
$invoice = new Invoice;
$invoice->subtotal = 100.00; // You set: $100.00 (decimal)
$invoice->tax = 13.00; // You set: $13.00 (decimal)
$invoice->total = 113.00; // You set: $113.00 (decimal)
$invoice->save(); // DB stores: 10000, 1300, 11300 (integers)
// Calculate percentage (works naturally with decimals)
$taxRate = ($invoice->tax / $invoice->subtotal) * 100; // 13%
// Display to user (already a decimal!)
$formatted = '$' . number_format($invoice->total, 2); // "$113.00"
$product = Product::find(1); // price = 19.99 (DB has 1999)
$quantity = 3;
$lineTotal = $product->price * $quantity; // 59.97 (19.99 × 3)
$discount = 5.00; // $5.00 discount
$finalTotal = $lineTotal - $discount; // 54.97 ✅
// Works naturally with decimal arithmetic!
// Zero values
$product->price = 0.00; // Stores 0 in DB
// Negative values (refunds, discounts)
$refund->amount = -25.00; // Stores -2500 in DB (negative cents)
// Large numbers
$property->price = 500000.00; // Stores 50000000 in DB ($500,000.00)
Your database columns should be defined as INTEGER (to store cents):
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->integer('price')->default(0); // Stores cents: 1999 = $19.99
$table->integer('cost')->default(0); // Stores cents: 1500 = $15.00
$table->integer('tax')->default(0); // Stores cents: 250 = $2.50
$table->timestamps();
});
Why INTEGER instead of DECIMAL?
| Solution | DB Column Type | PHP Value Type | Precision | Package Size |
|----------|----------------|----------------|-----------|--------------|
| Lara100 | INTEGER (cents) | float (19.99) | ✅ Perfect | Lightweight cast |
| moneyphp/money | INTEGER (cents) | Money object | ✅ Perfect | Full-featured library |
| brick/money | INTEGER (cents) | Money object | ✅ Perfect | Full-featured library |
| Native DECIMAL | DECIMAL(10,2) | float (19.99) | ⚠️ Precision issues | No package needed |
Key Differences:
Choose Lara100 when:
Consider alternatives when:
The package includes comprehensive tests for both the cast and trait:
composer test
Run tests with coverage:
composer test-coverage
Run tests in parallel:
composer test-parallel
Run PHPStan static analysis:
composer phpstan
Run Laravel Pint code formatter:
composer format
Please see CHANGELOG for more information on what has changed recently.
Contributions are welcome! Please feel free to submit a Pull Request.
If you discover a security vulnerability, please send an e-mail to Abdelkarim Mateos Sanchez via [email protected].
The MIT License (MIT). Please see License File for more information.
AichaDigital is a ITt company focused on IT services.