Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save graste/2e0c83e3d33313c590de1c81fed1da77 to your computer and use it in GitHub Desktop.
Save graste/2e0c83e3d33313c590de1c81fed1da77 to your computer and use it in GitHub Desktop.
<?php
namespace App\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
final class ValidatorRequestListener implements EventSubscriberInterface
{
private ValidatorInterface $validator;
public function __construct(ValidatorInterface $validator)
{
$this->validator = $validator;
}
public function onKernelRequest(RequestEvent $event = null)
{
/** @var Request $request */
$request = $event->getRequest();
// we fetch the validator
$validator = $request->get('_validator');
// Early return if we don't have defined a Validator or
// the method is not a POST,PUT or GET.
if (null === $validator || !in_array($request->getMethod(), ['POST', 'PUT', 'GET'])) {
return;
}
// We create a collection of constraint(s) with the constraints given in the defaults Route option.
$collection = [];
foreach ($validator as $propertyToValidate => $constraintName) {
// Hack to dynamically create the constraint
// ⚠️ My case is simple, I just have 1 constraint per property
// if you have an array of constraints for a property, you need to iterate on them
$fqcn = "Symfony\Component\Validator\Constraints\\${constraintName}";
$constraint = new $fqcn;
if (!$constraint instanceof Constraint) {
throw new \LogicException("Only Constraint are allowed to validate value");
}
$collection[$propertyToValidate] = new $constraint;
}
// If method is POST or PUT, we should get the payload from the request content
// otherwise we get it from query string
if (in_array($request->getMethod(), ['POST', 'PUT'])) {
$payload = \json_decode($request->getContent(), true);
} else {
// Retrieve the input from the query string.
$payload = $request->query->all();
}
// We remove properties that should not have to be validated
$input = array_intersect_key($payload, $collection);
$errors = $this->validator->validate($input, new Constraints\Collection($collection));
// We set errors in a key "_errors" that can be retrieve from
// the request object with $request->attributes->get('_errors');
$request->attributes->set('_errors', $errors);
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['onKernelRequest', 31]],
];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment