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

Cpf Cnpj Laravel Package

stonkeep/cpf-cnpj

Validate, format, and generate Brazilian CPF and CNPJ documents in Laravel. Includes ready-to-use validation rules, mask and formatting helpers, and clean value objects so you can handle tax IDs consistently across your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register

composer require stonkeep/cpf-cnpj
php artisan vendor:publish --provider="Stonkeep\CpfCnpj\FieldServiceProvider" --tag=assets  # Nova 3 only

In Nova 4+ fields are plain classes — no service provider or asset publish step is needed unless the package ships custom JS you must copy. Check vendor/stonkeep/cpf-cnpj/src for a FieldServiceProvider; if it exists and is not auto-discovered, add it to config/app.php.

First use case — a "document" column that accepts either a CPF (11 digits) or CNPJ (14 digits), masks it in the UI, and stores digits only:

use Stonkeep\CpfCnpj\CpfCnpj;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Name', 'name')->rules('required'),
        CpfCnpj::make('Document', 'document')
            ->rules('required', 'max:18')
            ->help('CPF or CNPJ'),
    ];
}

Where to look first

  1. The field class itself (src/*.php) — confirm the exact make() signature, the component string, and whether it exposes mask/format helpers.
  2. resources/js/components/Field.vue (or dist/js/field.js) — this is where the masking happens, and where you find out whether it emits formatted or raw values.
  3. composer.json for the nova constraint — this tells you if it supports Nova 4/5 at all.

Before adopting, note the repo has no stars and no dependents. Read the ~100 lines of source before wiring it into a production resource; if the field is thin, copying it into app/Nova/Fields is often cheaper than owning a dependency.

Implementation Patterns

Separate storage from presentation. The single most common pattern is: mask in the UI, digits in the database.

// Model
public function setDocumentAttribute($value): void
{
    $this->attributes['document'] = preg_replace('/\D/', '', (string) $value);
}

public function getDocumentAttribute($value): string
{
    return $value; // raw digits; mask at the presentation layer
}

Then on the Nova index, format for readability:

CpfCnpj::make('Document', 'document')
    ->displayUsing(fn ($value) => $this->formatDocument($value))
    ->onlyOnIndex(),

If the field ships a ->mask() / ->formatted() fluent method, prefer it over displayUsing so index, detail, and form stay consistent.

Server-side validation is your responsibility. Nova fields are Vue components; a JS mask is not validation. Add a rule (Laravel 10+ Rule object or laravel-validation-rules/cpf-cnpj if the package doesn't ship one):

CpfCnpj::make('Document')->rules([
    'required',
    function ($attribute, $value, $fail) {
        $digits = preg_replace('/\D/', '', (string) $value);
        if (! in_array(strlen($digits), [11, 14], true) || ! $this->isValidCpfCnpj($digits)) {
            $fail('Invalid CPF/CNPJ.');
        }
    },
]),

Two-field vs one-field designs. If the package exposes distinct Cpf and Cnpj fields, model them as two nullable columns and show the right one conditionally:

Select::make('Person Type')->options(['pf' => 'Individual', 'pj' => 'Company']),
Cpf::make('CPF')->rules('required_if:person_type,pf')->hideFromIndex(),
Cnpj::make('CNPJ')->rules('required_if:person_type,pj')->hideFromIndex(),

A single polymorphic field is friendlier for data entry but pushes the pf/pj decision into your validation logic.

Uniqueness and search. ->rules('unique:customers,document') works only if you store digits consistently — a masked value in the column will silently defeat both the unique rule and Nova's ->searchable() LIKE query.

Legacy imports. Use fillUsing to normalise rows coming from spreadsheets where the value may arrive as 123.456.789-09, 12345678909, or an Excel float:

CpfCnpj::make('Document')->fillUsing(function ($request, $model, $attribute) {
    $model->{$attribute} = preg_replace('/\D/', '', (string) $request->input($attribute));
}),

Gotchas and Tips

  • Masked values leaking into the DB. Test this explicitly: create a record through the Nova UI and dd() the raw column. If the component emits 123.456.789-09, either strip it in a mutator or file a bug. This is the #1 failure mode for mask-based packages.
  • No validation on the server out of the box. Many small Nova fields ship only the Vue mask. Treat client-side formatting as cosmetic and always pair it with a Rule.
  • Leading zeros. CPFs like 01234567890 are valid. Anything that casts to int or uses (int) $value will destroy them — keep the column string/char(14) and never (int) cast.
  • Alphanumeric CNPJ. Brazil's CNPJ format gains letters starting in 2026. Most validators written before 2024 reject [A-Z0-9]{12}\d{2}, so a package that hasn't been updated will start rejecting legitimate new companies. Verify the regex in the source.
  • Nova version drift. Fields built for Nova 3 (FieldServiceProvider + Nova::script()) break on Nova 4's Vite-bundled asset pipeline. Check the composer.json constraint against your nova requirement before installing; a mismatch usually shows as a blank form field with no console error.
  • component name collisions. If two installed packages register a component named cpf-cnpj-field, one silently wins. Grep resources/js for the component string in the field class.
  • Searchable + masked = no results. ->searchable() generates WHERE document LIKE '%...%'; a user typing digits will never match a masked column. Either store digits or override searchableColumns().
  • Debugging the mask. Open Vue DevTools, select the input, and inspect the emitted input event payload — that tells you instantly what reaches the server. Alternatively Log::info($request->all()) in the resource's store path.
  • Extension points. Subclass the field and override component() or add fluent setters of your own; publish views with php artisan vendor:publish --tag=cpf-cnpj-views if templates are exposed. Because the codebase is small and unmaintained, forking the field into app/Nova/Fields (and crediting the original) removes upgrade risk entirely — for a field this small it is usually the better long-term call than pinning an abandoned dependency.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast