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

Moeda Br Laravel Package

henriquemattia/moeda-br

A Laravel package for working with Brazilian currency (BRL). Format numbers as R$, parse localized money strings, and convert amounts using simple, reusable helpers. Ideal for e-commerce, invoices, and financial dashboards, it keeps monetary values consistent across your application.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Confirm you are on Nova first. Despite the package description talking about "framework-agnostic PHP" and "parsing strings into floats", moeda-br is a Laravel Nova form field that applies a Brazilian currency input mask. If you are not running Laravel Nova (a paid license), this package has nothing to offer you — use NumberFormatter with pt_BR instead.

    composer require henriquemattia/moeda-br
    
  2. Read the source before the README. With 0 stars and a single maintainer, the entire package is likely a few hundred lines: a field class in src/ and a compiled input mask in dist/js/field.js. That dist/js file is the ground truth for what the mask actually does (decimals, minus sign, paste handling). Verify the exact class name and namespace there — the package description does not match the code.

  3. First use case: a price field on a Nova resource.

    // app/Nova/Product.php  (verify namespace in src/)
    use Henriquemattia\MoedaBr\MoedaBr;
    
    public function fields(NovaRequest $request): array
    {
        return [
            // ...
            MoedaBr::make('Preço', 'price_cents')
                ->rules('required', 'integer', 'min:0'),
        ];
    }
    
  4. Decide your storage format on day one. Nova mask fields submit the masked string ("1.234,56"), not a number. Store cents as unsignedBigInteger and convert at the model boundary — do not store "1.234,56" in a decimal column and hope.

Implementation Patterns

Wrap the field in your own class. This is the single highest-value pattern for a 0-star dependency: it lets you add rules, resolution logic, and help text in one place, and lets you swap the package out later without touching 40 resources.

namespace App\Nova\Fields;

use Henriquemattia\MoedaBr\MoedaBr;

final class BrlMoney extends MoedaBr
{
    public static function make($name, $attribute = null, $resolveCallback = null): static
    {
        return parent::make($name, $attribute, $resolveCallback)
            ->rules('required', 'integer', 'min:0', 'max:99999999999')
            ->help('Valores em reais. Use vírgula para centavos.')
            ->resolveUsing(fn ($value) => $value === null
                ? null
                : number_format($value / 100, 2, ',', '.')); // cents -> "1.234,56"
    }
}

Normalize on the way in with a model mutator (not fillUsing). The mask runs in the browser; the server receives a string like "1.234,56". Parse it once, centrally:

protected function priceCents(): Attribute
{
    return Attribute::make(
        set: function ($value) {
            if ($value === null || $value === '') {
                return null;
            }
            // "R$ 1.234,56" | "1234,56" | "1234.56" -> 123456
            $clean = preg_replace('/[^\d,\-]/', '', (string) $value);
            $clean = str_replace(',', '.', $clean);
            return (int) round(((float) $clean) * 100);
        },
    );
}

Keep formatting outside Nova duplicated deliberately. Nova fields only exist inside the admin panel. For API responses, PDFs, exports, and emails, use a shared helper rather than reaching for the package:

function brl(int $cents): string
{
    return 'R$ ' . number_format($cents / 100, 2, ',', '.');
}

Pair with a Form Request sanitizer for non-Nova entry points. If the same value can also be edited through an API or Livewire, put the parsing in prepareForValidation() so both paths share one parser — not in the field.

Test the mask boundary, not the mask. Unit-test the accessor/mutator with a data provider covering "1.234,56", "1234,56", "1234.56", "R$ 0,00", "", "-10,00", and "1.234.567,89". The browser mask is untestable in PHP; the parsing contract is what breaks in production.

Reuse across resources via one static factory. If you have invoices, products, subscriptions, and payouts all holding money, expose BrlMoney::make() everywhere so a future change (decimals, help text, rules) is one edit.

Gotchas and Tips

  • The description is wrong — trust the code. The package metadata claims a framework-agnostic currency library with R$ formatting and parsing helpers. The repository is a Nova field. Any plan built on "we'll call MoedaBr::format() from a job" will collapse. Grep src/ for public static methods before committing to an architecture.
  • Masked string vs. numeric value is the whole ballgame. Most production bugs with this kind of field are not the package — they're a decimal column being fed "1.234,56" (MySQL stores 1.23 silently, or errors depending on STRICT_MODE). Assert the stored column type and cast.
  • Empty inputs. Masks frequently submit "", "0,00", or the un-formatted value when untouched. Decide explicitly whether "no price" is null or 0 and write the test; Nova's edit form will exercise this path constantly.
  • Negative values (refunds, adjustments). Input masks often cannot produce a leading -, so a user editing a -10,00 row may see the sign silently dropped on save. Test editing a negative record; if it's broken, block negatives in validation and manage them via a separate field.
  • Paste and autofill. A user pasting R$ 1.234,56 or 1234.56 from a spreadsheet produces garbage the mask can't interpret. Defend on the server with the sanitizer above; never trust the client-side mask to produce valid input.
  • Nova version compatibility is the real risk. A Nova-only package is pinned to Nova's field API. Check the release date against the Nova major you run, and open dist/js/field.js — if it was compiled against an older Nova webpack/Vue build, it may not render at all in the panel. Smoke-test in the browser before rolling out to more than one resource.
  • Evaluate the built-in alternative first. Nova ships Currency::make('Preço')->currency('BRL'), which handles numeric storage and formatting natively. This package's only added value is the pt-BR input mask UX. If your team is comfortable typing 1234.56, you may not need a 0-star dependency at all.
  • Debugging: the server sees what the JS produced. dd($request->all()) inside a FormRequest is the fastest way to see the real submitted value. If the field "isn't saving", the problem is almost always the payload format, not the package.
  • Pin the version and insulate. Use "henriquemattia/moeda-br": "~3.2.0" and route every usage through your App\Nova\Fields\BrlMoney subclass. That way, if the package goes stale or breaks against Nova 6, you migrate to a two-line custom field instead of a refactor.
  • After Nova upgrades, republish assets. php artisan nova:publish (and a frontend build) is required for the field's compiled JS to be served; a stale public/vendor/nova is a classic "works on my machine, blank field in staging" cause.
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