diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.php index c397e73d4250..6eaafb704afd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.php @@ -19,6 +19,7 @@ use Symfony\Component\Validator\Constraints\NotCompromisedPasswordValidator; use Symfony\Component\Validator\Constraints\WhenValidator; use Symfony\Component\Validator\ContainerConstraintValidatorFactory; +use Symfony\Component\Validator\EventListener\RequestValidationSubscriber; use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader; use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -109,5 +110,12 @@ service('property_info'), ]) ->tag('validator.auto_mapper') + + ->set('validator.request_validator', RequestValidationSubscriber::class) + ->args([ + service('validator'), + service('serializer')->nullOnInvalid(), + ]) + ->tag('kernel.event_subscriber') ; }; diff --git a/src/Symfony/Component/Validator/Attribute/RequestValidator.php b/src/Symfony/Component/Validator/Attribute/RequestValidator.php new file mode 100644 index 000000000000..d94979286317 --- /dev/null +++ b/src/Symfony/Component/Validator/Attribute/RequestValidator.php @@ -0,0 +1,24 @@ + 'validateRequest' + ]; + } + + public function validateRequest(ControllerArgumentsEvent $event): void { + $controller = $event->getController(); + $arguments = $event->getArguments(); + $reflectionMethod = $this->getReflectionMethod($controller); + $request = $event->getRequest(); + + $attributes = $reflectionMethod->getAttributes(RequestValidator::class, \ReflectionAttribute::IS_INSTANCEOF); + + if (count($attributes) === 0) { + return; + } + + // only first attribute can validate + $attribute = $attributes[0]; + + $attributeArguments = $attribute->getArguments(); + if(key_exists('class', $attributeArguments)) { + $class = $attributeArguments['class']; + $override = key_exists('override', $attributeArguments) ? $attributeArguments['override'] : true; + $order = key_exists('order', $attributeArguments) ? $attributeArguments['order'] : [ + RequestValidator::ORDER_ATTRIBUTES, + RequestValidator::ORDER_QUERY, + RequestValidator::ORDER_REQUEST, + ]; + $serializedFormat = key_exists('serializedFormat', $attributeArguments) ? $attributeArguments['json'] : 'json'; + }else { + $class = $attributeArguments[0]; + $override = key_exists(1, $attributeArguments) ? $attributeArguments[1] : true; + $order = key_exists(2, $attributeArguments) ? $attributeArguments[2] : [ + RequestValidator::ORDER_ATTRIBUTES, + RequestValidator::ORDER_QUERY, + RequestValidator::ORDER_REQUEST, + ]; + $serializedFormat = key_exists(3, $attributeArguments) ? $attributeArguments[3] : 'json'; + } + + $object = new $class(); + + foreach ($order as $type) { + switch ($type) { + case RequestValidator::ORDER_SERIALIZE: + if(empty($request->getContent())) { + continue 2; + } + $serializer = $this->getSerializer(); + $serializer->deserialize($request->getContent(), $class, $serializedFormat, + [AbstractNormalizer::OBJECT_TO_POPULATE => $object]); + continue 2; + case RequestValidator::ORDER_REQUEST: + $this->setProperties($object, $request->request->all(), $override); + break; + case RequestValidator::ORDER_QUERY: + $this->setProperties($object, $request->query->all(), $override); + break; + case RequestValidator::ORDER_ATTRIBUTES: + $this->setProperties($object, $request->attributes->all(), $override); + break; + } + + } + + $violations = $this->validator->validate($object); + + if(count($violations) > 0) { + throw new ValidationFailedException(sprintf("Validation of %s failed!", $class), $violations); + } + + foreach ($arguments as $index => $argument) { + if(!$argument instanceof $class) { + continue; + } + $arguments[$index] = $object; + } + + $event->setArguments($arguments); + } + + private function setProperties(object $object, array $parameters, bool $override) { + foreach ($parameters as $key => $value) { + if(false === $override && property_exists($object, $key) && isset($object->{$key})) { + continue; + } + $object->{$key} = $value; + } + } + + private function getReflectionMethod(callable $controller): \ReflectionMethod + { + if (is_array($controller)) { + $class = $controller[0]; + $method = $controller[1]; + } else { + /** @var object $controller */ + $class = $controller; + $method = '__invoke'; + } + + return new \ReflectionMethod($class, $method); + } + + private function getSerializer(): SerializerInterface + { + if (!class_exists(Serializer::class)) { + throw new LogicException(sprintf('The "symfony/serializer" component is required to use the "%s" validator. Try running "composer require symfony/serializer".', + __CLASS__)); + } + + return $this->serializer; + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy