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

Laravel Formatters Laravel Package

michael-rubel/laravel-formatters

Laravel Formatters provides a clean, extensible set of formatter classes for common tasks like money, phone numbers, names, dates, and more. Formatters auto-resolve through the container and support method chaining, making consistent formatting simple throughout your app.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require michael-rubel/laravel-formatters

The package is small and opinionated: it gives you an abstract MichaelRubel\Formatters\Formatter, a formatter() helper that resolves formatters from the container, a CollectionFormatter base for collection/array transformations, and (typically) a make:formatter generator. There is no service provider wiring you need to touch in a standard Laravel app — package discovery handles it.

First place to look is the source (vendor/michael-rubel/laravel-formatters/src) and the README; the public surface is intentionally tiny, so a five-minute read covers it.

Create your first formatter:

namespace App\Formatters;

use MichaelRubel\Formatters\Formatter;

class PriceFormatter extends Formatter
{
    public function format(float|int|null $value): string
    {
        return $value === null
            ? '—'
            : number_format($value, 2, '.', ' ');
    }
}

First real use case — format at the boundary of your app (Blade, API resource, mail), not inside the model:

formatter(PriceFormatter::class)->format($order->total);

Implementation Patterns

One formatter per concern. Keep them tiny and pure: PriceFormatter, DateFormatter, PhoneFormatter, FullNameFormatter. A formatter that touches the database or dispatches events has stopped being a formatter.

Configuration via the constructor. Pass format strings, locales, or currency symbols as constructor arguments and bind context-specific variants in a service provider:

$this->app->bind(EuPriceFormatter::class, fn () => new PriceFormatter(currency: 'EUR'));

Compose formatters. A UserPresenter-style formatter can depend on smaller formatters through constructor injection, so formatting rules stay in one place per concept:

class UserCardFormatter extends Formatter
{
    public function __construct(private DateFormatter $dates) {}

    public function format(User $user): array
    {
        return [
            'name'       => $user->name,
            'joined_at'  => $this->dates->format($user->created_at),
        ];
    }
}

Use CollectionFormatter for lists. Mapping a collection to presentation data is the common second use case; extending CollectionFormatter keeps the map/filter logic reusable across controllers and resources.

Keep it at the edge. Call formatters from Blade ({{ formatter(PriceFormatter::class)->format($order->total) }}), API resources, or mailables — never from model accessors that might later be used for persistence, and never from formatters you then feed back into update().

Inject, don't app(). Resolve a formatter once in a controller/service and reuse it, rather than calling the helper in a loop. For expensive formatters (money libraries, locale data), register them as singletons.

Test them like functions. Because formatters are plain classes, unit tests need no Laravel bootstrapping beyond the container: instantiate directly or resolve through app(), assert exact output, and use Carbon::setTestNow() for anything date-related. This is where the pattern pays off versus scattered number_format()/->format() calls.

Gotchas and Tips

  • Decide the null contract up front. Every formatter should answer "what do I return for null?" — an em dash, an empty string, or null. Inconsistent choices leak into Blade and API responses and are painful to normalize later.
  • Don't format in model accessors. If a formatted attribute is later read back into business logic, you get double-formatting and locale-dependent bugs. Formatting belongs at render time.
  • Locale and timezone are global state. number_format, Carbon::format, and trans() all depend on ambient configuration. Pass locale/timezone explicitly (or pin them in constructor args) so tests and queued jobs don't drift from the request context.
  • Escaping in Blade. Formatter output is not escaped; if a formatter can emit HTML, use {!! !!} deliberately, or return plain text and let Blade escape it.
  • Container resolution quirks. If your formatter has required constructor parameters, the helper/app() call will fail unless the parameters are auto-resolvable or explicitly bound. Bind contextual variants in a service provider rather than passing raw arguments everywhere.
  • Debugging output. When a value looks wrong, dump the raw value and the formatter class name — most "formatter bugs" are actually missing attributes, null relations, or a decimal stored as a string.
  • Generator/config. If the package publishes a config for the make:formatter stub path/namespace, publish it only if you want non-default locations; otherwise let the default App\Formatters convention stand.
  • Extension points are just OOP. Subclass the base Formatter, override format(), add your own abstract base with shared helpers, and bind interfaces for test doubles. There are no macros or magic hooks to learn.
  • Small ecosystem, pin the version. With ~94 stars, zero listed dependents, and a last release in November 2024, treat it as a lightweight utility you could replace in an afternoon. Pin the exact version in composer.json and keep a one-class fallback if you need long-term stability.
  • MIT license means no friction for internal and commercial use — the main risk is maintenance, not licensing.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin