Weave Code
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 Laravel Package

symfony/validator

Symfony Validator provides a flexible validation system based on the JSR-303/Bean Validation model. Define constraints via annotations/attributes, YAML/XML, or PHP, validate objects and values, and get detailed, localized violation messages.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

  1. Installation:

    composer require symfony/validator
    

    Laravel already includes this package via Symfony components, so no additional configuration is needed.

  2. First Use Case: Validate a DTO or request payload in a Laravel controller:

    use Symfony\Component\Validator\Validator\ValidatorInterface;
    
    public function store(Request $request, ValidatorInterface $validator)
    {
        $data = $request->validate([
            'email' => 'required|email',
            'age' => 'integer|min:18',
        ]);
    
        $errors = $validator->validate($data);
        if (count($errors) > 0) {
            return response()->json(['errors' => (string) $errors], 400);
        }
    
        // Proceed with valid data
    }
    
  3. Key Classes to Know:

    • ValidatorInterface: Core validator service (injected via Laravel's container).
    • Constraint: Base class for custom validation rules.
    • ConstraintValidator: Validates a specific constraint.
    • ConstraintViolationListInterface: Holds validation results.
  4. Where to Look First:

    • Symfony Validator Documentation
    • Laravel’s built-in Request::validate() (uses Symfony Validator under the hood).
    • app/Providers/AppServiceProvider.php for global validation configurations.

Implementation Patterns

1. Form Request Validation (Laravel Integration)

Leverage Laravel’s FormRequest to auto-validate with Symfony’s constraints:

use Symfony\Component\Validator\Constraints as Assert;

class StoreUserRequest extends FormRequest
{
    public function rules()
    {
        return [
            'name' => 'required|string|max:255',
            'email' => ['required', 'email', new Assert\Email()],
        ];
    }

    public function authorize()
    {
        return true;
    }

    public function validated()
    {
        $validator = app(ValidatorInterface::class);
        $errors = $validator->validate($this->all());

        if ($errors->count() > 0) {
            throw new \Illuminate\Validation\ValidationException($validator->validate($this->all()));
        }

        return parent::validated();
    }
}

2. Custom Constraints

Create reusable validation rules:

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

#[Attribute]
class ValidPassword extends Constraint
{
    public string $message = 'The password must contain at least one uppercase letter, one lowercase letter, and one number.';
}

class ValidPasswordValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        if (!preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/', $value)) {
            $this->context->buildViolation($constraint->message)
                ->addViolation();
        }
    }
}

Usage:

use App\Validator\Constraints\ValidPassword;

#[ValidPassword]
public string $password;

3. Dynamic Validation Groups

Validate different subsets of data:

$validator = app(ValidatorInterface::class);
$violations = $validator->validate($user, null, ['registration']); // Only validate 'registration' group

4. Validation in Services

Reuse validation logic across services:

class UserService
{
    public function __construct(private ValidatorInterface $validator) {}

    public function createUser(array $data): void
    {
        $violations = $this->validator->validate($data);
        if ($violations->count() > 0) {
            throw new \RuntimeException((string) $violations);
        }
        // Save user
    }
}

5. API Response Handling

Format validation errors for JSON APIs:

$errors = $validator->validate($data);
return response()->json([
    'errors' => collect($errors)->map(fn ($error) => $error->getPropertyPath() . ': ' . $error->getMessage())
]);

6. Laravel Service Provider Configuration

Extend Symfony’s validator in AppServiceProvider:

public function register()
{
    $this->app->extend(ValidatorInterface::class, function ($validator) {
        $validator->setMappingCacheDir(storage_path('framework/cache/validator'));
        return $validator;
    });
}

Gotchas and Tips

Pitfalls

  1. Circular References in Validation:

    • Avoid validating deeply nested objects with circular references (e.g., User->posts->author->user). Use @Assert\Valid sparingly or disable it for specific properties.
  2. Performance with Large Datasets:

    • Symfony Validator caches metadata by default (cache_dir in config). For dynamic validation rules, disable caching or use ValidatorBuilder to rebuild the validator:
      $validator = ValidatorBuilder::create()
          ->enableAnnotationMapping()
          ->getValidator();
      
  3. Constraint Overrides:

    • Extending constraints (e.g., #[Assert\Length(min: 5)]) may not work as expected if the parent constraint’s options aren’t properly inherited. Use #[Assert\Callback] for complex logic:
      #[Assert\Callback]
      public function validate($value, ExecutionContextInterface $context)
      {
          if (!str_contains($value, 'laravel')) {
              $context->buildViolation('Must contain "laravel".')
                  ->addViolation();
          }
      }
      
  4. Validation Groups in Laravel:

    • Laravel’s FormRequest doesn’t natively support Symfony’s validation groups. Use a custom validator or manually pass groups:
      $validator = app(ValidatorInterface::class);
      $validator->validate($data, null, ['group1', 'group2']);
      
  5. Expression Language Quirks:

    • The Expression constraint (@Assert\Expression) requires the symfony/expression-language component. Install it separately:
      composer require symfony/expression-language
      
    • Example:
      #[Assert\Expression(
          expression: "this.getAge() >= 18",
          message: "You must be at least 18 years old."
      )]
      
  6. Type Safety:

    • Symfony Validator infers types loosely. For strict typing, use #[Assert\Type(type: 'string')] or #[Assert\Type(type: 'array')].

Debugging Tips

  1. Inspect Violations:

    $violations = $validator->validate($data);
    foreach ($violations as $violation) {
        dump([
            'property' => $violation->getPropertyPath(),
            'message' => $violation->getMessage(),
            'code' => $violation->getCode(),
        ]);
    }
    
  2. Enable Validation Tracing:

    • Set framework.validation.traceable to true in Laravel’s config/services.php to log validation calls.
  3. Constraint Dumping:

    • Use php artisan vendor:publish --tag=validator to publish Symfony’s constraint templates (e.g., YAML/XML mappings).
  4. Common Error Codes:

    • SYMFONY\Component\Validator\Constraints\Length: Use min/max in error messages:
      #[Assert\Length(
          min: 5,
          minMessage: 'This value should be at least {{ limit }} characters long.',
          max: 20,
          maxMessage: 'This value should be at most {{ limit }} characters long.'
      )]
      

Extension Points

  1. Custom Constraint Validators:

    • Implement ConstraintValidatorInterface for complex rules:
      class CustomValidator extends AbstractConstraintValidator
      {
          public function validate($value, Constraint $constraint)
          {
              if ($value !== $constraint->expected) {
                  $this->context->buildViolation($constraint->message)
                      ->setParameter('{{ value }}', $value)
                      ->addViolation();
              }
          }
      }
      
  2. Validation Event Listeners:

    • Subscribe to validation events via Symfony’s event dispatcher (available in Laravel):
      $dispatcher = app(\Symfony\Component\EventDispatcher\EventDispatcherInterface::class);
      $dispatcher->addListener(ConstraintViolationListEvent::class, function ($event) {
          // Log violations or modify them
      });
      
  3. Override Default Constraints:

    • Replace built-in constraints (e.g., Email) by binding a custom validator in Laravel’s service container:
      $this->app->bind(EmailValidator::class, function () {
          return new CustomEmailValidator();
      });
      
  4. Validation in Tests:

    • Use ValidatorInterface in PHPUnit tests:
      public function testValidation()
      {
          $validator = $this->app->make(ValidatorInterface::class);
          $violations = $validator->validate(['email' => 'invalid']);
          $this->assertCount(1, $violations);
      }
      
  5. Laravel Policy Integration:

    • Combine Symfony Validator with Laravel Policies for authorization:
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi