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

syno/money-bundle

Syno Money Bundle provides Symfony integration for working with monetary values and currencies, packaging money-related services and configuration to help keep amount handling consistent across your application.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install (the bundle does not ship moneyphp/money transitively in a way you should rely on — require both, explicitly pinned):

    composer require syno/money-bundle:^1.0 moneyphp/money:^4.0
    
  2. Register the bundle. In a modern Symfony app this is a one-liner in config/bundles.php:

    Tbbc\MoneyBundle\TbbcMoneyBundle::class => ['all' => true],
    
  3. Minimum viable config in config/packages/tbbc_money.yaml:

    tbbc_money:
        reference_currency: EUR
        currencies: [EUR, USD, GBP]
        decimal_digits: 2
    

    Everything else (storage, ratio provider) has defaults that work for a first smoke test.

  4. Verify the wiring before writing code. The bundle is a thin DI layer, so the container is the API:

    bin/console config:dump-reference tbbc_money
    bin/console debug:container tbbc_money.money_manager
    bin/console debug:twig --filter=money
    bin/console debug:validator | grep -i money
    

Where to look first, in order

File Why
DependencyInjection/Configuration.php The authoritative config tree. This is the only doc you can trust for a 0-star package.
MoneyManager.php The façade service you'll inject into controllers/services.
Form/Type/MoneyType.php + Resources/views/Form/ The composite amount+currency widget and its theme.
Twig/Extension/* Exact filter names — they vary by fork, so don't guess from blog posts.
Validator/Constraints/Money* The constraint and its validator.

First use case — a product price. Add a price field to your entity, expose it with the bundle's form type, render it with the Twig filter, and guard it with the Money constraint. That loop (form → entity → template → validator) is 90% of what this bundle is for.

Implementation Patterns

Route all money creation through the manager. Don't new Money(...) in controllers; inject tbbc_money.money_manager and call createMoney($amount, $currencyCode). The decimal_digits config decides how the amount argument is interpreted (decimal string vs. minor units) — read MoneyManager::createMoney() once, write a test that asserts createMoney(100, 'EUR') gives the value you expect, and then never think about it again.

Form usage. The bundle's MoneyType renders an amount input plus a currency select limited to your configured currencies. Two patterns worth adopting:

$builder->add('price', MoneyType::class, [
    'currency' => 'EUR',        // pin it when the user shouldn't choose
    'scale'    => 2,
]);

If your domain has exactly one currency per entity (most do), pin currency and skip the select entirely — it removes a whole class of validation bugs.

Persisting. Never store a float. Either store amount (integer minor units) + currency (3-char code) as two columns, or map Money as a Doctrine embeddable with those two properties and a __toString/getter that reconstitutes Money on hydrate. A DBAL custom type also works but is overkill for two scalar columns.

Currency conversion. Two providers:

  • ratio_provider: config — static rates in YAML. Correct for fixtures and tests, wrong for production FX.
  • ratio_provider: doctrine — the bundle's CurrencyPair/Ratio entities, which you own the migrations and admin CRUD for.

Either way, conversion happens through the manager. Wrap it: conversion hits the DB (or the config array) per call, so cache rates per request and never convert inside a loop over 200 order lines.

Serialization / API boundary. Emit money as strings, never JSON numbers:

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

Derive the string from Money::getAmount() / Money::getCurrency()->getSubUnit() at the serialization edge, so internal storage stays integer.

Validation. Combine the bundle's Money constraint (type/format) with your own (non-negative, currency whitelist, max for the field). The bundle's constraint won't know your business rules.

Testing. Use KernelTestCase and boot a real container; the services are private by default on Symfony 4+. Build expected values with moneyphp/money directly rather than with MoneyManager, otherwise you're asserting the object under test against itself.

Gotchas and Tips

  • Maintenance is the headline risk. Zero stars, zero dependents, last release March 2022, and it's a fork of tbbc/money-bundle. There is no forward-compat guarantee with Symfony 6.4/7.x or PHP 8.3+. Pin the exact version in composer.json, and budget for vendoring: the useful surface (form type, Twig filter, validator) is a few hundred lines.
  • Check symfony/* constraints before installing. A 2022-era bundle may declare ^5.0 and still install under 6.x with a warning, then break on form theme paths or autowired constructor arguments. Run the test suite of the bundle's demo if one exists.
  • decimal_digits is a single global value, but currencies don't share one. JPY has 0 minor digits, KWD has 3. A config of 2 silently rounds a JPY amount. For anything genuinely multi-currency, use Currency::getSubUnit() from moneyphp and treat the bundle setting as a display default only.
  • reference_currency defaults to EUR. If you never set it, every conversion pivots through EUR in ways that are invisible until your rates are wrong. Set it explicitly even when you think it doesn't matter.
  • Twig filter output is not locale-aware. The bundle string-formats; it doesn't consult intl. For user-facing prices, prefer NumberFormatter::CURRENCY and use the bundle filter only in admin/debug views, or you'll fight thousands separators per locale.
  • Model transformer type errors. The form expects a Money instance (or null) on the model side. Passing a string from a fixture or a JSON payload throws deep inside the transformer with an unhelpful message. Validate the input type at your DTO boundary before it reaches the form.
  • Private services. Inject tbbc_money.money_manager via an alias in services.yaml or rely on autowiring by MoneyManager type; $container->get() in a controller will fail on modern Symfony.
  • Extension points, not patches. The ratio provider is an interface — implement your own backed by an FX API + Redis rather than bending the config provider. Same for the Twig extension if you need a house format. Forking the bundle for these is a waste; decorating is not.
  • Ask whether you need it at all. If you already use moneyphp/money directly, this bundle buys you a form type, a Twig filter, and a validator binding. Weigh that against an unmaintained dependency in your composer.json — for most applications, a small custom MoneyType and one Doctrine embeddable are cheaper and safer than adopting a zero-star 2022 fork.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource