*/ final readonly class ClientTicketNumberProcessor implements ProcessorInterface { public function __construct( private EntityManagerInterface $entityManager, private Security $security, private ClientTicketRepository $clientTicketRepository, private NotificationService $notificationService, ) {} public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ClientTicket { assert($data instanceof ClientTicket); $user = $this->security->getUser(); assert($user instanceof User); $project = $data->getProject(); if (null === $project) { throw new BadRequestHttpException('Project is required.'); } // Admins can create tickets on any project; clients only on allowed projects if (!$this->security->isGranted('ROLE_ADMIN')) { if (null === $user->getClient()) { throw new AccessDeniedHttpException('Only client users can create tickets.'); } if (!$user->getAllowedProjects()->contains($project)) { throw new AccessDeniedHttpException('You do not have access to this project.'); } } $now = new DateTimeImmutable(); $maxNumber = $this->clientTicketRepository->findMaxNumberByProjectForUpdate($project); $data->setNumber($maxNumber + 1); $data->setSubmittedBy($user); $data->setStatus('new'); $data->setCreatedAt($now); $data->setUpdatedAt($now); $this->entityManager->persist($data); $this->entityManager->flush(); $this->notificationService->createForTicketCreated($data); return $data; } }