*/ final readonly class ClientTicketStatusProcessor implements ProcessorInterface { private const FORBIDDEN_TRANSITIONS = [ 'done' => ['new'], 'rejected' => ['new'], ]; public function __construct( private EntityManagerInterface $entityManager, private NotificationService $notificationService, ) {} public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ClientTicket { assert($data instanceof ClientTicket); $originalData = $context['previous_data'] ?? null; if ($originalData instanceof ClientTicket) { $oldStatus = $originalData->getStatus(); $newStatus = $data->getStatus(); if ($oldStatus !== $newStatus) { $forbidden = self::FORBIDDEN_TRANSITIONS[$oldStatus] ?? []; if (in_array($newStatus, $forbidden, true)) { throw new BadRequestHttpException(sprintf('Transition from "%s" to "%s" is not allowed.', $oldStatus, $newStatus)); } if ('rejected' === $newStatus && (null === $data->getStatusComment() || '' === trim($data->getStatusComment()))) { throw new BadRequestHttpException('A comment is required when rejecting a ticket.'); } } } $data->setUpdatedAt(new DateTimeImmutable()); $this->entityManager->persist($data); $this->entityManager->flush(); $this->notificationService->createForStatusChange($data); return $data; } }