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

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\GetResponseEvent;
  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.     private $decoderProvider;
  29.     private $throwExceptionOnUnsupportedContentType;
  30.     private $defaultFormat;
  31.     private $arrayNormalizer;
  32.     private $normalizeForms;
  33.     /**
  34.      * Constructor.
  35.      *
  36.      * @param DecoderProviderInterface $decoderProvider
  37.      * @param bool                     $throwExceptionOnUnsupportedContentType
  38.      * @param ArrayNormalizerInterface $arrayNormalizer
  39.      * @param bool                     $normalizeForms
  40.      */
  41.     public function __construct(
  42.     DecoderProviderInterface $decoderProvider$throwExceptionOnUnsupportedContentType falseArrayNormalizerInterface $arrayNormalizer null$normalizeForms false
  43.     ) {
  44.         $this->decoderProvider $decoderProvider;
  45.         $this->throwExceptionOnUnsupportedContentType $throwExceptionOnUnsupportedContentType;
  46.         $this->arrayNormalizer $arrayNormalizer;
  47.         $this->normalizeForms $normalizeForms;
  48.     }
  49.     /**
  50.      * Sets the fallback format if there's no Content-Type in the request.
  51.      *
  52.      * @param string $defaultFormat
  53.      */
  54.     public function setDefaultFormat($defaultFormat) {
  55.         $this->defaultFormat $defaultFormat;
  56.     }
  57.     /**
  58.      * Core request handler.
  59.      *
  60.      * @param GetResponseEvent $event
  61.      *
  62.      * @throws BadRequestHttpException
  63.      * @throws UnsupportedMediaTypeHttpException
  64.      */
  65.     public function onKernelRequest(GetResponseEvent $event) {
  66.         $request $event->getRequest();
  67.         if (!$request->attributes->get(FOSRestBundle::ZONE_ATTRIBUTEtrue)) {
  68.             return;
  69.         }
  70.         $method $request->getMethod();
  71.         $contentType $request->headers->get('Content-Type');
  72.         $normalizeRequest $this->normalizeForms && $this->isFormRequest($request);
  73.         if ($this->isDecodeable($request)) {
  74.             $format null === $contentType $request->getRequestFormat() : $request->getFormat($contentType);
  75.             $format $format ?: $this->defaultFormat;
  76.             $content $request->getContent();
  77.             if (!$this->decoderProvider->supports($format)) {
  78.                 if ($this->throwExceptionOnUnsupportedContentType && $this->isNotAnEmptyDeleteRequestWithNoSetContentType($method$content$contentType)
  79.                 ) {
  80.                     throw new UnsupportedMediaTypeHttpException("Request body format '$format' not supported");
  81.                 }
  82.                 return;
  83.             }
  84.             if (!empty($content)) {
  85.                 $decoder $this->decoderProvider->getDecoder($format);
  86.                 $data $decoder->decode($content);
  87.                 if (is_array($data)) {
  88.                     $request->request = new ParameterBag($data);
  89.                     $normalizeRequest true;
  90.                 } else {
  91.                     throw new BadRequestHttpException('Invalid ' $format ' message received');
  92.                 }
  93.             }
  94.         }
  95.         if (null !== $this->arrayNormalizer && $normalizeRequest) {
  96.             $data $request->request->all();
  97.             try {
  98.                 $data $this->arrayNormalizer->normalize($data);
  99.             } catch (NormalizationException $e) {
  100.                 throw new BadRequestHttpException($e->getMessage());
  101.             }
  102.             $request->request = new ParameterBag($data);
  103.         }
  104.     }
  105.     /**
  106.      * Check if the Request is not a DELETE with no content and no Content-Type.
  107.      *
  108.      * @param $method
  109.      * @param $content
  110.      * @param $contentType
  111.      *
  112.      * @return bool
  113.      */
  114.     private function isNotAnEmptyDeleteRequestWithNoSetContentType($method$content$contentType) {
  115.         return false === ('DELETE' === $method && empty($content) && empty($contentType));
  116.     }
  117.     /**
  118.      * Check if we should try to decode the body.
  119.      *
  120.      * @param Request $request
  121.      *
  122.      * @return bool
  123.      */
  124.     protected function isDecodeable(Request $request) {
  125.         if (!in_array($request->getMethod(), ['POST''PUT''PATCH''DELETE'])) {
  126.             return false;
  127.         }
  128.         return !$this->isFormRequest($request);
  129.     }
  130.     /**
  131.      * Check if the content type indicates a form submission.
  132.      *
  133.      * @param Request $request
  134.      *
  135.      * @return bool
  136.      */
  137.     private function isFormRequest(Request $request) {
  138.         $contentTypeParts explode(';'$request->headers->get('Content-Type'));
  139.         if (isset($contentTypeParts[0])) {
  140.             return in_array($contentTypeParts[0], ['multipart/form-data''application/x-www-form-urlencoded']);
  141.         }
  142.         return false;
  143.     }
  144. }