Files
Inventory/src/EventSubscriber/UniqueConstraintSubscriber.php
T
Matthieu 0fc9daa974
Auto Tag Develop / tag (push) Successful in 13s
feat(machines) : unicité du nom de machine par site
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)
2026-05-27 15:37:38 +02:00

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;
}
}