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

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