vendor/can/rest/src/Can/RestBundle/EventListener/RequestFormatListener.php line 65

Open in your IDE?
  1. <?php
  2. namespace Can\RestBundle\EventListener;
  3. use Can\RestBundle\CanRestBundle;
  4. use Can\RestBundle\Http\Exception\UnsupportedRequestFormatHttpException;
  5. use Can\RestBundle\Http\Method;
  6. use Can\RestBundle\Ingest\IngestConfiguration;
  7. use Can\RestBundle\Negotiation\Format;
  8. use Can\RestBundle\Negotiation\FormatGuesserInterface;
  9. use Can\RestBundle\Negotiation\NegotiationConfiguration;
  10. use Can\RestBundle\Negotiation\NoContentTypeException;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpKernel\Event\RequestEvent;
  13. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  14. use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
  15. /**
  16.  * A content-negotiation listener which returns a 400 (Bad Request) error
  17.  * response if the request format is not supported.
  18.  *
  19.  * @group http
  20.  *
  21.  * @package can/rest-bundle
  22.  * @author lechecacharro <lechecacharro@gmail.com>
  23.  */
  24. class RequestFormatListener
  25. {
  26.     /**
  27.      * @var IngestConfiguration
  28.      */
  29.     protected $ingestConfiguration;
  30.     /**
  31.      * @var NegotiationConfiguration
  32.      */
  33.     protected $negotiationConfiguration;
  34.     /**
  35.      * @var FormatGuesserInterface
  36.      */
  37.     protected $formatGuesser;
  38.     /**
  39.      * RequestFormatListener constructor.
  40.      *
  41.      * @param IngestConfiguration      $ingestConfiguration
  42.      * @param NegotiationConfiguration $negotiationConfiguration
  43.      * @param FormatGuesserInterface   $formatGuesser
  44.      */
  45.     public function __construct(IngestConfiguration $ingestConfigurationNegotiationConfiguration $negotiationConfigurationFormatGuesserInterface $formatGuesser)
  46.     {
  47.         $this->ingestConfiguration $ingestConfiguration;
  48.         $this->negotiationConfiguration $negotiationConfiguration;
  49.         $this->formatGuesser $formatGuesser;
  50.     }
  51.     /**
  52.      * @param RequestEvent $event
  53.      *
  54.      * @throws BadRequestHttpException on malformed Content-Type
  55.      */
  56.     public function onRequest(RequestEvent $event): void
  57.     {
  58.         if (! $event->isMasterRequest()) {
  59.             return;
  60.         }
  61.         $request $event->getRequest();
  62.         // Skip if not in the REST zone, or if the request has no content
  63.         if (! $request->attributes->get(CanRestBundle::ATTR_SERVICE_ZONE) ||
  64.             ! $request->attributes->get(CanRestBundle::ATTR_REQUEST_CONTENT)) {
  65.             return;
  66.         }
  67.         $format null;
  68.         try {
  69.             // Try to guess the request format from the request (most probably
  70.             // based on the Content-Type header, but maybe the guesser supports
  71.             // sniffing the request payload)
  72.             $format $this->formatGuesser->guess($request);
  73.         } catch (NoContentTypeException $e) {
  74.             // If the request format could not be figured out for some reason
  75.             // (e.g., no Content-Type header),either fail (if the no Content-Type
  76.             // policy is STRICT) or fall-through and use the default media type
  77.             if ($this->negotiationConfiguration->isStrictNoContentTypePolicy()) {
  78.                 throw new UnsupportedMediaTypeHttpException();
  79.             }
  80.             // Fall-through
  81.         }
  82.         if (null === $format) {
  83.             $format $this->formatGuesser->getDefaultFormat();
  84.         }
  85.         $request->attributes->set(CanRestBundle::ATTR_REQUEST_FORMAT$format);
  86.         $request->attributes->set(CanRestBundle::ATTR_REQUEST_MEDIATYPE$format->getMediaType());
  87.         if (! $this->isSupportedFormat($request$format)) {
  88.             $request->attributes->set(CanRestBundle::ATTR_REQUEST_SUPPORTEDfalse);
  89.             throw new UnsupportedRequestFormatHttpException($format->getName(), $format->getMediaType());
  90.         }
  91.         $request->attributes->set(CanRestBundle::ATTR_REQUEST_SUPPORTEDtrue);
  92.     }
  93.     /**
  94.      * Figures out whether the specified format is supported. Note that the
  95.      * support for some formats (e.g. support for patch formats, or support
  96.      * for ingest formats may be allowed only for some particular kinds of
  97.      * requests).
  98.      *
  99.      * @param Request $request
  100.      * @param Format  $format
  101.      *
  102.      * @return bool
  103.      */
  104.     protected function isSupportedFormat(Request $requestFormat $format): bool
  105.     {
  106.         $name $format->getName();
  107.         if ($this->negotiationConfiguration->isSupportedFormat($name)) {
  108.             return true;
  109.         }
  110.         $method $request->getMethod();
  111.         if (Method::PATCH === $method && $this->negotiationConfiguration->isSupportedPatchFormat($name)) {
  112.             return true;
  113.         }
  114.         if ($this->ingestConfiguration->isMethodAllowed($method) &&
  115.             $this->ingestConfiguration->isMediaTypeAllowed($format->getMediaType())) {
  116.             return true;
  117.         }
  118.         return false;
  119.     }
  120. }