vendor/gollumsf/rest-bundle/src/EventSubscriber/SerializerSubscriber.php line 118

Open in your IDE?
  1. <?php
  2. namespace GollumSF\RestBundle\EventSubscriber;
  3. use Doctrine\Persistence\ManagerRegistry;
  4. use GollumSF\RestBundle\Annotation\Serialize;
  5. use GollumSF\RestBundle\Annotation\Unserialize;
  6. use GollumSF\RestBundle\Annotation\Validate;
  7. use GollumSF\RestBundle\Exceptions\UnserializeValidateException;
  8. use GollumSF\RestBundle\Serializer\Transform\SerializerTransformInterface;
  9. use GollumSF\RestBundle\Serializer\Transform\UnserializerTransformInterface;
  10. use GollumSF\RestBundle\Traits\ManagerRegistryToManager;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
  15. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  16. use Symfony\Component\HttpKernel\Event\ViewEvent;
  17. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  18. use Symfony\Component\HttpKernel\KernelEvents;
  19. use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
  20. use Symfony\Component\Serializer\Exception\NotEncodableValueException;
  21. use Symfony\Component\Serializer\SerializerInterface;
  22. use Symfony\Component\Validator\Validator\ValidatorInterface;
  23. class SerializerSubscriber implements EventSubscriberInterface {
  24.     
  25.     use ManagerRegistryToManager;
  26.     
  27.     /**
  28.      * @var SerializerInterface
  29.      */
  30.     private $serializer;
  31.     /**
  32.      * @var ManagerRegistry
  33.      */
  34.     private $managerRegistry;
  35.     /**
  36.      * @var ValidatorInterface
  37.      */
  38.     private $validator;
  39.     
  40.     public static function getSubscribedEvents() {
  41.         return [
  42.             KernelEvents::CONTROLLER_ARGUMENTS => [
  43.                 ['onKernelControllerArguments', -10],
  44.             ],
  45.             KernelEvents::VIEW => [
  46.                 ['onKernelView', -10],
  47.             ],
  48.             KernelEvents::EXCEPTION => [
  49.                 ['onKernelValidateException'257],
  50.             ],
  51.         ];
  52.     }
  53.     
  54.     public function __construct(
  55.         SerializerInterface $serializer
  56.     ) {
  57.         $this->serializer $serializer;
  58.     }
  59.     public function setManagerRegistry(ManagerRegistry $managerRegistry): self {
  60.         $this->managerRegistry $managerRegistry;
  61.         return $this;
  62.     }
  63.     public function setValidator(ValidatorInterface $validator): self {
  64.         $this->validator $validator;
  65.         return $this;
  66.     }
  67.     
  68.     public function onKernelControllerArguments(ControllerArgumentsEvent $event) {
  69.         
  70.         $request $event->getRequest();
  71.         
  72.         /** @var Unserialize $annotation */
  73.         $annotation $request->attributes->get('_'.Unserialize::ALIAS_NAME);
  74.         if ($annotation) {
  75.             
  76.             $content $request->getContent();
  77.             $entity $request->attributes->get($annotation->getName());
  78.             
  79.             $groups array_merge(
  80.                 [ strtolower($request->getMethod()) ], 
  81.                 $annotation->getGroups()
  82.             );
  83.             $class $request->attributes->get('_'.Unserialize::ALIAS_NAME.'_class');
  84.             if (!$class && $entity) {
  85.                 $class get_class($entity);
  86.             }
  87.             if (!$class) {
  88.                 throw new \LogicException('Class not found on un serialize action');
  89.             }
  90.             
  91.             if ($content) {
  92.                 $entity $this->unserialize($content$entity$class$groups);
  93.             }
  94.             if (!$entity) {
  95.                 throw new BadRequestHttpException('Bad parameter on request content');
  96.             }
  97.     
  98.             $request->attributes->set($annotation->getName(), $entity);
  99.             
  100.             $this->validate($request$entity);
  101.             if ($annotation->isSave() && $this->isEntity($entity)) {
  102.                 $em $this->getEntityManagerForClass($entity);
  103.                 $em->persist($entity);
  104.                 $em->flush();
  105.             }
  106.             
  107.         }
  108.     }
  109.     
  110.     public function onKernelView(ViewEvent $event) {
  111.         $request  $event->getRequest();
  112.         /** @var Serialize $annotation */
  113.         $annotation $request->attributes->get('_'.Serialize::ALIAS_NAME);
  114.         if ($annotation) {
  115.             $data $event->getControllerResult();
  116.             $groups array_merge([ 'get' ], $annotation->getGroups());
  117.             $content $this->serialize($data,'json'$groups);
  118.             $headers $annotation->getHeaders();
  119.             $headers['Content-Type']   = 'application/json';
  120.             $headers['Content-Length'] = mb_strlen($content'UTF-8');
  121.             $event->setResponse(new Response($content$annotation->getCode(), $headers));
  122.         }
  123.     }
  124.     public function onKernelValidateException(ExceptionEvent $event) {
  125.         
  126.         $e $event->getThrowable();
  127.         if ($e instanceof UnserializeValidateException) {
  128.             $rtn = [];
  129.             foreach ($e->getConstraints() as $violation) {
  130.                 $prop $violation->getPropertyPath();
  131.                 if (!$prop) {
  132.                     $prop '_root_';
  133.                 }
  134.                 if (!array_key_exists($prop$rtn)) {
  135.                     $rtn[$prop] = [];
  136.                 }
  137.                 $rtn[$prop][] = $violation->getMessage();
  138.             }
  139.             $content $this->serializer->serialize($rtn'json');
  140.             $headers = [
  141.                 'Content-Type'   => 'application/json',
  142.                 'Content-Length' => mb_strlen($content'UTF-8')
  143.             ];
  144.             $event->setResponse(new Response($contentResponse::HTTP_BAD_REQUEST$headers));
  145.         }
  146.     }
  147.     
  148.     protected function unserialize(string $content$entitystring $class, array $groups) {
  149.         try {
  150.             $format 'json';
  151.             $context = [
  152.                 'groups' => $groups,
  153.             ];
  154.             if ($entity) {
  155.                 $context['object_to_populate'] = $entity;
  156.             }
  157.             
  158.             if (!$this->serializer->supportsDecoding($format$context)) {
  159.                 throw new NotEncodableValueException(sprintf('Deserialization for the format %s is not supported'$format));
  160.             }
  161.             $data $this->serializer->decode($content$format$context);
  162.             $entity $this->serializer->denormalize($data$class$format$context);
  163.             if ($entity instanceof UnserializerTransformInterface) {
  164.                 $entity->unserializeTransform($data$groups);
  165.             }
  166.             return $entity;
  167.         } catch (MissingConstructorArgumentsException $e) {
  168.             throw new BadRequestHttpException($e->getMessage());
  169.         } catch (\UnexpectedValueException $e) {
  170.             throw new BadRequestHttpException($e->getMessage());
  171.         }
  172.     }
  173.     protected function validate(Request $request$entity): void {
  174.         /** @var Validate $annotationValidate */
  175.         $annotationValidate $request->attributes->get('_'.Validate::ALIAS_NAME);
  176.         if ($annotationValidate) {
  177.             $groups array_merge([
  178.                 strtolower($request->getMethod()) ],
  179.                 $annotationValidate->getGroups()
  180.             );
  181.             
  182.             if (!$this->validator) {
  183.                 throw new \LogicException(sprintf('%s service not declared.'ValidatorInterface::class));
  184.             }
  185.             $errors $this->validator->validate($entitynull$groups);
  186.             if ($errors->count()) {
  187.                 throw new UnserializeValidateException($errors);
  188.             }
  189.         }
  190.     }
  191.     
  192.     protected function serialize($datastring $format, array $groups) {
  193.         
  194.         $context = [
  195.             'groups' =>  $groups,
  196.         ];
  197.         
  198.         if (!$this->serializer->supportsEncoding($format$context)) {
  199.             throw new NotEncodableValueException(sprintf('Serialization for the format %s is not supported'$format));
  200.         }
  201.         $json $this->serializer->normalize($data$format$context);
  202.         
  203.         if ($data instanceof SerializerTransformInterface) {
  204.             $json $data->serializeTransform($json$groups);
  205.         }
  206.         
  207.         return $this->serializer->encode($json$format$context);
  208.     }
  209. }