PHPackages                             aichadigital/lara100 - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. aichadigital/lara100

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

aichadigital/lara100
====================

Laravel cast for handling decimal values as base-100 integers (cents/centesimals)

v2.0.0(1w ago)0902[1 issues](https://github.com/AichaDigital/lara100/issues)[1 PRs](https://github.com/AichaDigital/lara100/pulls)1MITPHPPHP ^8.3|^8.4CI passing

Since Oct 10Pushed 3d agoCompare

[ Source](https://github.com/AichaDigital/lara100)[ Packagist](https://packagist.org/packages/aichadigital/lara100)[ Docs](https://github.com/aichadigital/lara100)[ RSS](/packages/aichadigital-lara100/feed)WikiDiscussions main Synced today

READMEChangelog (8)Dependencies (43)Versions (16)Used By (1)

Lara100 — Exact Decimal for Laravel
===================================

[](#lara100--exact-decimal-for-laravel)

[![Latest Version](https://camo.githubusercontent.com/e12ed48104155aeb8978cdb50d0d16a6a79bad330d06f506d67bac2c8f81c4b0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f61696368616469676974616c2f6c6172613130302e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aichadigital/lara100)[![Total Downloads](https://camo.githubusercontent.com/cd59ddf569218359f313eb3dda0bfa3775e47b0bc40adcaf08f958752233627b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f61696368616469676974616c2f6c6172613130302e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aichadigital/lara100)[![Tests](https://camo.githubusercontent.com/7edada64e2781eca1f53eb07dab7c507beea0ac4e97ef85cb0b798928097a522/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f41696368614469676974616c2f6c6172613130302f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/AichaDigital/lara100/actions?query=workflow%3Arun-tests+branch%3Amain)[![Code Style](https://camo.githubusercontent.com/67dba782d1b6eeda58b1dab6ad4a4875db5524fc288c2c75e045e11197c58121/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f41696368614469676974616c2f6c6172613130302f70696e742e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/AichaDigital/lara100/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Code Coverage](https://camo.githubusercontent.com/35c996cf391082607ed2f09313c919d9907ad2ad24eb4c426ee704719b9339ba/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f41696368614469676974616c2f6c6172613130303f7374796c653d666c61742d737175617265266c6f676f3d636f6465636f76)](https://codecov.io/gh/AichaDigital/lara100)[![PHPStan level max](https://camo.githubusercontent.com/a60c66806869738507a0d6a41376d9aa8bfa5bb2fe69bf4cb5969aa7e6f251b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c2532306d61782d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265266c6f676f3d706870)](https://phpstan.org/)[![PHP Version](https://camo.githubusercontent.com/fafd8fd17ff7d92fb7d097b065f3d3ffed563aa79ad21dd9d44beacadc99898b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f61696368616469676974616c2f6c6172613130302e7376673f7374796c653d666c61742d737175617265266c6f676f3d706870)](https://packagist.org/packages/aichadigital/lara100)[![Laravel Version](https://camo.githubusercontent.com/18f881b50e044a91960c1023095094599e65c156497c42fffd139e2e14059fc7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31322e7825323025374325323031332e782d7265642e7376673f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c)](https://laravel.com)[![License](https://camo.githubusercontent.com/012a7f0e67549c02959673eb9cc1d01c81fdfb46b178083223c7d36a296c39b4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f61696368616469676974616c2f6c6172613130302e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aichadigital/lara100)

A Laravel package providing an **immutable, scale-configurable exact decimal value object** (`FixedDecimal`) and a matching Eloquent cast (`FixedDecimalCast`). Values are stored as plain integers (unscaled) in the database; the cast and value object handle all precision arithmetic using `brick/math` under the hood.

Why Lara100?
------------

[](#why-lara100)

Floating-point arithmetic is not safe for monetary or fiscal values:

```
0.1 + 0.2 === 0.3;  // false — result is 0.30000000000000004
```

`FixedDecimal` eliminates this class of error entirely:

```
use AichaDigital\Lara100\ValueObjects\FixedDecimal;

$a = FixedDecimal::ofDecimalString('0.1');
$b = FixedDecimal::ofDecimalString('0.2');
$c = $a->plus($b);

$c->toDecimalString();  // '0.3' — exact, always
```

Arithmetic is exact at every step. The result serialises as a decimal string (`'0.3'`), not a float, so API consumers and hash-based fiscal systems (AEAT Verifactu, etc.) always receive the canonical value.

Requirements
------------

[](#requirements)

- PHP 8.3 or 8.4
- Laravel 12.x or 13.x
- `brick/math` ^0.14.2 (pulled in automatically)

Installation
------------

[](#installation)

```
composer require aichadigital/lara100
```

No configuration file is required — lara100 ships with no publishable config.

Usage
-----

[](#usage)

### 1. Database schema

[](#1-database-schema)

Store unscaled integers. The scale is declared at the model level, not in the column:

```
Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->integer('price')->default(0);      // scale 2: 1999 = 19.99
    $table->integer('exchange_rate')->default(0); // scale 4: 12345 = 1.2345
    $table->timestamps();
});
```

### 2. Model casts

[](#2-model-casts)

Declare the cast with the scale as a colon-separated suffix. The scale is **required**; omitting it throws immediately rather than silently misinterpreting the column:

```
use AichaDigital\Lara100\Casts\FixedDecimalCast;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected function casts(): array
    {
        return [
            'price'         => FixedDecimalCast::class.':2',  // 1999 → 19.99
            'exchange_rate' => FixedDecimalCast::class.':4',  // 12345 → 1.2345
        ];
    }
}
```

### 3. Reading and writing

[](#3-reading-and-writing)

The cast accepts only `FixedDecimal|null` on assignment. Scalars are rejected deliberately — callers must choose the conversion explicitly:

```
// Reading: the cast returns a FixedDecimal built from the stored integer
$product = Product::find(1);
$price = $product->price;           // FixedDecimal('19.99', scale=2)
$price->toDecimalString();          // '19.99'
$price->unscaledValue();            // 1999
$price->scale();                    // 2
echo json_encode($price);           // "19.99"  (exact decimal string, not float)

// Writing: build a FixedDecimal explicitly, then assign it
$product->price = FixedDecimal::ofDecimalString('29.99', 2);
$product->save();                   // DB stores 2999 (integer)

// null is allowed for nullable columns
$product->price = null;
$product->save();                   // DB stores NULL
```

Assigning a raw scalar throws `InvalidFixedDecimal` — the strict contract prevents accidental precision loss at the boundary:

```
$product->price = 19.99;  // throws InvalidFixedDecimal — use ofDecimalString / ofFloat
```

### 4. Constructing FixedDecimal

[](#4-constructing-fixeddecimal)

**Recommended constructors:**

```
use AichaDigital\Lara100\ValueObjects\FixedDecimal;

// From the raw stored integer (no conversion, no rounding — the cleanest path)
$price = FixedDecimal::ofUnscaled(1999, 2);   // 19.99
$rate  = FixedDecimal::ofUnscaled(12345, 4);  // 1.2345

// From a decimal string (parse and optionally coerce to a target scale)
$price = FixedDecimal::ofDecimalString('19.99');       // scale inferred from the string's decimals (here, 2)
$price = FixedDecimal::ofDecimalString('19.9', 2);     // coerced to scale 2 → '19.90'

// Zero at a given scale
$zero = FixedDecimal::zero(2);  // 0.00
```

**Migration-only boundary (not for new code):**

```
use AichaDigital\Lara100\RoundingMode;

// From a float — reintroduces IEEE-754 at the boundary; use only when crossing
// a legacy float API or when receiving user input that cannot be treated as a string
$price = FixedDecimal::ofFloat(19.99, 2, RoundingMode::HalfUp);
```

### 5. Arithmetic

[](#5-arithmetic)

All arithmetic produces a new `FixedDecimal`; the original is unchanged (immutable):

```
$price    = FixedDecimal::ofDecimalString('19.99');
$tax_rate = FixedDecimal::ofDecimalString('0.21');

$tax   = $price->multipliedBy($tax_rate)->toScale(2, RoundingMode::HalfUp);
$total = $price->plus($tax);

$tax->toDecimalString();    // '4.20'
$total->toDecimalString();  // '24.19'

// Division always requires an explicit scale and rounding mode
$half = $total->dividedBy(2, 2, RoundingMode::HalfUp);
$half->toDecimalString();   // '12.10'
```

Available arithmetic: `plus`, `minus`, `multipliedBy`, `dividedBy`, `toScale`, `negated`, `abs`.

### 6. Comparison

[](#6-comparison)

```
$a = FixedDecimal::ofDecimalString('10.00');
$b = FixedDecimal::ofDecimalString('20.00');

$a->isEqualTo($b);      // false
$a->isLessThan($b);     // true
$a->isGreaterThan($b);  // false
$a->isZero();           // false
$a->isPositive();       // true
$a->isNegative();       // false
$a->compareTo($b);      // -1
```

### 7. Output

[](#7-output)

```
$price = FixedDecimal::ofUnscaled(1999, 2);

$price->toDecimalString();   // '19.99'   — exact, preferred for persistence / hashing
$price->unscaledValue();     // 1999      — raw stored integer
$price->scale();             // 2
$price->toFloat();           // 19.99     — reintroduces float imprecision; display/legacy only
$price->toBigDecimal();      // Brick\Math\BigDecimal — escape hatch for raw brick/math use
json_encode($price);         // "19.99"   — jsonSerialize() returns the decimal string
```

### 8. RoundingMode

[](#8-roundingmode)

lara100 ships its own `RoundingMode` enum — fully encapsulated from the underlying `brick/math` engine:

CaseDescriptionTypical use`HalfUp`0.5 rounds away from zero**EU/Spain fiscal standard; default**`HalfEven`0.5 rounds to nearest evenBanker's rounding; accounting`HalfDown`0.5 rounds toward zeroConservative rounding`Up`Always away from zeroAlways round up`Down`Always toward zero (truncate)Always truncate`Ceiling`Toward positive infinity`Floor`Toward negative infinity`HalfUp` is the European/Spanish fiscal standard and the default wherever lara100 accepts a rounding mode. `HalfEven` (banker's rounding) is the right choice for general accounting aggregations.

Positioning
-----------

[](#positioning)

lara100 is a **Laravel-native, scale-aware exact decimal** built on top of `brick/math`. It occupies a specific niche — here is when to reach for each option:

LibraryAbstractionLaravel castCurrencyWhen to use**lara100**`FixedDecimal` (exact, scale-aware)Yes (`FixedDecimalCast`)NoPrices, rates, fiscal amounts in Laravel — exact arithmetic without currency overhead`brick/math``BigDecimal`, `BigInteger`NoNoRaw exact arithmetic outside Laravel; lara100 builds on this`brick/money``Money` (amount + currency)NoYesMulti-currency systems, allocation, currency conversion`moneyphp/money``Money` (amount + currency)NoYesSame as brick/money; wider ecosystem adoption**Choose lara100 when:**

- You are building a Laravel application and want Eloquent models to carry `FixedDecimal` attributes directly
- You need exact arithmetic over scale-aware values (prices at scale 2, VAT rates at scale 4, etc.)
- You do not need multi-currency support or allocation algorithms

**Reach for brick/math directly when:**

- You need exact arithmetic outside of Laravel (CLI tools, pure PHP libraries, etc.)
- You need `BigInteger` or `BigRational` (lara100 only wraps `BigDecimal`)

**Reach for brick/money or moneyphp/money when:**

- You need currency codes, currency conversion, or monetary allocation (splitting a total into N parts that sum exactly)

lara100 encapsulates `brick/math ^0.14.2` internally. The dependency is lightweight; `brick` types are not exposed except via the explicit `toBigDecimal()` escape hatch.

Comparison with Alternatives
----------------------------

[](#comparison-with-alternatives)

SolutionDB columnPHP valuePrecisionLaravel castMulti-currency**lara100 `FixedDecimal`**`INTEGER` (unscaled)`FixedDecimal` (exact)ExactYesNo**lara100 `Base100Int`**`INTEGER` (cents)`int`ExactYesNo`brick/math` (`BigDecimal`)—`BigDecimal` (exact)ExactNoNo`brick/money``INTEGER``Money` (exact + currency)ExactNoYes`moneyphp/money``INTEGER``Money` (exact + currency)ExactNoYesNative `DECIMAL` column`DECIMAL(10,2)``float`Float — impreciseNoNoTesting
-------

[](#testing)

```
composer test
composer test-coverage
composer test-parallel
```

Code Quality
------------

[](#code-quality)

```
composer phpstan
composer pint
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

If you discover a security vulnerability, please send an e-mail to Abdelkarim Mateos Sanchez via .

Credits
-------

[](#credits)

- [Abdelkarim Mateos Sanchez](https://github.com/aichadigital)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

About AichaDigital
------------------

[](#about-aichadigital)

AichaDigital is an IT company focused on IT services.

###  Health Score

51

—

FairBetter than 95% of packages

Maintenance99

Actively maintained with recent releases

Popularity20

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 97.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~36 days

Recently: every ~52 days

Total

8

Last Release

13d ago

Major Versions

v1.3.0 → v2.0.02026-06-22

### Community

Maintainers

![](https://www.gravatar.com/avatar/0a4694c48c325d3dfbc4c43d97c2617f9317d7a447971750c338f943a88bd164?d=identicon)[abkrim](/maintainers/abkrim)

---

Top Contributors

[![abkrim](https://avatars.githubusercontent.com/u/1238625?v=4)](https://github.com/abkrim "abkrim (40 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

laraveldecimalcastprecisionmonetarybase100AichaDigitallara100

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/aichadigital-lara100/health.svg)

```
[![Health](https://phpackages.com/badges/aichadigital-lara100/health.svg)](https://phpackages.com/packages/aichadigital-lara100)
```

###  Alternatives

[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.9k102.4M1.4k](/packages/spatie-laravel-permission)[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[codewithdennis/filament-select-tree

The multi-level select field enables you to make single selections from a predefined list of options that are organized into multiple levels or depths.

329530.5k29](/packages/codewithdennis-filament-select-tree)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.0k](/packages/simplestats-io-laravel-client)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.6k](/packages/rawilk-profile-filament-plugin)[api-platform/laravel

API Platform support for Laravel

58171.8k14](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
