<?php
declare(strict_types=1);
namespace App\EventListener;
use ApiPlatform\Symfony\Validator\Exception\ValidationException;
use App\Entity\Admin\LocaleInterface;
use App\Generator\Logger\ApiLoggerExceptionGenerator;
use App\Helper\Response\ResponseInterface as CustomResponseInterface;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Contracts\Translation\TranslatorInterface;
#[AsEventListener(priority: 135)]
class ExceptionListener
{
public function __construct(
private TranslatorInterface $translator,
private ApiLoggerExceptionGenerator $apiLoggerExceptionGenerator,
) {
}
public function __invoke(ExceptionEvent $event): void
{
$request = $event->getRequest();
$route = $request->attributes->get('_route');
$exception = $event->getThrowable();
if (null === $route || !str_starts_with($route, 'api_')) {
return;
}
$this->apiLoggerExceptionGenerator->generate($exception);
if (false === $exception instanceof ValidationException || false === property_exists($exception, 'constraintViolationList')) {
return;
}
$errors = [
'detail' => CustomResponseInterface::INVALID_INPUT,
'violations' => [],
];
$locale = $request->headers->get('locale');
if (null === $locale || false === \in_array($locale, LocaleInterface::LOCALES, true)) {
$locale = LocaleInterface::LOCALE_EN;
}
/** @var ValidationException $exception */
foreach ($exception->getConstraintViolationList() as $violation) {
$errors['violations'][] = [
'property' => $violation->getPropertyPath(),
'message' => $this->translator->trans($violation->getMessageTemplate(), $violation->getParameters(), 'validators', $locale),
];
}
$response = new Response();
$response->setContent(stripslashes(json_encode($errors, JSON_UNESCAPED_UNICODE)));
$code = 0 === $exception->getCode() ? Response::HTTP_BAD_REQUEST : $exception->getCode();
$response->setStatusCode($code);
$event->setResponse($response);
}
}