vendor/api-platform/core/src/Action/ExceptionAction.php line 33

  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <dunglas@gmail.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. declare(strict_types=1);
  11. namespace ApiPlatform\Action;
  12. use ApiPlatform\Metadata\ApiResource;
  13. use ApiPlatform\Metadata\HttpOperation;
  14. use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
  15. use ApiPlatform\Util\ErrorFormatGuesser;
  16. use ApiPlatform\Util\OperationRequestInitiatorTrait;
  17. use ApiPlatform\Util\RequestAttributesExtractor;
  18. use Symfony\Component\ErrorHandler\Exception\FlattenException;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\HttpFoundation\Response;
  21. use Symfony\Component\Serializer\SerializerInterface;
  22. /**
  23.  * Renders a normalized exception for a given {@see FlattenException}.
  24.  *
  25.  * @author Baptiste Meyer <baptiste.meyer@gmail.com>
  26.  * @author Kévin Dunglas <dunglas@gmail.com>
  27.  */
  28. final class ExceptionAction
  29. {
  30.     use OperationRequestInitiatorTrait;
  31.     /**
  32.      * @param array $errorFormats      A list of enabled error formats
  33.      * @param array $exceptionToStatus A list of exceptions mapped to their HTTP status code
  34.      */
  35.     public function __construct(private readonly SerializerInterface $serializer, private readonly array $errorFormats, private readonly array $exceptionToStatus = [], ?ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory null)
  36.     {
  37.         $this->resourceMetadataCollectionFactory $resourceMetadataCollectionFactory;
  38.     }
  39.     /**
  40.      * Converts an exception to a JSON response.
  41.      */
  42.     public function __invoke(FlattenException $exceptionRequest $request): Response
  43.     {
  44.         $operation $this->initializeOperation($request);
  45.         $exceptionClass $exception->getClass();
  46.         $statusCode $exception->getStatusCode();
  47.         $exceptionToStatus array_merge(
  48.             $this->exceptionToStatus,
  49.             $operation $operation->getExceptionToStatus() ?? [] : $this->getOperationExceptionToStatus($request)
  50.         );
  51.         foreach ($exceptionToStatus as $class => $status) {
  52.             if (is_a($exceptionClass$classtrue)) {
  53.                 $statusCode $status;
  54.                 break;
  55.             }
  56.         }
  57.         $headers $exception->getHeaders();
  58.         $format ErrorFormatGuesser::guessErrorFormat($request$this->errorFormats);
  59.         $headers['Content-Type'] = sprintf('%s; charset=utf-8'$format['value'][0]);
  60.         $headers['X-Content-Type-Options'] = 'nosniff';
  61.         $headers['X-Frame-Options'] = 'deny';
  62.         return new Response($this->serializer->serialize($exception$format['key'], ['statusCode' => $statusCode]), $statusCode$headers);
  63.     }
  64.     private function getOperationExceptionToStatus(Request $request): array
  65.     {
  66.         $attributes RequestAttributesExtractor::extractAttributes($request);
  67.         if ([] === $attributes) {
  68.             return [];
  69.         }
  70.         $resourceMetadataCollection $this->resourceMetadataCollectionFactory->create($attributes['resource_class']);
  71.         /** @var HttpOperation $operation */
  72.         $operation $resourceMetadataCollection->getOperation($attributes['operation_name'] ?? null);
  73.         $exceptionToStatus = [$operation->getExceptionToStatus() ?: []];
  74.         foreach ($resourceMetadataCollection as $resourceMetadata) {
  75.             /* @var ApiResource $resourceMetadata */
  76.             $exceptionToStatus[] = $resourceMetadata->getExceptionToStatus() ?: [];
  77.         }
  78.         return array_merge(...$exceptionToStatus);
  79.     }
  80. }