Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Money Bundle Laravel Package

yceruto/money-bundle

A Symfony bundle that integrates MoneyPHP into your app, offering form types, Twig extensions, Doctrine mapping, validators, and serializers for handling monetary amounts and currencies safely and consistently.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the bundle with Composer and let Flex wire it up:

composer require yceruto/money-bundle

If you are not using Symfony Flex (or the recipe is not available for your version), register it manually in config/bundles.php:

return [
    // ...
    Yceruto\MoneyBundle\MoneyBundle::class => ['all' => true],
];

The bundle is a thin integration layer over moneyphp/money, so the first thing to read is the bundle's own DependencyInjection/Configuration.php and Resources/config/*.yaml in vendor/yceruto/money-bundle/. That tells you exactly which services, Doctrine types, form types, and Twig helpers are registered and what config keys exist. Do this before reading the README — the config tree is the source of truth for a small bundle like this.

A minimal config/packages/money.yaml is usually enough:

money:
    default_currency: EUR

Your first end-to-end use case should be "store a price on an entity and render it":

  1. Add a Money property to a Doctrine entity and map it with the bundle's DBAL type (check the type name registered by the bundle — typically money).
  2. Create a form with the bundle's MoneyType field so users enter amount + currency.
  3. Render it in Twig with the bundle's filter/function, or serialize it through the provided normalizer for an API.

If any of those three pieces is missing in your version, the underlying moneyphp/money API still works — the bundle just removes boilerplate.

Implementation Patterns

Doctrine persistence. Prefer the bundle's DBAL type over a manual amount/currency pair so hydration always returns a Money object instead of a raw string. Two common storage layouts:

  • Two columns: amount BIGINT (minor units) + currency CHAR(3).
  • One column: a single string/JSON column, parsed by the type.

Whichever the bundle uses, align your migrations with it. When generating a migration, verify the generated ADD/ALTER statements use the right column type — DBAL custom types often need ->setColumnType() or a manual edit.

Form handling. Use the provided MoneyType for input rather than two bare text fields. If your users type "12,50 €" rather than 1250, parse it with Money\Parser\DecimalMoneyParser (or AggregateMoneyParser for multi-currency) in a form data transformer, and let the bundle's field handle the amount/currency split. Keep the transformation at the form boundary so your domain always receives a valid Money.

Serialization / APIs. Register the bundle's normalizer and expose money as an object:

{ "amount": "1250", "currency": "EUR" }

Document for your frontend team that amount is in minor units and is a string to avoid JS integer overflow. If you need a different shape ("{ "value": 12.50, "currency": "EUR" }"), write a small custom normalizer and tag it serializer.normalizer with a higher priority than the bundle's.

Service-layer usage. Inject Money factories or the bundle's configured currency/parser services into your pricing, cart, and invoice services instead of new Money(...) scattered through the code. That keeps currency defaults and rounding policy in one place.

Twig rendering. Use the bundle's money filter/function in templates, passing the locale explicitly where the app is multi-locale. For PDFs and emails, render server-side with the same helper so formatting stays consistent with the web UI.

Validation. Combine the form type with a GreaterThan(0) or custom constraint on the underlying amount. moneyphp/money throws InvalidArgumentException on malformed input, so wrap parsing in try/catch and convert to form errors rather than letting a 500 escape.

Gotchas and Tips

  • Minor units are the #1 source of bugs. Money::EUR(1000) is €10.00, not €1000. Every bug report about "amounts are 100x off" traces back to this. Write the conversion in exactly one place (a parser/form transformer) and use it everywhere.
  • Never use floats. Construct Money from strings or integers. Money::EUR(0.1 + 0.2) will bite you; Money::EUR('30') will not.
  • Money is immutable. $money->add($other) returns a new instance. Forgetting to reassign ($total = $total->add($line)) silently loses data.
  • Currency mismatch throws. Adding EUR to USD raises InvalidArgumentException. Guard at boundaries (cart vs. catalog currency) with an explicit check and a domain exception.
  • Doctrine type registration. If you see Unknown column type "money" after install, the bundle's DBALTypes registration did not run — check that the bundle is enabled and that doctrine.dbal.types is not overridden in your config. Clearing the cache (bin/console cache:clear) after config changes is usually required.
  • Migrations don't know custom types. doctrine:migrations:diff may emit VARCHAR or fail on a custom type. Set the column type explicitly in the entity mapping and review every generated migration by hand.
  • Config quirks. Small bundles like this often only expose default_currency and a couple of toggles. Run bin/console debug:config money and bin/console debug:container --tag=… to see what's actually wired before assuming a feature exists.
  • Serializer output is not human-friendly. The default object shape (amount in minor units, ISO code) is for machines, not users. Do not surface it directly in an API consumed by non-technical clients without a documented contract.
  • Extension points. Override the bundle's services in config/services.yaml (same service id, decorates: or a compiler pass) for custom normalizers, Twig extensions, or a different parser. Prefer decoration over forking; the bundle is small and its service IDs are stable enough for this.
  • Testing. Assert on Money objects ($this->assertEquals(Money::EUR(1250), $order->getTotal())), not on strings. In functional tests, seed the DB with minor-unit integers so fixtures match what the DBAL type hydrates.
  • Version pinning. With a low-traffic bundle like this (29 stars, releases as recent as Dec 2025), pin to a minor version and watch the changelog. The surface area is small, so the cost of a breaking change is low, but so is the buffer against one.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style