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

Symfony Validation Enhancements Bundle Laravel Package

michaelcozzolino/symfony-validation-enhancements-bundle

A Symfony bundle that enhances the Validator component with additional validation features and constraints. Integrates quickly into existing Symfony applications to simplify common validation scenarios and keep validation logic reusable and configuration-driven.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a native Laravel package — v1.0.0 is its first stable release, so treat it as "usable but young." In a Laravel codebase you'll consume the underlying constraints/validators rather than the bundle wiring.

  1. Install: composer require michaelcozzolino/symfony-validation-enhancements-bundle
  2. Look first at src/Validator/Constraints/ and src/Validator/ — EntityExistsValidator is the headline feature and the only piece with real day-to-day value for a Laravel dev.
  3. Read README.md and docs/ (added in PR #12) for the renamed rule names — v1.0.0 changed them, so any snippet you find from v0.2.0 or blog posts will be wrong.
  4. First use case: replacing a hand-rolled repository lookup in a FormRequest with a declarative "does this entity exist / not exist" check.
use MichaelCozzolino\Validation\Constraints\EntityExists;

// exists check (mirrors Laravel's `exists` rule, but backed by your Doctrine/entity layer)
new EntityExists(['entity' => User::class, 'field' => 'email']);

Implementation Patterns

FormRequest wrapper. Keep the Symfony constraint out of your controllers and wrap it in a Laravel Rule object so your validation stays idiomatic:

class EntityExistsRule implements ValidationRule
{
    public function __construct(
        private string $entity,
        private string $field,
        private bool $mustNotExist = false,
    ) {}

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $constraint = new EntityExists([
            'entity' => $this->entity,
            'field'  => $this->field,
            'mustNotExist' => $this->mustNotExist,
        ]);

        $violations = app(ValidatorInterface::class)->validate($value, $constraint);

        if (count($violations) > 0) {
            $fail($violations[0]->getMessage());
        }
    }
}

Check the constraint's actual option key for the non-existence mode (PR #14) — it may be mustNotExist, notExists, or a separate constraint class; confirm against the renamed rules list before shipping.

Registration rule (Symfony only). If you're bridging into a Symfony app, register the bundle in config/bundles.php and make sure doctrine/orm (or whichever entity layer the validator queries) is available in the container — the validator resolves entities through a service, not static calls.

Error listener for API responses. The new validation error listener is the second real feature: it normalizes validation failures into a consistent payload. Use it when you want one JSON error shape across every endpoint, rather than per-controller ValidationException formatting. In Laravel you'd typically do this via App\Exceptions\Handler + ValidationException::errors(); adopt the listener only if you need the exact Symfony-shaped output (e.g., a shared API consumed by a Symfony frontend).

Reuse across requests. Cache constraint instances per entity/field pair — building a constraint per attribute per request is cheap, but the entity metadata lookup it triggers is not always memoized. A small EntityExistsRule::for(User::class, 'email') factory keeps call sites readable:

'email' => ['required', 'email', EntityExistsRule::for(User::class, 'email')],

Test with Pest. The package converted its own suite to Pest in v1.0.0, so its test files are the best documentation of intended behavior — including edge cases for the non-existence mode. Mirror those cases in your app tests.

Gotchas and Tips

  • Rule names changed in v1.0.0. PR #11 ("update validation rules names") plus the 1.0.0 bump means this is effectively a rename release. Grep your codebase for the old string names before upgrading; nothing here looks like it kept BC aliases.
  • Symfony-first design. The constraints assume Symfony's ValidatorInterface and error-listener plumbing. In Laravel you're importing a Symfony component graph — expect symfony/validator and symfony/http-kernel transitively. Audit composer.lock for framework version conflicts (Laravel 10/11 pin different Symfony majors).
  • Non-existence validation is not the same as unique. "The entity must not exist" checks a single field by value. It will not respect soft deletes, tenancy scopes, or global query scopes unless the validator's repository lookup does — verify against your SoftDeletes models, where a "non-existent" email may still be a deleted row that blocks re-registration.
  • Error listener scope. A global validation listener can hijack error rendering you already handle (Inertia redirects with errors, back()->withErrors()). Scope it to API routes / Accept: application/json requests, or skip it in favor of Laravel's native ValidationException handling.
  • Query cost. Each EntityExists is a SELECT 1 (or worse, a hydrated fetch). On bulk imports or array validation with * wildcards this multiplies fast — batch pre-check with a single whereIn query and fall back to the rule for single-field validation.
  • Index the column. Existence checks on unindexed fields are the most common performance regression from adopting this; ensure the target field has a unique or standard index.
  • Null / empty handling. Confirm how the validator treats null and '' before combining it with nullable — a naive constraint will fire a query on empty input and report "not found" style errors instead of letting nullable short-circuit.
  • Extension points. The validator is DI-driven, so it's swappable in a service provider if you need custom entity resolution (e.g., resolving through a repository interface rather than an EntityManager). Bind your repository into the container and alias it before the bundle's default if you go this route.
  • Stability. v1.0.0 with PHPStan adoption (PR #9) and Pest tests (PR #10) suggests typed, verified code, but the public API surface is still one release deep — pin the version and read CHANGELOG before minor bumps.
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.
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
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox