<?php
namespace App\EventSubscriber\Webhooks;
use App\Entity\AssetOnline;
use App\Entity\VOD\Operator;
use App\Entity\VOD\OperatorWebhook;
use App\Entity\VOD\Title;
use App\Entity\VOD\TitleMediaFormat;
use App\Enum\PressSite\DomainLanguageEnum;
use App\Event\VOD\WebhookEvent;
use App\Service\Helper\Webhook\AssetOnlineTransformer;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Enqueue\Util\JSON;
use Ramsey\Uuid\Uuid;
class AssetSubscriber extends BaseWebhookSubscriber
{
private $transformer;
/**
* @var AssetOnline
*/
protected $entity;
public function __construct(EntityManagerInterface $entityManager, AssetOnlineTransformer $transformer)
{
parent::__construct($entityManager);
$this->transformer = $transformer;
}
public function process(WebhookEvent $event): void
{
parent::process($event);
$operatorRepo = $this->entityManager->getRepository(Operator::class);
if (!$this->entity instanceof AssetOnline) {
return;
}
$message = [];
$message['messageID'] = Uuid::uuid4()->toString();
$message['assetID'] = $this->entity->getAssetID();
$message['mediaIDs'] = $this->getMediaIds();
$message['formats'] = $this->getMediaFormats();
$message['eventName'] = $this->getEventName();
$message['timestamp'] = (new DateTime())->format(DateTime::ISO8601);
$message = array_merge($message, $this->transformer->transform($this->entity));
$message['topic'] = $this->getAssetType() . '-operation';
// Find operators that have access to entity.
$operators = [];
foreach ($this->entity->getAssociatedVodTitles() as $title) {
$operators = array_merge($operators, $operatorRepo->findEligibleOperatorsbyTitle($title));
}
// Remove operators with missing "asset image" contentType.
/* @var Operator $operator */
foreach ($operators as $key => $operator) {
if (($this->entity->isImageOrKeyArt() || $this->entity->isSubtitle())
&& !$operator->hasContentType($this->entity->getContentType())
) {
unset($operators[$key]);
}
}
switch ($this->event->getAction()) {
case 'create':
$operators = $this->filterOperatorsOnCreate($operators);
break;
case 'update':
$operators = $this->filterOperatorsOnUpdate($operators);
break;
case 'delete':
$operators = $this->filterOperatorsOnDelete($operators);
// If the asset is removed from an operator there is no need to send data about the assets location or
// properties.
unset(
$message['subTitleFile'],
$message['imageUrl'],
$message['size'],
);
break;
default:
return;
}
$this->addToQueue($operators, $message);
$event->stopPropagation();
}
protected function filterOperatorsOnCreate(array $operators): array
{
/** @var Operator $operator */
foreach ($operators as $index => $operator) {
if (!$this->operatorHasAssetLanguage($operator)) {
unset($operators[$index]);
}
}
return $operators;
}
protected function filterOperatorsOnUpdate(array $operators): array
{
/** @var Operator $operator */
foreach ($operators as $index => $operator) {
if (!$this->operatorHasAssetLanguage($operator)) {
unset($operators[$index]);
}
}
return $operators;
}
protected function filterOperatorsOnDelete(array $operators): array
{
/** @var Operator $operator */
foreach ($operators as $index => $operator) {
if (!$this->operatorHasAssetLanguage($operator)) {
unset($operators[$index]);
}
}
return $operators;
}
private function operatorHasAssetLanguage(Operator $operator): bool
{
$has_eligible_languages = false;
// Check if Operator has any of the languages, attached to the asset, assigned.
// Also, check if the country is enabled for export on the VOD Title.
$titles = $this->entity->getAssociatedVodTitles();
foreach ($this->entity->getLanguages() as $language_name) {
$language = array_search($language_name->__toString(), DomainLanguageEnum::readables(), true);
if ($language) {
$country = DomainLanguageEnum::getCountryByLanguage($language);
/** @var Title $title */
foreach ($titles as $title) {
if ($operator->hasCountryByCode($country) && in_array(
$country,
$title->getAllApprovedCountriesForExport(),
true
)) {
$has_eligible_languages = true;
$this->affected_countries[strtoupper($language)] = strtoupper($country);
}
}
}
}
return $has_eligible_languages;
}
protected function getMediaFormats(): array
{
$media_formats = $this->entity->getAssociatedVodTitles()->map(fn(Title $title) => $title->getMediaFormats()->map(fn(TitleMediaFormat $format) => $format->getFormat())->toArray())->toArray();
if (!empty($media_formats)) {
return reset($media_formats);
}
return [];
}
protected function getMediaIds(): array
{
$media_ids = $this->entity->getAssociatedVodTitles()->map(fn(Title $title) => $title->getMediaFormats()->map(fn(TitleMediaFormat $format) => $format->getId())->toArray())->toArray();
if (!empty($media_ids)) {
return reset($media_ids);
}
return [];
}
protected function getEventName(): string
{
return $this->getAssetType() . '-' . $this->event->getAction() . 'd';
}
protected function getAssetType(): string
{
return ($this->entity->isImageOrKeyArt()) ? 'image' : 'subtitle';
}
protected function addToQueue($operators, $message): void
{
/** @var Operator $operator */
foreach ($operators as $operator) {
$personalized_message = $this->personalizeMessage($operator, $message);
/* @var OperatorWebhook $webhook */
foreach ($operator->getWebhooks() as $webhook) {
if (in_array($message['topic'], $webhook->getTopics(), true)) {
$personalized_message_json = JSON::encode($personalized_message);
if (empty($this->messagesSent[$operator->getId()][$personalized_message['messageID']])) {
$this->messagesSent[$operator->getId()]
[$personalized_message['messageID']] =
$personalized_message_json;
$now = (new \DateTime())->format('Y-m-d H:i:s');
$sql = "INSERT INTO `vod_operator_webhook_log`(`created_at`, `webhook_id`, `request_body`)
VALUES ('{$now}',{$webhook->getId()},'{$personalized_message_json}')";
$this->entityManager->getConnection()->executeQuery($sql);
}
}
}
}
}
}