diff --git a/src/State/ClientTicketStatusProcessor.php b/src/State/ClientTicketStatusProcessor.php new file mode 100644 index 0000000..271834a --- /dev/null +++ b/src/State/ClientTicketStatusProcessor.php @@ -0,0 +1,56 @@ + + */ +final readonly class ClientTicketStatusProcessor implements ProcessorInterface +{ + private const FORBIDDEN_TRANSITIONS = [ + 'done' => ['new'], + 'rejected' => ['new'], + ]; + + public function __construct( + private EntityManagerInterface $entityManager, + ) {} + + 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(); + + return $data; + } +}