0fc9daa974
Auto Tag Develop / tag (push) Successful in 13s
Le nom d'une machine n'est plus unique globalement mais par site : deux machines peuvent porter le même nom sur des sites différents, mais le doublon reste interdit sur un même site. - Machine : contrainte composite (name, siteId) + UniqueEntity (name, site) - UniqueConstraintSubscriber : message explicite pour uniq_machine_name_site - Migration : drop index global sur name + create unique index (name, siteid) - Front : message d'erreur inline explicite à la création (page + modale) - Tests : 4 scénarios (sites différents / même site / renommage / déplacement)
70 lines
2.1 KiB
PHP
70 lines
2.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\EventSubscriber;
|
|
|
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
|
|
use Symfony\Component\HttpKernel\KernelEvents;
|
|
use Throwable;
|
|
|
|
final class UniqueConstraintSubscriber implements EventSubscriberInterface
|
|
{
|
|
public static function getSubscribedEvents(): array
|
|
{
|
|
return [
|
|
KernelEvents::EXCEPTION => ['onKernelException', 256],
|
|
];
|
|
}
|
|
|
|
public function onKernelException(ExceptionEvent $event): void
|
|
{
|
|
$exception = $this->findUniqueConstraintViolation($event->getThrowable());
|
|
|
|
if (!$exception) {
|
|
return;
|
|
}
|
|
|
|
$constraint = $this->detectConstraintName($exception);
|
|
$error = match ($constraint) {
|
|
'unique_category_name' => 'Un élément avec ce nom existe déjà dans cette catégorie.',
|
|
'uniq_machine_name_site' => 'Une machine avec ce nom existe déjà sur ce site.',
|
|
default => 'Un élément avec cette valeur existe déjà.',
|
|
};
|
|
|
|
$event->setResponse(new JsonResponse(
|
|
[
|
|
'success' => false,
|
|
'error' => $error,
|
|
'constraint' => $constraint,
|
|
],
|
|
JsonResponse::HTTP_CONFLICT
|
|
));
|
|
}
|
|
|
|
private function findUniqueConstraintViolation(Throwable $throwable): ?UniqueConstraintViolationException
|
|
{
|
|
for ($current = $throwable; null !== $current; $current = $current->getPrevious()) {
|
|
if ($current instanceof UniqueConstraintViolationException) {
|
|
return $current;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function detectConstraintName(UniqueConstraintViolationException $exception): ?string
|
|
{
|
|
$message = $exception->getMessage();
|
|
|
|
if (preg_match('/constraint\s+"([^"]+)"/', $message, $matches)) {
|
|
return $matches[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|