genealabs/laravel-two-way-attribute-casting
A Laravel package that enables two-way attribute casting on Eloquent models, letting you transform values both when reading from and writing to the database with custom cast classes. Useful for encapsulating conversion logic in one place for cleaner, reusable model code.
The decision this assessment actually unlocks is a "no-build, no-buy" call — and that is a useful output. The underlying problem is real and worth framing for the roadmap: monetary and precision-sensitive attributes (decimal(10,2) columns) are frequently passed through PHP floats, and that round trip is a recurring source of "off by one cent" defects in pricing, invoicing, tax, and reporting surfaces. What this specific package changes is whether we solve that with a third-party dependency or with the framework.
CastsAttributes::get() / set(), which apply on both hydrate and persist — precisely the "two-way" behavior this package advertises. Laravel 10/11 add the casts() method and CastsInboundAttributes. This package's last release is May 2018, predating that API, and the repo is archived with 1 star and 0 dependents. The capability is now a framework primitive, so the buy decision collapses to zero cost: write a small in-house cast class.(float) casts, string-formatting accessors, or a vendored copy of this package, this assessment supports a migration ticket: replace with CastsAttributes implementations, delete the accessors (they override casts and cause silent drift), and add round-trip tests.Net PM framing: the problem is worth funding; this package is not the vehicle.
Adoption criteria (all would have to be true):
^0.1.2, not floating), since 0.1.2 changed decimal hydration behavior and 0.1.x semantics were never frozen.Realistically, that combination means: do not adopt for new work, and treat any existing usage as tech debt with a remediation ticket.
Look elsewhere when (the common case):
CastsAttributes class. You get two-way casting, an upgrade path, and no dependency. This covers essentially all modern applications and should be the default recommendation.moneyphp/money (with brick/math for arbitrary precision) and let the cast handle persistence only. A cast normalizes representation; it does not make operators safe, handle FX, or format for a locale.->sum('amount') bypasses casts entirely and returns whatever the driver hands back (a string on MySQL, sometimes an integer on SQLite). No cast package solves this; budget for explicit re-wrapping at the query layer.decimal column. If CI and production use different drivers, that must be tested directly; the package's one historical bug fix (decimal handling in 0.1.2) is a marker of exactly this class of edge case, not evidence it is exhausted.For executives: We evaluated a small open-source Laravel component that standardized how precise decimal values — prices, totals, tax — are read from and written to the database, with the goal of reducing cent-level rounding errors that surface as customer-facing discrepancies and reconciliation work. Recommendation: do not adopt it. The project has been archived by its maintainer, has no users, and last shipped in 2018; more importantly, the framework itself now provides the same capability natively, so there is nothing to license, procure, or maintain. The business need is still real and worth one bounded piece of work: standardize decimal handling in our Eloquent models using Laravel's built-in casting, cover it with round-trip tests, and close the defect class. Cost is internal effort only — roughly half a sprint — with no dependency, no lock-in, and no vendor risk. If any codebase already depends on this package or its hand-rolled equivalent, that becomes a small, scheduled cleanup rather than an open question.
For engineering: The package predates Laravel 7's CastsAttributes interface and is now redundant — the framework applies get() and set() symmetrically on hydrate and persist, which is the entire value proposition described. Last release May 2018, repo archived, zero dependents, one historical fix (0.1.2, decimal handling). Recommendation: close the spike; implement a small in-house cast.
The work, if we proceed:
decimal attributes with a native CastsAttributes implementation (or a thin wrapper around moneyphp/money if currency semantics enter scope — do not extend the cast to cover FX or locale formatting).decimal(10,2), cast scale parameter, and validation rule (decimal:0,2) must agree. Mismatch here is the top source of silent truncation.prepareForValidation, never floats on assignment — and do arithmetic outside the model (bcmath or the value object's methods).Attribute mutator on the same attribute; it wins over the cast and reintroduces drift.assertSame on normalized strings, one case per write path (create, update, fill, refresh, first) plus negative, zero, and high-scale values; run against both the CI driver and the production driver.Guardrails: decide and document rounding vs. truncation for over-scale input (19.999 → 19.99 or 20.00), pin a canonical output scale so string equality and cache keys are stable, and confirm whether null is preserved or coerced to 0.00 — that distinction affects whereNull queries and form prefill. Keep the cast behind a consistent attribute contract so a future swap to moneyphp/money stays cheap.
How can I help you explore Laravel packages today?