vyuldashev/nova-money-field
A Laravel Nova field for handling monetary values with moneyphp/money. Store amounts as integers, format them by locale and currency, and edit money safely in your Nova resources.
Architecture fit. vyuldashev/nova-money-field is a presentation-layer adapter, not a money system. It slots into Laravel Nova's field abstraction (Money::make('Price')->currency('USD')) and delegates value semantics to moneyphp/money. That seam is correct: it belongs in app/Nova/Resources, never in domain services or models. The TPM framing is that this package answers one question — "can operators view and adjust currency-aware amounts in the admin panel without fat-fingering minor units?" — and answers it cheaply. It does not address FX conversion, rounding/allocation policy, tax computation, multi-currency aggregation, or customer-facing price rendering. If those are on the roadmap, they are separate decisions and separate vendors/builds. Architecture fit is therefore high but narrow: it is only high if (a) Nova is already the production admin surface, (b) the domain layer already stores money as integer minor units + ISO currency code, and (c) the requirement is internal display/edit. If money is rendered in Inertia/Livewire/API surfaces, this package creates a second source of truth for formatting and should be scoped as "admin-only," not "our money strategy."
Integration feasibility. Composer-installable, no migrations, no config file, no service provider ceremony — the entire adoption is a composer require, a $casts/accessor decision, and a few lines in a resource's fields() method. A competent Laravel engineer gets a POC running in under a day; the effort is dominated not by the package but by the storage-format decision (integer minor units with a paired currency column vs. decimal). That decision is effectively irreversible once data exists and should be made explicitly and documented before any code is written. Feasibility blockers are external: a paid Nova license, a pinned Nova major version (Nova is closed-source with breaking releases), and a compatible moneyphp/money range.
Technical risk.
Money object. An inconsistent choice produces 100x display or persistence defects — the classic, expensive failure mode here.IntlMoneyFormatter and ICU locale data; version skew between dev, staging, and prod environments yields inconsistent symbols and separators — a support-ticket generator, not an outage.src/Money.php (resolve() and fill()), not the README.Key questions.
moneyphp/money version range is required, and does it conflict with our domain package?->rules()?Verdict. A reasonable, low-cost convenience for an existing Nova admin panel on a single currency, with an already-settled money storage model. Not a money architecture, and not advisable where Nova version currency, vendor support, or procurement process is required.
Stack fit. Assumes Laravel + Laravel Nova + PHP 8.x, with moneyphp/money as the value-object layer and the field as the only Nova-side touchpoint. The recommended shape is a MoneyCast (or accessor/mutator) on the model plus this field purely for admin form/table rendering; API and serialization paths use the same Money value object. This keeps domain logic out of Nova and makes the field a one-file swap if it ever needs replacing.
Migration path.
decimal columns exist, write a backfill migration to minor units and rehearse it against a staging copy with production-shaped data. This is the only step with real downside risk.resolve()/fill() round-trip fidelity in code, not by assumption.Compatibility. Pin exact versions of laravel/nova, this package, and moneyphp/money in composer.json. Add a smoke test that boots a Nova resource route, renders the field, and asserts a value round-trips with amount and currency preserved. That single test is the early-warning system for every Nova upgrade — it converts a silent frontend break into a red CI build.
Sequencing.
price): verify storage round-trip, null/zero/negative handling, locale output under the pinned moneyphp/money.MoneyCast, the backfill migration if needed, and the render/round-trip test to CI. Pin versions.Maintenance. Low day-to-day cost, but effective ownership transfers to us. Budget a periodic "still compatible?" check on each Nova upgrade cycle and accept that at some point you may fork or vendor the field. Because the surface area is genuinely small (a Field subclass with resolve()/fill() and a thin frontend component), forking is viable — keep the field class thin and free of business logic so a fork stays a half-day, not a week.
Support. Community-only; no SLA, no escalation path, no vendor to blame. Internal documentation of conventions (minor units, currency source of truth, null policy, locale expectations) carries more operational weight than upstream docs. Finance-ops and support should know which surfaces display currency and what the "no currency" and "zero" renders look like, so they don't file tickets that turn out to be correct behavior.
Scaling. Runtime cost is negligible — formatting happens at render time on admin routes, not high-throughput paths. The scaling concern is organizational: every new admin surface and every new engineer must internalize the minor-unit convention or you get 100x bugs that pass tests but mislead humans. Scaling out the number of monetary resources scales the convention risk linearly, so enforcement belongs in code review and in the MoneyCast, not in tribal knowledge.
Failure modes.
Ramp-up. Hours for a developer already fluent in Nova fields; under a day including the storage decision and cast. The real onboarding cost is the convention: publish a one-page spec — "monetary columns are integer minor units; currency stored alongside; display via cast + field; no floats; no currency-less amounts" — and enforce it in code review. New engineers should be able to read that spec and one Money::make() call and understand the whole system, which is also the test of whether this package stayed a tactical utility rather than quietly becoming load-bearing.
How can I help you explore Laravel packages today?