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

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): void
  46.     {
  47.         $this->defaultFormat $defaultFormat;
  48.     }
  49.     public function onKernelRequest(RequestEvent $event): void
  50.     {
  51.         $request $event->getRequest();
  52.         if (!$request->attributes->get(FOSRestBundle::ZONE_ATTRIBUTEtrue)) {
  53.             return;
  54.         }
  55.         $method $request->getMethod();
  56.         $contentType $request->headers->get('Content-Type');
  57.         $normalizeRequest $this->normalizeForms && $this->isFormRequest($request);
  58.         if ($this->isDecodeable($request)) {
  59.             $format null === $contentType
  60.                 $request->getRequestFormat()
  61.                 : $request->getFormat($contentType);
  62.             $format $format ?: $this->defaultFormat;
  63.             $content $request->getContent();
  64.             if (null === $format || !$this->decoderProvider->supports($format)) {
  65.                 if ($this->throwExceptionOnUnsupportedContentType
  66.                     && $this->isNotAnEmptyDeleteRequestWithNoSetContentType($method$content$contentType)
  67.                 ) {
  68.                     throw new UnsupportedMediaTypeHttpException("Request body format '$format' not supported");
  69.                 }
  70.                 return;
  71.             }
  72.             if (!empty($content)) {
  73.                 $decoder $this->decoderProvider->getDecoder($format);
  74.                 $data $decoder->decode($content);
  75.                 if (is_array($data)) {
  76.                     $request->request = new ParameterBag($data);
  77.                     $normalizeRequest true;
  78.                 } else {
  79.                     throw new BadRequestHttpException('Invalid '.$format.' message received');
  80.                 }
  81.             }
  82.         }
  83.         if (null !== $this->arrayNormalizer && $normalizeRequest) {
  84.             $data $request->request->all();
  85.             try {
  86.                 $data $this->arrayNormalizer->normalize($data);
  87.             } catch (NormalizationException $e) {
  88.                 throw new BadRequestHttpException($e->getMessage());
  89.             }
  90.             $request->request = new ParameterBag($data);
  91.         }
  92.     }
  93.     private function isNotAnEmptyDeleteRequestWithNoSetContentType(string $method$content, ?string $contentType): bool
  94.     {
  95.         return false === ('DELETE' === $method && empty($content) && empty($contentType));
  96.     }
  97.     private function isDecodeable(Request $request): bool
  98.     {
  99.         if (!in_array($request->getMethod(), ['POST''PUT''PATCH''DELETE'])) {
  100.             return false;
  101.         }
  102.         return !$this->isFormRequest($request);
  103.     }
  104.     private function isFormRequest(Request $request): bool
  105.     {
  106.         $contentTypeParts explode(';'$request->headers->get('Content-Type'''));
  107.         if (isset($contentTypeParts[0])) {
  108.             return in_array($contentTypeParts[0], ['multipart/form-data''application/x-www-form-urlencoded']);
  109.         }
  110.         return false;
  111.     }
  112. }