<?php
namespace App\EventSubscriber;
use ApiPlatform\Core\EventListener\EventPriorities;
use ApiPlatform\Core\Exception\InvalidArgumentException;
use Doctrine\DBAL\Exception\DriverException;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Doctrine\DBAL\Types\ConversionException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Serializer\Exception\{
NotEncodableValueException,
UnexpectedValueException,
};
use Symfony\Contracts\Translation\TranslatorInterface;
class InvalidIRIExceptionSubscriber implements EventSubscriberInterface
{
public const SYNTAX_ERROR_EXCEPTIONS = [
NotEncodableValueException::class,
];
public const UNEXPECTED_VALUE_EXCEPTION = [
UnexpectedValueException::class,
];
public const CONVERSION_ERROR_EXCEPTION = [
ConversionException::class,
DriverException::class,
];
public const FOREIGN_KEY_EXCEPTION = [
ForeignKeyConstraintViolationException::class,
];
public function __construct(private TranslatorInterface $translator)
{
}
public function onRequest(ExceptionEvent $event): void
{
$route = $event->getRequest()->attributes->get('_route');
$content = (string) $event->getRequest()->getContent();
$throwable = \get_class($event->getThrowable());
$mes = $event->getThrowable()->getMessage();
if (\in_array($throwable, self::CONVERSION_ERROR_EXCEPTION)) {
$event->setThrowable(new NotFoundHttpException('Data error: ' . $mes));
}
if (\in_array($throwable, self::FOREIGN_KEY_EXCEPTION)) {
$event->setThrowable(new InvalidArgumentException($mes));
}
if (\in_array($throwable, self::SYNTAX_ERROR_EXCEPTIONS)) {
$event->setThrowable(new InvalidArgumentException('Syntax error: ' . $mes));
}
if (\in_array($route, ['api_units_delete_item']) && \str_contains($mes, 'SQLSTATE[23503]')) {
$event->setThrowable(new InvalidArgumentException('Entity with relations cannot be removed'));
}
try {
$data = \json_decode($content, true, flags: JSON_THROW_ON_ERROR);
} catch (\Exception) {
return;
}
if (\in_array($route, ['api_time_entries_open_collection', 'api_time_entries_post_collection'])
&& \array_key_exists('project', $data) && (!\is_string($data['project']) || empty(\trim($data['project'])))
) {
$message = $this->translator->trans('The field \'field_name\' must not be an empty string', ['field_name' => 'project']);
$event->setThrowable(new InvalidArgumentException($message));
}
if (\in_array($throwable, self::UNEXPECTED_VALUE_EXCEPTION)) {
$message = $this->translator->trans('The entity does not exist: ');
$event->setThrowable(new InvalidArgumentException($message . \str_replace('Invalid IRI ', '', $mes)));
}
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::EXCEPTION => ['onRequest', EventPriorities::PRE_RESPOND],
];
}
}