<?php
namespace App\Service\Admission\Tickets;
use App\Entity\Admission\Tickets\AbstractTicketStatus;
use App\Entity\Admission\Tickets\AgreeTicketStatus;
use App\Entity\Admission\Tickets\TicketInterface;
use App\Entity\Admission\Tickets\TicketOperator;
use Carbon\Carbon;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Workflow\Event\CompletedEvent;
class MercureManager implements EventSubscriberInterface
{
protected HubInterface $publisher;
protected Serializer $serializer;
private $em;
public function __construct(HubInterface $publisher, EntityManagerInterface $em)
{
$defaultContext = [
AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object, $format, $context) {
return $object->__toString();
},
AbstractNormalizer::CALLBACKS => [
'datetime' => function ($innerObject, $outerObject, string $attributeName, string $format = null, array $context = []) {
return $innerObject instanceof Carbon ? $innerObject->getTimestamp() : '';
}
]
];
$normalizer = new ObjectNormalizer(null, null, null, null, null, null, $defaultContext);
$this->serializer = new Serializer([$normalizer], [new JsonEncoder()]);
$this->publisher = $publisher;
$this->em = $em;
}
public static function getSubscribedEvents(): array
{
return [
'workflow.entrant_ticket_workflow.completed.ticket_assign' => 'onTicketAssign',
'workflow.entrant_ticket_workflow.completed.ticket_accept' => 'onTicketAccept',
'workflow.entrant_ticket_workflow.completed.ticket_cancel' => 'onTicketCancel',
'workflow.entrant_ticket_workflow.completed.ticket_activate' => 'onTicketActivate',
'workflow.entrant_ticket_workflow.completed.ticket_close' => 'onTicketClose',
'workflow.agree_ticket_workflow.completed.ticket_assign' => 'onAgreeTicketAssign',
'workflow.agree_ticket_workflow.completed.ticket_close' => 'onAgreeTicketClose',
'workflow.agree_ticket_workflow.completed.ticket_reassign' => 'onAgreeTicketReassign',
'workflow.agree_ticket_workflow.completed.ticket_pause' => 'onAgreeTicketPause',
'workflow.agree_ticket_workflow.completed.ticket_unpause' => 'onAgreeTicketUnpause',
'workflow.agree_ticket_workflow.completed.ticket_cancel' => 'onAgreeTicketCancel',
'workflow.original_ticket_workflow.completed.ticket_assign' => 'onAgreeTicketAssign',
'workflow.original_ticket_workflow.completed.ticket_close' => 'onAgreeTicketClose',
'workflow.original_ticket_workflow.completed.ticket_reassign' => 'onAgreeTicketReassign',
'workflow.original_ticket_workflow.completed.ticket_pause' => 'onAgreeTicketPause',
'workflow.original_ticket_workflow.completed.ticket_unpause' => 'onAgreeTicketUnpause',
'workflow.original_ticket_workflow.completed.ticket_cancel' => 'onAgreeTicketCancel',
];
}
public function onAgreeTicketAssign(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::ASSIGN);
$this->em->flush();
}
public function onAgreeTicketClose(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::CLOSE);
$this->em->flush();
}
public function onAgreeTicketReassign(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::REASSIGN);
$this->em->flush();
}
public function onAgreeTicketPause(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AgreeTicketStatus::PAUSE);
$this->em->flush();
}
public function onAgreeTicketUnpause(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AgreeTicketStatus::UNPAUSE);
$this->em->flush();
}
public function onAgreeTicketCancel(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::CANCEL);
$this->em->flush();
}
public function onTicketAssign(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::ASSIGN);
$this->em->flush();
}
public function onTicketAccept(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::ACCEPT);
$this->em->flush();
}
public function onTicketCancel(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::CANCEL);
$this->em->flush();
}
public function onTicketActivate(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::ACTIVATE);
$this->em->flush();
}
public function onTicketClose(CompletedEvent $event)
{
/** @var TicketInterface $ticket */
$ticket = $event->getSubject();
$this->publishTicketEvent($ticket, AbstractTicketStatus::CLOSE);
$this->em->flush();
}
protected function publish(Update $update)
{
$this->publisher->publish($update);
}
public function publishOperatorStatusEvent(TicketOperator $operator, string $event)
{
$update = new Update(
$this->getOperatorStatusTopic($operator),
$this->serializer->serialize(
$operator,
'json',
[
AbstractNormalizer::IGNORED_ATTRIBUTES => [
'lastAssignedTicket',
'password',
'plainPassword',
'plainPasswordConfirmation',
'roles',
'salt',
'token',
]
]),
false,
null,
$event
);
$this->publish($update);
}
public function getTicketsTopic(TicketInterface $ticket = null): string
{
$id = $ticket ? $ticket->getId() : null;
return 'pk-tickets/' . ($id ?? '{id}');
}
public function getOperatorStatusTopic(TicketOperator $operator = null): string
{
$id = $operator ? $operator->getId() : null;
return 'ticket-operators/' . ($id ?? '{id}');
}
public function publishTicketEvent(TicketInterface $ticket, string $event)
{
$ticketOperator = $ticket->getCurrentStatus()->getOperator();
$update = new Update(
$this->getTicketsTopic($ticket),
json_encode([
'userId' => $ticketOperator ? $ticketOperator->getUser()->getId() : null,
'ticketId' => $ticket->getId(),
]),
false,
null,
$event
);
$this->publish($update);
}
}