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

Dosh Laravel Package

bluebaytravel/dosh

Dosh is a Laravel package for working with money in your application. It provides convenient helpers for formatting and displaying monetary values, helping keep prices consistent, readable, and currency-aware across your app.

View on GitHub
Deep Wiki
Context7

Getting Started

bluebaytravel/dosh is a deliberately small, framework-agnostic currency formatter. Treat it as a thin presentation helper, not a money library — it turns a numeric amount plus a currency code into a localized display string and does nothing else.

composer require bluebaytravel/dosh

Where to look first

  1. README.md — the entire public API is usually demonstrated in one or two snippets; the surface area is tiny.
  2. src/ — with a package this small you can read every class in a few minutes. Confirm the exact method signature, whether it is static or instance-based, and whether a Laravel service provider / facade is shipped (check composer.json for illuminate/support).
  3. composer.json — check the PHP version constraint and whether it depends on ext-intl (almost certainly) versus a pure-PHP fallback.

First use case

Formatting a stored price for display in a storefront or invoice. The canonical flow is: persist amounts as integers in minor units (pence/cents), then format only at the edge of the application:

use BlueBayTravel\Dosh\Dosh;

// Illustrative — verify the exact signature in src/ before relying on it.
$formatter = new Dosh();

echo $formatter->format(129900, 'GBP'); // "£1,299.00"

If you are in Laravel, register it once in a service provider so you inject a configured instance rather than new-ing it in views:

$this->app->singleton(Dosh::class, fn () => new Dosh());

Implementation Patterns

Format at the presentation edge, never in models or queries. Keep price as an integer column and expose a formatted string via an accessor, view model, or API resource. Avoid storing pre-formatted strings — they are locale- and ICU-version-dependent.

Wrap it in your own adapter. Because the package is tiny and low-traffic, insulate your codebase behind one class you own:

final class PriceFormatter
{
    public function __construct(private Dosh $dosh, private string $locale = 'en_GB') {}

    public function format(int $minorUnits, string $currency, int $scale = 2): string
    {
        $amount = $minorUnits / (10 ** $scale);

        return $this->dosh->format($amount, $currency);
    }
}

This gives you a single place to swap in Brick\Money or NumberFormatter later, and a single place to handle zero-decimal currencies.

Blade component for views. Keep formatting out of templates beyond a single call:

{{-- resources/views/components/price.blade.php --}}
@props(['minor', 'currency' => 'GBP'])
<span {{ $attributes }}>{{ app(\App\Support\PriceFormatter::class)->format($minor, $currency) }}</span>
<x-price :minor="$product->price" currency="GBP" />

API resources: return both forms. Machine consumers want the raw value; humans want the formatted one. Returning only a formatted string forces clients to parse localized text.

return [
    'amount'   => $this->price,          // 129900
    'currency' => 'GBP',
    'formatted' => $formatter->format($this->price, 'GBP'),
];

Locale per request. If you serve multiple locales, resolve the locale from the user/request and pass it into your formatter wrapper rather than relying on a global default. Test that de_DE renders 1.299,00 € and en_GB renders £1,299.00.

Testing. Assert on formatted output for a fixed locale and ICU version, and assert on raw minor units everywhere else. Keep a small table-driven test covering: zero, negative, large values, zero-decimal currency (JPY), and an unknown currency code.

Gotchas and Tips

  • It formats; it does not calculate. No arithmetic, conversion, allocation, or rounding policy. For anything beyond display, use Brick\Money / moneyphp/money and let Dosh (or your adapter) handle only the final string.
  • Floats are a trap. Passing 12.99 as a float can surface as 12.989999... depending on the formatter's rounding. Store integers or strings and divide at the last moment, or pass a decimal string if the API accepts one.
  • Zero-decimal currencies. JPY, KRW, VND and friends have no minor unit. A naive amount / 100 will be wrong by two orders of magnitude. Guard this in your adapter with a scale map.
  • Locale, not currency, drives the format. 1,234.56 vs 1.234,56 vs 1 234,56 comes from the locale. Decide whether your app is single-locale (hardcode en_GB) or user-locale driven, and be consistent.
  • ICU / ext-intl dependency. Output can shift between ICU versions bundled with different PHP builds. If your CI and production images differ, golden-string tests can fail for reasons unrelated to your code. Pin the base image or assert loosely.
  • Currency code casing. Use ISO 4217 uppercase (GBP, USD). Lowercase codes may silently fall back to a generic symbol or throw — verify behavior for unknown codes and decide whether to fail loudly or degrade to the code itself.
  • Negative amounts. Decide early whether you want -£5.00, (£5.00), or £-5.00. Formatters differ; wrapping the output is usually easier than fighting the library.
  • No config to publish. If the package ships no config file, don't look for one — put your defaults (locale, default currency, scale map) in your own adapter/config class.
  • Debugging. Confirm php -m | grep intl first. Compare Dosh's output against a direct numfmt_format_currency() call to isolate whether the problem is your input or the underlying formatter.
  • Extension points are minimal by design. The realistic extension path is your own wrapper class, not subclassing. If you need symbols-only output, custom separators, or abbreviated notation (£1.2k), implement it in the adapter on top of the formatted string or bypass Dosh entirely.
  • Maintenance risk. With ~21 stars this is effectively a small in-house package published openly. Pin the version in composer.json, read the diff before upgrading, and keep the adapter so a fork or replacement is a one-file change.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package