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

Eori Laravel Package

slimad/eori

A Laravel package for working with EORI numbers, the EU customs identifier for traders. It provides validation rules, normalization, and country-prefix checks so you can verify economic operator IDs in forms, imports, and API requests with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package through Composer; Laravel's package auto-discovery should register the service provider (verify the extra.laravel.providers block in the package's composer.json):

composer require slimad/eori

Where to look first

  1. composer.json — confirm the service provider is registered and note the PHP/Laravel constraints.
  2. src/ — find the actual validator class. For a package of this size it is almost certainly one of two shapes: a Rule object (implements ValidationRule) or a Validator::extend call exposing a string alias like eori. That distinction drives how you call it.
  3. tests/ — the fixtures here are your best source of truth for accepted/rejected formats, country prefixes, and length boundaries.
  4. README.md — the single usage example is usually accurate for a tiny package.

First use case

A registration or checkout form where a business customer enters an EORI number for customs/shipping. The minimum viable integration is a FormRequest:

use Illuminate\Foundation\Http\FormRequest;

class CompanyRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'eori' => ['required', 'string', 'eori'], // or: new \Slimad\Eori\Rules\Eori()
        ];
    }

    protected function prepareForValidation(): void
    {
        $this->merge([
            'eori' => strtoupper(trim((string) $this->input('eori'))),
        ]);
    }
}

Start there, then widen the rule set with nullable/sometimes if EORI is optional for non-EU operators.

Implementation Patterns

FormRequest is the default home. Keep the rule in the request, not the controller, so the message and the normalization live together and are testable through $this->post(...).

Inline validation for smaller endpoints

$validated = $request->validate([
    'eori' => ['required', 'eori'],
]);

Rule objects compose better. If the package exposes a Rule class, instantiate it — you can then chain it with bail, exclude_if, and Rule::when() without fighting string-alias parsing:

use Illuminate\Validation\Rule;

'eori' => [
    'bail',
    Rule::requiredIf(fn () => $request->user()->is_eu_operator),
    new \Slimad\Eori\Rules\Eori(),
],

Conditional / partial forms. EORI is rarely mandatory for everyone. Use sometimes + required_if for the EU case and let the EORI rule handle format only:

'eori' => [
    'sometimes',
    'required_if:country,in:AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE',
    'nullable',
    'eori',
],

(Keep that country list in a config file or enum — inlining it in every request rots fast.)

Normalize before validating. EORI numbers are uppercase alphanumeric with a two-letter ISO country prefix. Users paste them with spaces, hyphens, and lowercase. Handle this once in prepareForValidation() or a EoriNumber cast/value object:

$normalized = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', $input));

If you normalize in prepareForValidation, always validate the normalized value; otherwise the DB gets a different string than the one you validated.

Custom error message. Override in the request's messages() (or your lang file) so the user-facing copy explains what an EORI number is:

public function messages(): array
{
    return [
        'eori.eori' => 'Enter the EORI number exactly as registered with your customs authority (e.g., FR12345678901234).',
    ];
}

Store it as a dedicated column, uppercase, fixed length. char(17) or varchar(17) (2-letter prefix + up to 15 chars) with a unique index if one business can only register once. If you use a value object, implement CastsAttributes so the cast normalizes on set() and get().

Testing pattern. Data providers are the right tool; assert both the valid fixture and a rejected fixture so a package upgrade that loosens the rule doesn't silently pass:

public function test_eori_validation(): void
{
    $this->post('/companies', ['eori' => 'FR12345678901234'])
        ->assertSessionHasNoErrors();

    $this->post('/companies', ['eori' => 'not-an-eori'])
        ->assertSessionHasErrors('eori');
}

Integration tip — external registry checks. Format validation is not existence validation. If a bad EORI number has business consequences (customs rejection, invoice disputes), treat this package as the cheap pre-filter and add your own verification against the EU EORI registry behind a queued job or a separate, rate-limited service class. Don't make the web request depend on an external API.

Gotchas and Tips

Format ≠ existence. The single most important distinction. An EORI number can be syntactically valid, have a real ISO country prefix, and still not exist. If your workflow requires certainty, this package is step one of two.

Country prefix must be a real ISO country code. The EU plus GB (post-Brexit) and a handful of others have EORI schemes. If the rule accepts any two letters, you can get false positives — add Rule::in([...]) on a separate country field and cross-check that the EORI prefix matches it.

Case sensitivity. EORI numbers are conventionally uppercase. If the package treats fr123... as invalid, that's correct behavior but a frequent user complaint — normalize before validation so you're not telling users their number is wrong when it's just lowercase.

Whitespace and separators. Most EORI inputs arrive pasted from a registration letter or PDF, usually with spaces. Never rely on trim(), which won't catch internal spaces or non-breaking spaces (\u{00A0}). Strip with a regex character class.

No checksum. Unlike VAT numbers or IBANs, EORI has no checksum — there is no mathematical way to self-verify, which is why format-only packages exist and why "valid" here means "well-formed," not "real." Set that expectation with your stakeholders and in the field's helper text.

Zero dependents / single maintainer. Pin the version in composer.json ("slimad/eori": "^1.0", not *) and keep a thin app-level wrapper (a Eori rule of your own delegating to the package) so swapping it out later is a one-file change. This is the pragmatic hedge for any tiny validator package.

Debugging a failing assertion. When a value unexpectedly fails, dump the input after normalization and compare against the package's test fixtures. The three usual causes: lowercase input, a trailing newline from a textarea, or a country prefix the package's pattern doesn't include. If you can't tell, write a five-line scratch test that calls Validator::make(['e' => $x], ['e' => 'eori'])->passes() and iterate.

Config publishing. If the package ships a config (country list, strictness flag), run php artisan vendor:publish --tag=eori-config and commit the published file. Relying on package defaults means a minor version bump can change validation behavior out from under production without a diff review.

Extension point. The cleanest upgrade path for custom logic — "must match the operator's country," "reject sanctioned regions," "verify against registry" — is your own Rule class that wraps this one, rather than editing vendored files or layering five string rules onto the field.

Migration ordering. If you add EORI as required on an existing form, existing rows will have null. Backfill with nullable first, deploy, then tighten the validation rule — a straight jump to required breaks every edit form that touches a legacy record.

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.
skyraptor/chatter
edlugz/sasapay
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