src/EventSubscriber/Webhooks/MetaSubscriber.php line 43

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber\Webhooks;
  3. use App\Entity\VOD\Operator;
  4. use App\Entity\VOD\OperatorCountry;
  5. use App\Entity\VOD\OperatorWebhook;
  6. use App\Entity\VOD\OperatorWebhookLog;
  7. use App\Entity\VOD\Order;
  8. use App\Entity\VOD\OrderCountry;
  9. use App\Entity\VOD\OrderDetail;
  10. use App\Entity\VOD\Title;
  11. use App\Entity\VOD\TitleExcludedOperator;
  12. use App\Entity\VOD\TitleLocalizedText;
  13. use App\Entity\VOD\TitleMediaFormat;
  14. use App\Enum\PressSite\DomainLanguageEnum;
  15. use App\Event\VOD\WebhookEvent;
  16. use DateTime;
  17. use Doctrine\ORM\EntityManagerInterface;
  18. use Enqueue\Util\JSON;
  19. use Ramsey\Uuid\Uuid;
  20. class MetaSubscriber extends BaseWebhookSubscriber
  21. {
  22.     /**
  23.      * @var Title
  24.      */
  25.     protected $entity;
  26.     /**
  27.      * @var Order|null
  28.      */
  29.     private $order;
  30.     private $ordersOnTitle = [];
  31.     public function __construct(EntityManagerInterface $entityManager)
  32.     {
  33.         parent::__construct($entityManager);
  34.     }
  35.     public function process(WebhookEvent $event): void
  36.     {
  37.         parent::process($event);
  38.         $this->order $event->getOrder();
  39.         $operatorRepo $this->entityManager->getRepository(Operator::class);
  40.         if (!($this->entity instanceof Title)) {
  41.             return;
  42.         }
  43.         $message = [];
  44.         $message['messageID'] = Uuid::uuid4()->toString();
  45.         $message['topic'] = 'metadata-operation';
  46.         $message['entityLabel'] = $this->getEntityLabel();
  47.         $message['mediaIDs'] = $this->getMediaIds();
  48.         $message['formats'] = $this->getMediaFormats();
  49.         $message['eventName'] = $this->getEventName();
  50.         $message['timestamp'] = (new DateTime())->format(DateTime::ISO8601);
  51.         
  52.         $operators $operatorRepo->findEligibleOperatorsbyTitle($this->entity);
  53.         $this->ordersOnTitle $this->entityManager->createQueryBuilder()
  54.             ->select('o')
  55.             ->from(Order::class, 'o')
  56.             ->where('o.title = :title')
  57.             ->andWhere('o.closed = true')
  58.             ->setParameter('title'$this->entity)
  59.             ->getQuery()
  60.             ->getResult();
  61.         switch ($this->event->getAction()) {
  62.             case 'create':
  63.                 $operators array_unique(
  64.                     array_merge(
  65.                         $this->filterOperatorsOnCreate($operators),
  66.                         $operatorRepo->findBy(['id' => $event->getOperators()])
  67.                     )
  68.                 );
  69.                 $this->addToQueue($operators$message);
  70.                 break;
  71.             case 'update':
  72.                 $operators array_unique(
  73.                     array_merge(
  74.                         $this->filterOperatorsOnUpdate($operators),
  75.                         $operatorRepo->findBy(['id' => $event->getOperators()])
  76.                     )
  77.                 );
  78.                 $this->addToQueue($operators$message);
  79.                 break;
  80.             case 'delete':
  81.                 $operators array_unique(
  82.                     array_merge(
  83.                         $this->filterOperatorsOnDelete($operators),
  84.                         $operatorRepo->findBy(['id' => $event->getOperators()])
  85.                     )
  86.                 );
  87.                 $this->addToQueue($operators$message);
  88.                 break;
  89.             default:
  90.                 return;
  91.         }
  92.         $event->stopPropagation();
  93.     }
  94.     protected function filterOperatorsOnCreate(array $operators): array
  95.     {
  96.         // If the title got created, through an order, extract the operators and languages here.
  97.         if (!empty($this->order)) {
  98.             $this->ordersOnTitle[] = $this->order;
  99.             // Remove all operators. They are useless, and the affected operators are set in the event class.
  100.             $operators = [];
  101.             /** @var OrderCountry $country */
  102.             foreach ($this->order->getCountries() as $country) {
  103.                 $language DomainLanguageEnum::getLanguageByCountry($country->getCountry());
  104.                 $this->affected_countries[$language] = $country->getCountry();
  105.             }
  106.             return $operators;
  107.         }
  108.         // This will catch any operator, that is being _removed_ from the exclude list.
  109.         $included_operators $this->entityManager->getUnitOfWork()->getScheduledEntityDeletions();
  110.         foreach ($included_operators as $included_operator) {
  111.             if ($included_operator instanceof TitleExcludedOperator) {
  112.                 foreach ($included_operator->getCountries() as $country) {
  113.                     if (in_array($country$this->entity->getAllApprovedCountriesForExport())) {
  114.                         $this->affected_countries[DomainLanguageEnum::getLanguageByCountry($country)] = $country;
  115.                     }
  116.                 }
  117.             }
  118.         }
  119.         // If the metadata of the VOD title was created through enabling a language, find the localized languages that
  120.         // are enabled.
  121.         /** @var TitleLocalizedText $localizedText */
  122.         foreach ($this->entity->getLocalizedTexts() as $localizedText) {
  123.             $change_set $this->entityManager->getUnitOfWork()->getEntityChangeSet($localizedText);
  124.             $country DomainLanguageEnum::getCountryByLanguage($localizedText->getLanguage());
  125.             if (!empty($change_set)) {
  126.                 if ($localizedText->isExportApproved()) {
  127.                     $this->affected_countries[$localizedText->getLanguage()] = $country;
  128.                 }
  129.             }
  130.         }
  131.         // As a last resort, return an unmodified list of operators.
  132.         return $operators;
  133.     }
  134.     protected function filterOperatorsOnUpdate(array $operators): array
  135.     {
  136.         // If the VOD title it-self was not update, start calculating what languages that was affected.
  137.         if (empty($this->entityManager->getUnitOfWork()->getEntityChangeSet($this->entity))) {
  138.             // Check if the individual operators has the changed language available. If not, remove them from the list.
  139.             $country_updated = [];
  140.             foreach ($this->entity->getLocalizedTexts() as $localizedText) {
  141.                 $change_set $this->entityManager->getUnitOfWork()->getEntityChangeSet($localizedText);
  142.                 $country DomainLanguageEnum::getCountryByLanguage($localizedText->getLanguage());
  143.                 if (!empty($change_set)) {
  144.                     $country_updated[] = $country;
  145.                     if ($localizedText->isExportApproved()) {
  146.                         $this->affected_countries[$localizedText->getLanguage()] = $country;
  147.                     }
  148.                 }
  149.             }
  150.             if (!empty($country_updated)) {
  151.                 /** @var Operator $operator */
  152.                 foreach ($operators as $index => $operator) {
  153.                     // Run through all the languages that was updated and make sure that the operator is supporting the
  154.                     // language in question.
  155.                     $operator_eligible_for_deleted_language false;
  156.                     foreach ($country_updated as $country) {
  157.                         if ($operator->hasCountryByCode($country)) {
  158.                             $operator_eligible_for_deleted_language true;
  159.                             break;
  160.                         }
  161.                     }
  162.                     if (!$operator_eligible_for_deleted_language) {
  163.                         unset($operators[$index]);
  164.                     }
  165.                 }
  166.                 return $operators;
  167.             }
  168.         }
  169.         // If the metadata of the VOD title was updated, find the localized languages that are enabled.
  170.         /** @var TitleLocalizedText $localizedText */
  171.         foreach ($this->entity->getLocalizedTexts() as $localizedText) {
  172.             if ($localizedText->isExportApproved()) {
  173.                 $country DomainLanguageEnum::getCountryByLanguage($localizedText->getLanguage());
  174.                 $this->affected_countries[$localizedText->getLanguage()] = $country;
  175.             }
  176.         }
  177.         // As a last resort, return an unmodified list of operators.
  178.         return $operators;
  179.     }
  180.     protected function filterOperatorsOnDelete(array $operators): array
  181.     {
  182.         // In cases where we are dealing with a localized text that has been disabled, find out which language that
  183.         // was removed and save it for later
  184.         $country_disabled = [];
  185.         foreach ($this->entity->getLocalizedTexts() as $localizedText) {
  186.             $change_set $this->entityManager->getUnitOfWork()->getEntityChangeSet($localizedText);
  187.             $country DomainLanguageEnum::getCountryByLanguage($localizedText->getLanguage());
  188.             if (!empty($change_set['exportApproved']) &&
  189.                 $change_set['exportApproved'][0] === true &&
  190.                 !in_array($country$country_disabledfalse)) {
  191.                 $country_disabled[] = $country;
  192.                 $this->affected_countries[$localizedText->getLanguage()] = $country;
  193.             }
  194.         }
  195.         // If $country_disabled is not empty it means that we are dealing with a deleted localized text.
  196.         // Not a deleted title.
  197.         if (!empty($country_disabled)) {
  198.             /** @var Operator $operator */
  199.             foreach ($operators as $index => $operator) {
  200.                 // Run through all the languages that was deleted and make sure that the operator is supporting the
  201.                 // language in question.
  202.                 $operator_eligible_for_deleted_language false;
  203.                 foreach ($country_disabled as $country) {
  204.                     if ($operator->hasCountryByCode($country)) {
  205.                         $operator_eligible_for_deleted_language true;
  206.                         break;
  207.                     }
  208.                 }
  209.                 if (!$operator_eligible_for_deleted_language) {
  210.                     unset($operators[$index]);
  211.                 }
  212.             }
  213.             return $operators;
  214.         }
  215.         // If the title got deleted, through an order, extract the operators and languages here.
  216.         if (!empty($this->order)) {
  217.             $this->ordersOnTitle[] = $this->order;
  218.             // Remove all operators. They are useless, and the affected operators are set in the event class.
  219.             $operators = [];
  220.             /** @var OrderCountry $country */
  221.             foreach ($this->order->getCountries() as $country) {
  222.                 $language DomainLanguageEnum::getLanguageByCountry($country->getCountry());
  223.                 $this->affected_countries[$language] = $country->getCountry();
  224.             }
  225.             return $operators;
  226.         }
  227.         // If the operator was excluded from the VOD title, fetch all the available languages from the title.
  228.         $excluded_operators $this->entityManager->getUnitOfWork()->getScheduledEntityInsertions();
  229.         foreach ($excluded_operators as $excluded_operator) {
  230.             if ($excluded_operator instanceof TitleExcludedOperator) {
  231.                 foreach ($excluded_operator->getCountries() as $country) {
  232.                     if (in_array($country$this->entity->getAllApprovedCountriesForExport())) {
  233.                         $this->affected_countries[DomainLanguageEnum::getLanguageByCountry($country)] = $country;
  234.                     }
  235.                 }
  236.             }
  237.         }
  238.         // As a last resort, return an unmodified list of operators.
  239.         return $operators;
  240.     }
  241.     protected function getMediaFormats(): array
  242.     {
  243.         return $this->entity->getMediaFormats()->map(fn($format) => $format->getFormat())->toArray();
  244.     }
  245.     protected function getEntityLabel(): ?string
  246.     {
  247.         return $this->entity->getOriginalTitle();
  248.     }
  249.     protected function getEventName(): string
  250.     {
  251.         return 'metadata-' $this->event->getAction() . 'd';
  252.     }
  253.     protected function getMediaIds(): array
  254.     {
  255.         return $this->entity->getMediaFormats()->map(fn(TitleMediaFormat $format) => $format->getId())->toArray();
  256.     }
  257.     protected function addToQueue($operators$message): void
  258.     {
  259.         /** @var Operator $operator */
  260.         foreach ($operators as $operator) {
  261.             if (!empty($operator->getWebhooks()->toArray())) {
  262.                 $personalized_message $this->personalizeMessage($operator$message);
  263.                 // Remove languages from the message, if there is no closed order for that language.
  264.                 if (!empty($personalized_message['country'])) {
  265.                     foreach ($personalized_message['country'] as $index => $country) {
  266.                         $order_country_exists false;
  267.                         /** @var Order $order */
  268.                         foreach ($this->ordersOnTitle as $order) {
  269.                             /** @var OrderDetail $order_detail */
  270.                             foreach ($order->getDetails() as $order_detail) {
  271.                                 if ($order_detail->getOperator() !== null) {
  272.                                     if ($order_detail->getOperator()->getId() === $operator->getId()) {
  273.                                         foreach ($order->getCountriesAsArray() as $order_country) {
  274.                                             if ($order_country === $country) {
  275.                                                 $order_country_exists true;
  276.                                                 break;
  277.                                             }
  278.                                         }
  279.                                     }
  280.                                 }
  281.                             }
  282.                         }
  283.                         if (!$order_country_exists) {
  284.                             unset($personalized_message['country'][$index], $personalized_message['language'][$index]);
  285.                         }
  286.                     }
  287.                 }
  288.                 $personalized_message['country'] = array_values($personalized_message['country']);
  289.                 $personalized_message['language'] = array_values($personalized_message['language']);
  290.                 // Only continue, if there is a language set in the personalized message.
  291.                 // If the country is missing this message is no longer relevant to the operator.
  292.                 if (!empty($personalized_message['country'])) {
  293.                     /* @var OperatorWebhook $webhook */
  294.                     foreach ($operator->getWebhooks() as $webhook) {
  295.                         // Add header key and Value to the logs if they exist in their
  296.                         // fields on the operator's tab. VOD -> Operators -> Webhook tab
  297.                         if ($webhook->getHeaderKey() && $webhook->getHeaderValue()) {
  298.                             $headerKey $webhook->getHeaderKey();
  299.                             $headerValue $webhook->getHeaderValue();
  300.                             $personalized_message[$headerKey] = $headerValue;
  301.                         }
  302.                         if (in_array($message['topic'], $webhook->getTopics(), true)) {
  303.                             $personalized_message_json JSON::encode($personalized_message);
  304.                             if (empty($this->messagesSent[$operator->getId()][$personalized_message['messageID']])) {
  305.                                 $this->messagesSent[$operator->getId()][$personalized_message['messageID']] =
  306.                                     $personalized_message_json;
  307.                                 $now = (new \DateTime())->format('Y-m-d H:i:s');
  308.                                 // We run this entity insert around Doctrine to avoid infinite loops from the
  309.                                 // event listeners.
  310.                                 $sql "INSERT INTO `vod_operator_webhook_log`"
  311.                                     ." (`created_at`, `webhook_id`, `request_body`) "
  312.                                     ."VALUES ('{$now}',{$webhook->getId()},'{$personalized_message_json}')";
  313.                                 $this->entityManager->getConnection()->executeQuery($sql);
  314.                             }
  315.                         }
  316.                     }
  317.                 }
  318.             }
  319.         }
  320.     }
  321. }