<?php
declare(strict_types=1);
namespace App\Subscriber\Cinema;
use App\Action\Query\Cinema\GetCinemaDetailList\GetCinemaDetailListQuery;
use App\Event\Cinema\CinemaContextOnDemandEvent;
use App\Event\Cinema\CinemaWsdlLocationChangedEvent;
use App\Exception\Cinema\CinemaNotFoundException;
use App\Model\Cinema;
use App\Event\Cinema\CinemaContextChangedEvent;
use App\Service\Context\ContextInterface;
use App\Service\Factory\Client\CinemaClientFactory;
use App\Ws\Cinema\CinemaClient;
use App\WsProxy\WsProxy;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use ReflectionClass;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Stamp\HandledStamp;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class CinemaSubscriber implements EventSubscriberInterface
{
private WsProxy $wsProxy;
private EventDispatcherInterface $eventDispatcher;
private UuidInterface $posTypeId;
private ContextInterface $context;
private CinemaClient $cinemaClient;
private MessageBusInterface $messageBus;
private CinemaClientFactory $factory;
public function __construct(
WsProxy $wsProxy,
EventDispatcherInterface $eventDispatcher,
string $posTypeId,
ContextInterface $context,
CinemaClient $cinemaClient,
MessageBusInterface $messageBus,
CinemaClientFactory $factory,
)
{
$this->wsProxy = $wsProxy;
$this->eventDispatcher = $eventDispatcher;
$this->posTypeId = Uuid::fromString($posTypeId);
$this->context = $context;
$this->cinemaClient = $cinemaClient;
$this->messageBus = $messageBus;
$this->factory = $factory;
}
public static function getSubscribedEvents()
{
return [
CinemaContextOnDemandEvent::class => 'onDemand',
CinemaWsdlLocationChangedEvent::class => 'onLocationChanged'
];
}
public function onDemand(CinemaContextOnDemandEvent $event): void
{
$cinema = $this->messageBus->dispatch(new GetCinemaDetailListQuery())->last(HandledStamp::class)->getResult()->filter(
fn(Cinema $cinema) => strtolower((string)$cinema->getId()) === strtolower($event->getCinemaId())
)->first();
if ($cinema !== false) {
if ($cinema->getEndPointUrl() !== null) {
$this->eventDispatcher->dispatch(new CinemaWsdlLocationChangedEvent($cinema->getEndPointUrl()));
}
$this->wsProxy->setCinemaUrl($cinema->getEndPointUrl());
$this->wsProxy->setPosTypeId($this->posTypeId);
$this->context->setCinemaId($cinema->getId());
$this->context->setPOSTypeId($this->posTypeId);
$this->eventDispatcher->dispatch(new CinemaContextChangedEvent(
Uuid::fromString($event->getCinemaId()),
$cinema->getEndPointUrl()
));
} else {
throw new CinemaNotFoundException();
}
}
/**
* This method replace SOAP cinema client by client with new location (location get from Cinema object)
* It is solution instead of changeSoapLocation in old version of phpro/soap-client library
*/
public function onLocationChanged(CinemaWsdlLocationChangedEvent $event): void
{
/** @var CinemaClient $client */
$client = $this->factory->createClient($event->getLocation());
$reflectionClass = new ReflectionClass(CinemaClient::class);
$callerProperty = $reflectionClass->getProperty('caller');
$callerProperty->setAccessible(true);
$callerProperty->setValue($this->cinemaClient, $callerProperty->getValue($client));
}
}