vendor/friendsofsymfony/rest-bundle/FOS/RestBundle/EventListener/BodyListener.php line 86

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