custom/plugins/CrswCleverReachOfficial/src/Subscriber/NewsletterRecipients/NewsletterRecipientSubscriber.php line 176

Open in your IDE?
  1. <?php
  2. namespace Crsw\CleverReachOfficial\Subscriber\NewsletterRecipients;
  3. use Crsw\CleverReachOfficial\Components\EventHandlers\RecipientHandler;
  4. use Crsw\CleverReachOfficial\Components\EventHandlers\TagHandler;
  5. use Crsw\CleverReachOfficial\Components\Utility\Bootstrap;
  6. use Crsw\CleverReachOfficial\Components\Utility\Initializer;
  7. use Crsw\CleverReachOfficial\Core\BusinessLogic\Receiver\DTO\Tag\Special\Subscriber;
  8. use Crsw\CleverReachOfficial\Core\BusinessLogic\Receiver\DTO\Tag\Tag;
  9. use Crsw\CleverReachOfficial\Entity\Customer\Repositories\SubscriberRepository;
  10. use Crsw\CleverReachOfficial\Entity\Tag\Repositories\TagRepository;
  11. use Crsw\CleverReachOfficial\Service\BusinessLogic\SalesChannel\SalesChannelContextService;
  12. use Shopware\Core\Content\Newsletter\Event\NewsletterConfirmEvent;
  13. use Shopware\Core\Content\Newsletter\NewsletterEvents;
  14. use Shopware\Core\Framework\Context;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityDeletedEvent;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  17. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  18. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  21. use Symfony\Component\HttpKernel\KernelEvents;
  22. /**
  23.  * Class NewsletterRecipientSubscriber
  24.  *
  25.  * @package Crsw\CleverReachOfficial\Subscriber\NewsletterRecipients
  26.  */
  27. class NewsletterRecipientSubscriber implements EventSubscriberInterface
  28. {
  29.     /**
  30.      * Emails stored before newsletter recipient is deleted/changed
  31.      *
  32.      * @var array
  33.      */
  34.     private static $previousEmails = [];
  35.     /**
  36.      * Emails that have been changed on newsletter recipient update.
  37.      *
  38.      * @var array
  39.      */
  40.     private static $newEmails = [];
  41.     /**
  42.      * Emails of customer that unsubscribed.
  43.      *
  44.      * @var array
  45.      */
  46.     private static $deactivatedEmails = [];
  47.     /**
  48.      * @var RecipientHandler
  49.      */
  50.     private $recipientHandler;
  51.     /**
  52.      * @var SubscriberRepository
  53.      */
  54.     private $subscriberRepository;
  55.     /**
  56.      * @var TagHandler
  57.      */
  58.     private $tagHandler;
  59.     /**
  60.      * @var TagRepository
  61.      */
  62.     private $tagRepository;
  63.     /**
  64.      * @var SalesChannelContextService
  65.      */
  66.     private $salesChannelContextService;
  67.     /**
  68.      * NewsletterRecipientSubscriber constructor.
  69.      *
  70.      * @param RecipientHandler $recipientHandler
  71.      * @param SubscriberRepository $subscriberRepository
  72.      * @param Initializer $initializer
  73.      * @param TagHandler $tagHandler
  74.      * @param TagRepository $tagRepository
  75.      * @param SalesChannelContextService $salesChannelContextService
  76.      */
  77.     public function __construct(
  78.         RecipientHandler $recipientHandler,
  79.         SubscriberRepository $subscriberRepository,
  80.         Initializer $initializer,
  81.         TagHandler $tagHandler,
  82.         TagRepository $tagRepository,
  83.         SalesChannelContextService $salesChannelContextService
  84.     ) {
  85.         Bootstrap::register();
  86.         $initializer->registerServices();
  87.         $this->recipientHandler $recipientHandler;
  88.         $this->subscriberRepository $subscriberRepository;
  89.         $this->tagHandler $tagHandler;
  90.         $this->tagRepository $tagRepository;
  91.         $this->salesChannelContextService $salesChannelContextService;
  92.     }
  93.     /**
  94.      * @inheritDoc
  95.      */
  96.     public static function getSubscribedEvents(): array
  97.     {
  98.         return [
  99.             NewsletterEvents::NEWSLETTER_CONFIRM_EVENT => 'onNewsletterConfirm',
  100.             NewsletterEvents::NEWSLETTER_RECIPIENT_WRITTEN_EVENT => 'onNewsletterSave',
  101.             NewsletterEvents::NEWSLETTER_RECIPIENT_DELETED_EVENT => 'onNewsletterDelete',
  102.             KernelEvents::CONTROLLER => 'saveDataForDelete',
  103.             'newsletter_recipient_tag.deleted' => 'onNewsletterTagDelete',
  104.         ];
  105.     }
  106.     /**
  107.      * Newsletter confirmation by email.
  108.      *
  109.      * @param NewsletterConfirmEvent $event
  110.      */
  111.     public function onNewsletterConfirm(NewsletterConfirmEvent $event): void
  112.     {
  113.         if (!$this->recipientHandler->canHandle()) {
  114.             return;
  115.         }
  116.         $recipient $event->getNewsletterRecipient();
  117.         $this->recipientHandler->recipientSubscribedEvent($recipient->getEmail());
  118.     }
  119.     /**
  120.      * Newsletter recipient updated by administrator.
  121.      *
  122.      * @param EntityWrittenEvent $event
  123.      */
  124.     public function onNewsletterSave(EntityWrittenEvent $event): void
  125.     {
  126.         if (!$this->recipientHandler->canHandle()) {
  127.             return;
  128.         }
  129.         $writeResults $event->getWriteResults();
  130.         $this->handleSubscriberChangeEvent($writeResults$event);
  131.         $this->tagHandler->tagCreated();
  132.     }
  133.     /**
  134.      * Newsletter deleted by administrator.
  135.      *
  136.      * @param EntityDeletedEvent $event
  137.      */
  138.     public function onNewsletterDelete(EntityDeletedEvent $event): void
  139.     {
  140.         if (!$this->recipientHandler->canHandle()) {
  141.             return;
  142.         }
  143.         $ids $event->getIds();
  144.         $subscribers $this->subscriberRepository->getByIds($ids$event->getContext());
  145.         static::$previousEmails array_merge(static::$previousEmails, static::$deactivatedEmails);
  146.         foreach ($subscribers as $subscriber) {
  147.             static::$previousEmails[] = $subscriber->getEmail();
  148.         }
  149.         foreach (static::$previousEmails as $email) {
  150.             $this->recipientHandler->resyncRecipient([$email], [new Subscriber('Shopware 6')]);
  151.             $this->recipientHandler->recipientDeletedEvent($email);
  152.         }
  153.         static::$previousEmails = [];
  154.     }
  155.     /**
  156.      * @param ControllerEvent $event
  157.      */
  158.     public function saveDataForDelete(ControllerEvent $event): void
  159.     {
  160.         $request $event->getRequest();
  161.         if ($request->get('_route') === 'frontend.account.newsletter' &&
  162.             !$request->get('option'false)) {
  163.             $this->savePreviousEmailFromContext($request);
  164.             return;
  165.         }
  166.         if (in_array(
  167.             $request->get('_route'),
  168.             ['api.newsletter_recipient.delete''api.newsletter_recipient.update'],
  169.             true
  170.         )) {
  171.             $path $request->get('path');
  172.             // check if route contains subpaths
  173.             if (!strpos($path'/')) {
  174.                 $this->saveEmailForDelete(
  175.                     $path,
  176.                     $event->getRequest()->get('sw-context') ?: Context::createDefaultContext()
  177.                 );
  178.             }
  179.         }
  180.     }
  181.     /**
  182.      * Newsletter tag deleted.
  183.      *
  184.      * @param EntityDeletedEvent $event
  185.      */
  186.     public function onNewsletterTagDelete(EntityDeletedEvent $event): void
  187.     {
  188.         $newsletterIds = [];
  189.         $payloads $event->getPayloads();
  190.         $tagsForDelete = [];
  191.         foreach ($payloads as $payload) {
  192.             if (array_key_exists('newsletterRecipientId'$payload)) {
  193.                 $newsletterIds[] = $payload['newsletterRecipientId'];
  194.                 $tagsForDelete[$payload['newsletterRecipientId']] = array_key_exists('tagId'$payload)
  195.                     ? $payload['tagId'] : '';
  196.             }
  197.         }
  198.         $this->updateRecipients($newsletterIds$event->getContext(), $tagsForDelete);
  199.         $this->tagHandler->resyncSegments();
  200.     }
  201.     /**
  202.      * Check if email changed and deactivates recipients with old email address
  203.      *
  204.      * @param array $sourceIds
  205.      */
  206.     private function deactivateOldEmails(array $sourceIds): void
  207.     {
  208.         $emailsForDeactivation = static::$deactivatedEmails;
  209.         foreach ($sourceIds as $id) {
  210.             if ($this->isEmailChanged($id)) {
  211.                 $emailsForDeactivation[] = static::$previousEmails[$id];
  212.             }
  213.         }
  214.         foreach ($emailsForDeactivation as $email) {
  215.             $this->recipientHandler->recipientDeletedEvent($email);
  216.         }
  217.     }
  218.     /**
  219.      * Check if newsletter recipient email changed
  220.      *
  221.      * @param string $id
  222.      *
  223.      * @return bool
  224.      */
  225.     private function isEmailChanged(string $id): bool
  226.     {
  227.         return !empty(self::$previousEmails)
  228.             && !empty(self::$newEmails)
  229.             && self::$previousEmails[$id] !== self::$newEmails[$id];
  230.     }
  231.     /**
  232.      * @param array $sourceIds
  233.      * @param Context $context
  234.      * @param array|null $tagIds
  235.      */
  236.     private function updateRecipients(array $sourceIdsContext $context, ?array $tagIds): void
  237.     {
  238.         $emailsForCreate = [];
  239.         $newsletterRecipients $this->subscriberRepository->getByIds($sourceIds$context);
  240.         foreach ($newsletterRecipients as $entity) {
  241.             if ($entity->getStatus() === 'optOut') {
  242.                 $this->recipientHandler->recipientUnsubscribedEvent($entity->getEmail());
  243.                 continue;
  244.             }
  245.             if ($this->isEmailChanged($entity->getId())) {
  246.                 $this->recipientHandler->recipientUnsubscribedEvent(self::$previousEmails[$entity->getId()]);
  247.                 $emailsForCreate[$entity->getId()] = self::$newEmails[$entity->getId()];
  248.                 unset(
  249.                     self::$newEmails[$entity->getId()],
  250.                     self::$previousEmails[$entity->getId()]
  251.                 );
  252.             } else {
  253.                 $emailsForCreate[$entity->getId()] = $entity->getEmail();
  254.             }
  255.         }
  256.         foreach ($emailsForCreate as $key => $email) {
  257.             $crTag '';
  258.             if (!empty($tagIds[$key])) {
  259.                 $tag $this->tagRepository->getTagById($tagIds[$key], $context);
  260.                 $crTag = new Tag('Shopware 6'$tag->getName());
  261.                 $crTag->setType('Tag');
  262.             }
  263.             $this->recipientHandler->resyncRecipient([$email], $crTag ? [$crTag] : []);
  264.         }
  265.     }
  266.     /**
  267.      * @param Request $request
  268.      */
  269.     private function savePreviousEmailFromContext(Request $request): void
  270.     {
  271.         /** @var SalesChannelContext $salesChannelContext */
  272.         $salesChannelContext $request->get('sw-sales-channel-context') ?:
  273.             $this->salesChannelContextService->getSalesChannelContext($request);
  274.         if ($salesChannelContext) {
  275.             $customer $salesChannelContext->getCustomer();
  276.             if ($customer) {
  277.                 $id $this->subscriberRepository->getByEmail($customer->getEmail())['subscriberId'];
  278.                 static::$deactivatedEmails[bin2hex($id)] = $customer->getEmail();
  279.             }
  280.         }
  281.     }
  282.     /**
  283.      * @param string|null $id
  284.      * @param Context $context
  285.      */
  286.     private function saveEmailForDelete(?string $idContext $context): void
  287.     {
  288.         if (!$id) {
  289.             return;
  290.         }
  291.         $newsletterRecipient $this->subscriberRepository->getByIds([$id], $context)->first();
  292.         if ($newsletterRecipient) {
  293.             static::$previousEmails[$id] = $newsletterRecipient->getEmail();
  294.         }
  295.     }
  296.     /**
  297.      * @param array $writeResults
  298.      * @param EntityWrittenEvent $event
  299.      */
  300.     private function handleSubscriberChangeEvent(array $writeResultsEntityWrittenEvent $event): void
  301.     {
  302.         $emailsForCreate = [];
  303.         foreach ($writeResults as $writeResult) {
  304.             $payload $writeResult->getPayload();
  305.             if (!array_key_exists('id'$payload)) {
  306.                 continue;
  307.             }
  308.             $id $payload['id'];
  309.             if (empty($payload['email'])) {
  310.                 continue;
  311.             }
  312.             $email $payload['email'];
  313.             self::$newEmails[$id] = $email;
  314.             if (array_key_exists('status'$payload) && $payload['status'] === 'optOut') {
  315.                 $this->recipientHandler->recipientUnsubscribedEvent($email);
  316.                 continue;
  317.             }
  318.             if ($this->isEmailChanged($id)) {
  319.                 $this->recipientHandler->recipientUnsubscribedEvent(self::$previousEmails[$id]);
  320.                 $emailsForCreate[$id] = self::$newEmails[$id];
  321.                 unset(
  322.                     self::$newEmails[$id],
  323.                     self::$previousEmails[$id]
  324.                 );
  325.             } else {
  326.                 $emailsForCreate[$id] = $email;
  327.             }
  328.         }
  329.         $sourceIds $event->getIds();
  330.         $this->deactivateOldEmails($sourceIds);
  331.         if (!$emailsForCreate) {
  332.             $this->updateRecipients($sourceIds$event->getContext(), null);
  333.         }
  334.         foreach ($emailsForCreate as $email) {
  335.             $this->recipientHandler->resyncRecipient([$email]);
  336.         }
  337.     }
  338. }