vendor/friendsofsymfony/rest-bundle/EventListener/BodyListener.php line 59

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the FOSRestBundle package.
  4.  *
  5.  * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace FOS\RestBundle\EventListener;
  11. use FOS\RestBundle\Decoder\DecoderProviderInterface;
  12. use FOS\RestBundle\FOSRestBundle;
  13. use FOS\RestBundle\Normalizer\ArrayNormalizerInterface;
  14. use FOS\RestBundle\Normalizer\Exception\NormalizationException;
  15. use Symfony\Component\HttpFoundation\ParameterBag;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpKernel\Event\RequestEvent;
  18. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  19. use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
  20. /**
  21.  * This listener handles Request body decoding.
  22.  *
  23.  * @author Lukas Kahwe Smith <smith@pooteeweet.org>
  24.  *
  25.  * @internal
  26.  */
  27. class BodyListener
  28. {
  29.     private $decoderProvider;
  30.     private $throwExceptionOnUnsupportedContentType;
  31.     private $defaultFormat;
  32.     private $arrayNormalizer;
  33.     private $normalizeForms;
  34.     public function __construct(
  35.         DecoderProviderInterface $decoderProvider,
  36.         bool $throwExceptionOnUnsupportedContentType false,
  37.         ArrayNormalizerInterface $arrayNormalizer null,
  38.         bool $normalizeForms false
  39.     ) {
  40.         $this->decoderProvider $decoderProvider;
  41.         $this->throwExceptionOnUnsupportedContentType $throwExceptionOnUnsupportedContentType;
  42.         $this->arrayNormalizer $arrayNormalizer;
  43.         $this->normalizeForms $normalizeForms;
  44.     }
  45.     public function setDefaultFormat(?string $defaultFormat)
  46.     {
  47.         $this->defaultFormat $defaultFormat;
  48.     }
  49.     /**
  50.      * @param RequestEvent $event
  51.      */
  52.     public function onKernelRequest($event)
  53.     {
  54.         $request $event->getRequest();
  55.         if (!$request->attributes->get(FOSRestBundle::ZONE_ATTRIBUTEtrue)) {
  56.             return;
  57.         }
  58.         $method $request->getMethod();
  59.         $contentType $request->headers->get('Content-Type');
  60.         $normalizeRequest $this->normalizeForms && $this->isFormRequest($request);
  61.         if ($this->isDecodeable($request)) {
  62.             $format null === $contentType
  63.                 $request->getRequestFormat()
  64.                 : $request->getFormat($contentType);
  65.             $format $format ?: $this->defaultFormat;
  66.             $content $request->getContent();
  67.             if (null === $format || !$this->decoderProvider->supports($format)) {
  68.                 if ($this->throwExceptionOnUnsupportedContentType
  69.                     && $this->isNotAnEmptyDeleteRequestWithNoSetContentType($method$content$contentType)
  70.                 ) {
  71.                     throw new UnsupportedMediaTypeHttpException("Request body format '$format' not supported");
  72.                 }
  73.                 return;
  74.             }
  75.             if (!empty($content)) {
  76.                 $decoder $this->decoderProvider->getDecoder($format);
  77.                 $data $decoder->decode($content);
  78.                 if (is_array($data)) {
  79.                     $request->request = new ParameterBag($data);
  80.                     $normalizeRequest true;
  81.                 } else {
  82.                     throw new BadRequestHttpException('Invalid '.$format.' message received');
  83.                 }
  84.             }
  85.         }
  86.         if (null !== $this->arrayNormalizer && $normalizeRequest) {
  87.             $data $request->request->all();
  88.             try {
  89.                 $data $this->arrayNormalizer->normalize($data);
  90.             } catch (NormalizationException $e) {
  91.                 throw new BadRequestHttpException($e->getMessage());
  92.             }
  93.             $request->request = new ParameterBag($data);
  94.         }
  95.     }
  96.     private function isNotAnEmptyDeleteRequestWithNoSetContentType(string $method$content$contentType): bool
  97.     {
  98.         return false === ('DELETE' === $method && empty($content) && empty($contentType));
  99.     }
  100.     /**
  101.      * Check if we should try to decode the body.
  102.      *
  103.      * @return bool
  104.      */
  105.     protected function isDecodeable(Request $request)
  106.     {
  107.         if (!in_array($request->getMethod(), ['POST''PUT''PATCH''DELETE'])) {
  108.             return false;
  109.         }
  110.         return !$this->isFormRequest($request);
  111.     }
  112.     private function isFormRequest(Request $request): bool
  113.     {
  114.         $contentTypeParts explode(';'$request->headers->get('Content-Type'));
  115.         if (isset($contentTypeParts[0])) {
  116.             return in_array($contentTypeParts[0], ['multipart/form-data''application/x-www-form-urlencoded']);
  117.         }
  118.         return false;
  119.     }
  120. }