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

ph-il/money-bundle

ph-il/money-bundle brings structured money handling to Laravel/PHP apps, with helpers for monetary values, currencies, formatting, and conversions. Use it to keep prices, totals, and currency logic consistent and reusable across your project.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Check your PHP and Symfony versions first

    The 6.4 line requires PHP 8.4+ and Symfony 7.4 or 8.0. This is a hard floor, not a nice-to-have — on anything older, Composer will simply fail to resolve the constraint. Confirm both before you touch Composer:

    php -v            # must be >= 8.4
    php bin/console --version   # Symfony 7.4.x or 8.0.x
    

    Note that v6.4.1 is described as "no real change" over 6.4.0 — it's a housekeeping release (it removes an unused requirement). Don't expect behavioural changes from it.

  2. Install the package

    composer require ph-il/money-bundle
    

    This pulls in moneyphp/money as a dependency. Because moneyphp/money has its own PHP floor, cross-check the resolved version in composer.lock — the bundle's PHP 8.4 requirement and the library's requirement are separate constraints and both must be satisfied.

  3. Register the bundle

    If you're on Symfony Flex with a symfony.lock entry, the bundle is auto-registered. Otherwise add it manually in config/bundles.php:

    Phil\MoneyBundle\PhilMoneyBundle::class => ['all' => true],
    

    The organisation is moving. The release notes state the project will relocate to a new organisation with the next version. That means the Composer package name (ph-il/money-bundle) and possibly the namespace (Phil\MoneyBundle) may change. Confirm the current namespace against vendor/ph-il/money-bundle/src/ before wiring it in, and expect a follow-up migration step. Budget for a composer require new-vendor/money-bundle plus a namespace-wide rename in a future sprint — keep your own imports of bundle classes few and centralised.

  4. Look here first

    • vendor/ph-il/money-bundle/README.md — still the primary documentation.
    • vendor/ph-il/money-bundle/src/DependencyInjection/Configuration.php — the real config reference; every YAML key the bundle accepts is defined here.
    • vendor/ph-il/money-bundle/src/Resources/config/services.xml (or .php) — tells you which service IDs are available to inject.
  5. First use case: format a price in Twig

    Build a Money object using the library directly:

    use Money\Money;
    use Money\Currencies\ISOCurrencies;
    use Money\Formatter\IntlMoneyFormatter;
    
    $money = new Money(1999, new \Money\Currency('USD')); // 19.99 USD, in minor units
    

    Then either pass it to the view and format with a Twig extension if the bundle ships one, or format in the controller. Prefer injecting a bundle-provided formatter service over newing up IntlMoneyFormatter yourself — that keeps the intl extension and locale configured once.

    Dump the container to see exactly what's registered:

    bin/console debug:container --show-private | grep -i money
    

Implementation Patterns

Inject the formatter, don't construct it. The value of a bundle is centralised configuration of Money\Formatter\DecimalMoneyFormatter / IntlMoneyFormatter and the Money\Currencies\Currencies implementation (usually ISOCurrencies). Injecting the service keeps currency lists consistent across the app and lets you swap ISOCurrencies for a custom currency set in one place.

Keep minor units at the boundary. Store and transport integer minor units (1999), convert to decimal strings only for display. If the bundle provides a Doctrine type, it almost certainly maps to BIGINT/INTEGER — confirm the column type in the bundle's Doctrine/ directory before migrating existing columns, since a mistaken DECIMAL(10,2) will silently misbehave.

Symfony Form integration. If a MoneyType form field is registered, use it with the divisor option so user input like 19.99 maps to 1999. This keeps parsing logic out of your controllers:

$builder->add('price', MoneyType::class, [
    'currency' => 'USD',
    // 'divisor' => 100,
]);

Conversion and exchange. For anything involving CurrencyPair, Money\Converter, or an exchange service, wrap the bundle's service in your own thin adapter (e.g. PriceConverter) rather than injecting it across the codebase. Given the organisation move on the horizon, a single call site for third-party money logic means a future namespace change or fork touches one class, not forty.

Testing. Assert on Money values, not strings:

$this->assertTrue($invoice->getTotal()->equals(Money::USD(1999)));

Where you need to assert against stored values, use getAmount() (integer) and getCurrency()->getCode() — comparing IntlMoneyFormatter output ties your tests to the ICU version installed on the CI machine.

Plan a migration window for v8.0. The release notes promise "lots of rewrite to move in a more modern way" in 8.0 (PHP 8.4+ / Symfony 8.0, and likely a new namespace under the new organisation). Keep your integration thin and documented so the 7.x → 8.0 upgrade is a contained change.

Gotchas and Tips

  • Organisation move is the headline gotcha. The bundle is relocating to a new organisation, and with it the Composer package name and (likely) the PHP namespace. A version pin on ph-il/money-bundle will not follow the project when it moves. Record the current version in composer.json, watch the project's repository for the new name, and re-test imports after any switch. Keep bundle-specific code in as few files as possible so the rename is mechanical.
  • PHP 8.4+ / Symfony 7.4|8 requirement. Older PHP or Symfony installations are simply incompatible with 6.4+. If you're on 8.2/8.1, you'll have to stay on an earlier minor of the bundle or upgrade your runtime first. Check the composer.json require block to see the exact constraint of whatever version you install.
  • Read the roadmap before adopting. The notes confirm an active roadmap (6.4 → 8.0) and a move to PHPStan for static analysis. That's a positive signal — the "one star = abandoned" narrative from earlier assessments is now out of date — but it also means API churn. Expect at least one significant update cycle within the lifetime of your project.
  • Pin the version. Add an explicit constraint ("ph-il/money-bundle": "^6.4" or whatever tag resolves) rather than *, and commit composer.lock. With an advertised 8.0 rewrite inbound, ^6.4 gives you patch-level fixes without silently pulling a breaking 7.x.
  • Minor units, always. new Money(19.99, ...) will fail or behave unexpectedly — moneyphp accepts integers only (or numeric strings on newer versions). Every "the number is 100× too big" bug traces back to this. Cast and validate before constructing.
  • Currency scale is not always 2. ISOCurrencies knows that JPY has 0 decimals and KWD has 3. Never hardcode /100. Use Money\Money::getAmount() plus the currency's subunit count when converting manually.
  • intl extension required. IntlMoneyFormatter needs ext-intl. Minimal Docker images (e.g. php:8.4-alpine) often lack it — Composer installs fine, formatting blows up at runtime. Add intl to your image build.
  • Locale drift in output. IntlMoneyFormatter respects the \NumberFormatter locale, so $19.99 becomes 19,99 $ under fr_FR. Set locale per request for user-facing output; use DecimalMoneyFormatter for logs and APIs.
  • Doctrine types and schema diffs. If the bundle ships a custom DBAL type, doctrine:schema:validate may flag existing columns. Register the type explicitly in doctrine.dbal.types if the bundle doesn't do it via a compiler pass — otherwise Unknown column type "money" appears only on first hydration.
  • Configuration quirks. Don't assume a default_currency key exists — check Configuration.php. If it's absent, define your default currency in your own parameters and inject it rather than expecting the bundle to fill the gap.
  • Extension point that usually matters: the Currencies service. Override it in services.yaml (same service ID, your implementation) if you need a restricted currency list — safer than forking, and much safer given the imminent re-organisation.
  • Static analysis. The project is standardising on PHPStan (previously Psalm) as of the version-8 line. If you run PHPStan in CI, don't expect the bundle to ship its own baseline coverage — exclude vendor/ as usual and rely on your own typed adapters around bundle classes.
  • Debugging tips. bin/console debug:container Money\Money to locate the service; bin/console lint:container catches wiring errors before runtime; if a compiler pass fails silently, run with -vvv after bin/console cache:clear.
  • Escape hatch. The underlying moneyphp/money library is well-maintained and independent of the bundle. You can always drop the bundle and wire the two or three services you use directly in services.yaml. Given the organisation move and 8.0 rewrite, plan the integration so this remains a half-day change rather than a refactor.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib