CI / Docker Lint (push) Successful in 21s
- Added Symfony Validation Lib. - Updated API DTOs to include validation constraints.
87 lines
3.2 KiB
PHP
87 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace App\EventSubscriber;
|
|
|
|
use App\ApiErrorException;
|
|
use App\DTO\ApiErrorMessage;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
|
|
use Symfony\Component\HttpKernel\KernelEvents;
|
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
|
use Symfony\Component\Validator\Exception\ValidationFailedException;
|
|
|
|
class ApiExceptionSubscriber implements EventSubscriberInterface
|
|
{
|
|
|
|
public function __construct(
|
|
private LoggerInterface $logger,
|
|
) {}
|
|
|
|
public function onKernelException(ExceptionEvent $event): void
|
|
{
|
|
$e = $event->getThrowable();
|
|
if ($e instanceof ApiErrorException) {
|
|
$apiErrorMsg = $e->getApiErrorMsg();
|
|
} else {
|
|
$statusCode = $e instanceof HttpExceptionInterface ? $e->getStatusCode() : 500;
|
|
$apiErrorMsg = new ApiErrorMessage($statusCode);
|
|
|
|
/*
|
|
* If it's an HttpException message (e.g. for 404, 403),
|
|
* we'll say as a rule that the exception message is safe
|
|
* for the client. Otherwise, it could be some sensitive
|
|
* low-level exception, which should *not* be exposed
|
|
*/
|
|
if ($e instanceof HttpExceptionInterface) {
|
|
//Check if it's a Validation error.
|
|
// When using MapRequestPayload() ValidationErrors throw HttpExceptions.
|
|
$prev = $e->getPrevious();
|
|
if ($prev instanceof ValidationFailedException) {
|
|
//Get validation error details.
|
|
$errorList = [];
|
|
$violationList = $prev->getViolations();
|
|
foreach ($violationList as $violation) {
|
|
$errorList[] = [
|
|
'field' => $violation->getPropertyPath(),
|
|
'message' => $violation->getMessage(),
|
|
];
|
|
}
|
|
$apiErrorMsg->setExtraData('detail', "Validation Error. See errorList for details");
|
|
$apiErrorMsg->setExtraData('errorList', $errorList);
|
|
} else {
|
|
//Get exception error message.
|
|
$apiErrorMsg->setExtraData('detail', $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
//Send error to logs.
|
|
$exceptionError = [
|
|
'message' => $e->getMessage(),
|
|
'file' => $e->getFile(),
|
|
'line' => $e->getLine(),
|
|
'trace' => $e->getTrace()
|
|
];
|
|
$errorContext = array_merge($apiErrorMsg->toArray(), $exceptionError);
|
|
$this->logger->error("API ERROR Exception:", $errorContext);
|
|
|
|
//Send error to client.
|
|
$response = new JsonResponse(
|
|
$apiErrorMsg->toArray(),
|
|
$apiErrorMsg->getStatusCode()
|
|
);
|
|
$response->headers->set('Content-Type', 'application/problem+json');
|
|
|
|
$event->setResponse($response);
|
|
}
|
|
|
|
public static function getSubscribedEvents(): array
|
|
{
|
|
return [
|
|
KernelEvents::EXCEPTION => 'onKernelException',
|
|
];
|
|
}
|
|
}
|