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

Validator Bundle Laravel Package

assoconnect/validator-bundle

Symfony bundle providing validators for common scalar values: email addresses, phone numbers, latitude and longitude, monetary amounts, timezones, and French RNA, SIREN, and SIRET identifiers.

View on GitHub
Deep Wiki
Context7

Getting Started

Frame it correctly first. assoconnect/validator-bundle is a Symfony bundle, not a Laravel package. There is no ValidationServiceProvider, no Rule objects, no config/validator.php to publish. What you actually get is ~15 pairs of Constraint + ConstraintValidator classes built against symfony/validator's ConstraintValidatorInterface. In a Laravel app you have two honest options: run symfony/validator standalone and bridge violations into Laravel's MessageBag, or extract the validator logic into your own Illuminate\Contracts\Validation\ValidationRule classes under MIT. Day-to-day, the second is what most teams end up doing.

Install and version floor. Composer is straightforward, but the compatibility band is narrow:

composer require assoconnect/validator-bundle

Recent tags require PHP 8.4 and Symfony 7 only (Symfony 5.4 dropped in v2.32, Symfony 6 dropped in v2.39). If your Laravel app is on PHP 8.2/8.3, you are pinned to an older tag or excluded entirely. Confirm the tag before you plan anything else. symfony/validator and giggsey/libphonenumber-for-php (~9.0) come along transitively.

Where to look first. Skip the doc index for anything non-obvious and read src/Validator/Constraints/*Validator.php directly — the README explicitly delegates options to the source. The *Validator.php file tells you the real contract (what types it accepts, whether it throws on null, which library it wraps); the sibling *Constraint.php tells you the constructor options and the default message.

First use case. The highest-value, lowest-risk entry point is a single Laravel rule wrapping one constraint — typically SIRET for a French B2B onboarding form, or phone normalisation:

final class SiretRule implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (!is_string($value) || $value === '') {
            return; // let `required` decide emptiness
        }

        $constraint = new Siret();
        $validator  = new SiretValidator();

        if (!$validator->validate($value, $constraint)) {
            $fail('validation.siret')->translate();
        }
    }
}

That is the whole onboarding cost for one constraint. Expand from there only for identifiers you genuinely handle.

Implementation Patterns

Rule adapter per constraint (the default). One class per constraint, in app/Validation/Rules/, each holding a memoised constraint instance. Wire them into FormRequests exactly like built-in rules:

'company.siret' => ['required', 'string', new SiretRule()],
'contact.phone' => ['required', 'string', new PhoneRule()],
'venue.lat'     => ['required', 'numeric', new LatitudeRule()],

The adapter owns three responsibilities: guard the input type before delegating, translate the failure into a key, and never let a \Throwable from the underlying library escape as a 500.

Standalone Symfony validator bridge. When you need to validate a populated DTO or a whole array at once (import jobs, API payloads), build a Validator once and translate the ConstraintViolationList into Laravel's error bag:

$validator = Validation::createValidator();
$violations = $validator->validate($dto, [
    new Siret(propertyPath: 'siret'),
    new EuropeanVatNumber(propertyPath: 'vat'),
]);

if (count($violations) > 0) {
    throw ValidationException::withMessages(
        (new ConstraintViolationListAdapter($violations))->toArray()
    );
}

Keep this in one service and inject it — constructing validators per request is wasted work.

Normalise before you validate. These validators check formats; they do not clean input. Strip spaces and dots from SIRET/SIREN, convert 06 12 34 56 78 to E.164, and trim VAT prefixes before the rule runs. A prepareForValidation() hook on the FormRequest is the right place. Validating unnormalised user input is the single most common source of false negatives with this bundle.

Value objects for repeated identifiers. If SIRET or phone appears on five models, move validation into a small VO that throws on construction and let the rule simply attempt construction. You get one place to fix and the constraint logic stops leaking into controllers.

Composite rules for real business entities. A French company record needs SIRET and possibly EU VAT to agree. Compose your rules in a CompanyIdentifierRule rather than listing them in every FormRequest — the cross-field checks (does the VAT country match the SIRET country?) are the part worth sharing.

Batch/import workflow. For CSV imports, run the Symfony validator over mapped DTOs and collect violations per row instead of aborting on the first failure. These validators are stateless and cheap, so you can validate thousands of rows without pooling concerns — the cost is dominated by libphonenumber metadata loading, which you pay once.

Gotchas and Tips

It is a Symfony bundle — do not drag in the framework. Adding symfony/framework-bundle just to satisfy a DI extension pulls a second kernel into your app. You only need symfony/validator; the bundle's DI wiring is irrelevant to Laravel. If you ever find yourself registering a Bundle class, stop.

Version drift is the main long-term risk. The package tracks the newest PHP and Symfony closely and drops old support in minor releases. Pin it in composer.json with a caret on a known-good minor and treat every bump as a code change requiring a test run — especially for phone.

The phone dependency moved a major version in a patch release. giggsey/libphonenumber-for-php went ^8.13 → ^9.0 in v2.42.2. Phone parsing semantics and metadata can shift under you without a composer conflict. Pin the phone library explicitly and keep a fixture suite of real numbers (including the ones you've historically rejected) to catch regressions.

Null and empty input are not uniformly handled. Some validators return false, some throw UnexpectedValueException, some short-circuit. Read each validate() signature. Your adapter must guard is_string() / null before delegating, or you will ship 500s on optional fields.

Constraint constructors assert. They use webmozart/assert, so invalid configuration fails loudly at construction time. Good for fail-fast, bad if you build constraints from user-controlled option arrays. Memoise constraint instances in your rule classes rather than new-ing them per call.

Translations do not come with it. The bundle ships en/fr/es catalogues under Symfony's translator domain — Laravel will not read them. Return your own translation keys from the rule and add the strings to lang/. The constraint's message property is a good source for wording, not for runtime output.

Check what you're duplicating. Laravel already validates email, timezone, and numeric ranges well. Pulling in the bundle's email/timezone/lat-long constraints adds a dependency for something you already have. The genuine differentiators are the French RNA/SIREN/SIRET, Belgian enterprise number, NIF, EU VAT, and the libphonenumber-backed phone validator.

Regional ceiling. Roughly half the constraints are francophone/Benelux/Iberian. If those identifiers aren't in your 24-month roadmap, you're carrying a dependency for five scalar checks.

Debugging. When a value unexpectedly passes or fails, instantiate the validator in php artisan tinker, call validate() with a fresh constraint, and read the class source alongside it — there is no bundle-level logging or debug mode to lean on. For phone specifically, test against the raw libphonenumber API to see whether the failure is the bundle's logic or the underlying metadata.

Fork deliberately, not accidentally. MIT means extraction is legal and cheap; maintenance is not. If you go the port route, vendor the constraint classes into app/Support/Validation/ with the license header, keep the upstream commit SHA in a comment, and add a test per constraint. That is a two-hour job for the five constraints you actually use, and it removes the PHP/Symfony version gate permanently — which, for a Laravel shop, is usually the deciding factor.

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.
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table