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

Symfony Request Validation Laravel Package

digitalrevolution/symfony-request-validation

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require digitalrevolution/symfony-request-validation
    

    Register the bundle in config/bundles.php:

    DigitalRevolution\SymfonyRequestValidation\Bundle\RequestValidationBundle::class => ['all' => true],
    
  2. First Use Case: Create a request class extending AbstractValidatedRequest and define validation rules:

    use DigitalRevolution\SymfonyRequestValidation\AbstractValidatedRequest;
    use DigitalRevolution\SymfonyRequestValidation\ValidationRules;
    
    class CreateUserRequest extends AbstractValidatedRequest
    {
        protected function getValidationRules(): array
        {
            return [
                ValidationRules::string('name')->required()->maxLength(50),
                ValidationRules::email('email')->required(),
                ValidationRules::numeric('age')->min(18)->max(120),
            ];
        }
    }
    
  3. Register as Service: Tag the request class as a service in services.yaml:

    services:
        App\Request\CreateUserRequest:
            tags: ['request_validation.request']
    
  4. Inject and Validate:

    use Symfony\Component\HttpFoundation\RequestStack;
    
    class UserController
    {
        public function __construct(
            private RequestStack $requestStack,
            private CreateUserRequest $createUserRequest
        ) {}
    
        public function create(Request $request): Response
        {
            $this->createUserRequest->validate($request);
            // Proceed with validated data
        }
    }
    

Implementation Patterns

Common Workflows

  1. Request Validation in Controllers:

    public function update(Request $request, UpdateUserRequest $updateRequest): Response
    {
        $updateRequest->validate($request);
        $data = $updateRequest->getValidatedData();
        // Use $data directly
    }
    
  2. Reusable Validation Logic: Create base request classes for shared validation:

    class BaseUserRequest extends AbstractValidatedRequest
    {
        protected function getValidationRules(): array
        {
            return [
                ValidationRules::string('name')->required(),
                ValidationRules::email('email')->required(),
            ];
        }
    }
    

    Extend for specific use cases:

    class UpdateUserRequest extends BaseUserRequest
    {
        protected function getValidationRules(): array
        {
            return array_merge(parent::getValidationRules(), [
                ValidationRules::numeric('age')->min(18),
            ]);
        }
    }
    
  3. Custom Error Handling: Override handleValidationErrors() in your request class:

    protected function handleValidationErrors(ConstraintViolationListInterface $errors): void
    {
        throw new HttpException(400, json_encode($errors));
    }
    
  4. Dynamic Rule Generation: Use closures for conditional rules:

    protected function getValidationRules(): array
    {
        return [
            ValidationRules::string('password')->required()->when(
                fn() => $this->get('action') === 'create',
                fn($rule) => $rule->minLength(8)
            ),
        ];
    }
    
  5. Integration with Symfony Forms: Use validated data directly in form factories:

    public function create(Request $request, CreateUserRequest $createRequest): Response
    {
        $createRequest->validate($request);
        $form = $this->createForm(UserType::class, $createRequest->getValidatedData());
    }
    

Gotchas and Tips

Pitfalls

  1. Service Registration:

    • Forgetting to tag the request class as a service will result in ServiceNotFoundException.
    • Fix: Ensure tags: ['request_validation.request'] is present in services.yaml.
  2. Circular Dependencies:

    • Injecting the request class directly into another request class (e.g., CreateUserRequest injecting UpdateUserRequest) causes circular references.
    • Fix: Use constructor injection sparingly; prefer passing raw Request objects or validated data.
  3. Rule Overrides:

    • Extending validation rules in child classes may unintentionally override parent rules if not merged properly.
    • Fix: Use array_merge() to combine rules:
      return array_merge(parent::getValidationRules(), [...]);
      
  4. Performance with Large Payloads:

    • Validating deeply nested arrays or large payloads can be slow.
    • Fix: Use ValidationRules::skip() for non-critical fields:
      ValidationRules::skip('metadata.non_critical_field')
      
  5. Symfony Cache Invalidation:

    • Changes to validation rules require cache clearing if using Symfony’s cache system.
    • Fix: Run php bin/console cache:clear after updating rules.

Debugging Tips

  1. Validation Errors:

    • Use dd($this->getValidationErrors()) to inspect raw errors during development.
  2. Rule Debugging:

    • Enable Symfony’s validation debug mode in config/packages/validator.yaml:
      validator:
          debug: true
      
  3. Logging:

    • Log validation failures for debugging:
      protected function handleValidationErrors(ConstraintViolationListInterface $errors): void
      {
          $this->logger->error('Validation failed', ['errors' => $errors]);
          throw new HttpException(400, 'Validation failed');
      }
      

Extension Points

  1. Custom Validators:

    • Extend the package by creating custom validation rules:
      use Symfony\Component\Validator\Constraint;
      
      class CustomConstraint extends Constraint
      {
          public $message = 'This value is invalid.';
      }
      
    • Register the constraint in services.yaml:
      services:
          App\Validator\Constraints\CustomConstraint:
              tags: [validator.constraint]
      
  2. Event Listeners:

    • Listen to validation events (e.g., RequestValidationEvent):
      use DigitalRevolution\SymfonyRequestValidation\Event\RequestValidationEvent;
      use Symfony\Component\EventDispatcher\EventSubscriberInterface;
      
      class ValidationSubscriber implements EventSubscriberInterface
      {
          public static function getSubscribedEvents(): array
          {
              return [
                  RequestValidationEvent::VALIDATION_FAILED => 'onValidationFailed',
              ];
          }
      
          public function onValidationFailed(RequestValidationEvent $event): void
          {
              // Custom logic
          }
      }
      
  3. Custom Error Formats:

    • Override formatErrors() to change the error response format:
      protected function formatErrors(ConstraintViolationListInterface $errors): array
      {
          return array_map(fn($error) => [
              'field' => $error->getPropertyPath(),
              'message' => $error->getMessage(),
          ], iterator_to_array($errors));
      }
      
  4. Integration with API Platform:

    • Use validated requests in API Platform’s denormalize() methods:
      public function denormalize($data, string $type, array $context = []): User
      {
          $request = new CreateUserRequest();
          $request->validate(new Request([], [], [], [], [], ['json' => $data]));
          return new User($request->getValidatedData());
      }
      
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor