diff --git a/mailpoet/lib/Entities/SubscriberEntity.php b/mailpoet/lib/Entities/SubscriberEntity.php index 919bbf15af..ac6ec5c64a 100644 --- a/mailpoet/lib/Entities/SubscriberEntity.php +++ b/mailpoet/lib/Entities/SubscriberEntity.php @@ -10,6 +10,7 @@ use MailPoet\Doctrine\EntityTraits\UpdatedAtTrait; use MailPoet\Util\Helpers; use MailPoetVendor\Doctrine\Common\Collections\ArrayCollection; use MailPoetVendor\Doctrine\Common\Collections\Collection; +use MailPoetVendor\Doctrine\Common\Collections\Criteria; use MailPoetVendor\Doctrine\ORM\Mapping as ORM; use MailPoetVendor\Symfony\Component\Validator\Constraints as Assert; @@ -460,6 +461,13 @@ class SubscriberEntity { return $this->subscriberTags; } + public function getSubscriberTag(TagEntity $tag): ?SubscriberTagEntity { + $criteria = Criteria::create() + ->where(Criteria::expr()->eq('tag', $tag)) + ->setMaxResults(1); + return $this->getSubscriberTags()->matching($criteria)->first() ?: null; + } + /** * @return float|null */ diff --git a/mailpoet/lib/Subscribers/SubscriberSaveController.php b/mailpoet/lib/Subscribers/SubscriberSaveController.php index 4acfafad7d..7994561520 100644 --- a/mailpoet/lib/Subscribers/SubscriberSaveController.php +++ b/mailpoet/lib/Subscribers/SubscriberSaveController.php @@ -8,10 +8,12 @@ use MailPoet\Doctrine\Validator\ValidationException; use MailPoet\Entities\StatisticsUnsubscribeEntity; use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberSegmentEntity; +use MailPoet\Entities\SubscriberTagEntity; use MailPoet\Newsletter\Scheduler\WelcomeScheduler; use MailPoet\Segments\SegmentsRepository; use MailPoet\Settings\SettingsController; use MailPoet\Statistics\Track\Unsubscribes; +use MailPoet\Tags\TagRepository; use MailPoet\Util\Security; use MailPoet\WP\Functions as WPFunctions; use MailPoetVendor\Carbon\Carbon; @@ -38,6 +40,12 @@ class SubscriberSaveController { /** @var SubscriberSegmentRepository */ private $subscriberSegmentRepository; + /** @var SubscriberTagRepository */ + private $subscriberTagRepository; + + /** @var TagRepository */ + private $tagRepository; + /** @var Unsubscribes */ private $unsubscribesTracker; @@ -55,6 +63,8 @@ class SubscriberSaveController { SubscriberCustomFieldRepository $subscriberCustomFieldRepository, SubscribersRepository $subscribersRepository, SubscriberSegmentRepository $subscriberSegmentRepository, + SubscriberTagRepository $subscriberTagRepository, + TagRepository $tagRepository, Unsubscribes $unsubscribesTracker, WelcomeScheduler $welcomeScheduler, WPFunctions $wp @@ -66,9 +76,11 @@ class SubscriberSaveController { $this->subscriberSegmentRepository = $subscriberSegmentRepository; $this->subscribersRepository = $subscribersRepository; $this->subscriberCustomFieldRepository = $subscriberCustomFieldRepository; + $this->tagRepository = $tagRepository; $this->unsubscribesTracker = $unsubscribesTracker; $this->welcomeScheduler = $welcomeScheduler; $this->wp = $wp; + $this->subscriberTagRepository = $subscriberTagRepository; } public function filterOutReservedColumns(array $subscriberData): array { @@ -107,6 +119,10 @@ class SubscriberSaveController { $data['segments'] = array_merge($data['segments'], $this->getNonDefaultSubscribedSegments($data)); $newSegments = $this->findNewSegments($data); + if (empty($data['tags'])) { + $data['tags'] = []; + } + $oldSubscriber = $this->findSubscriber($data); $oldStatus = $oldSubscriber ? $oldSubscriber->getStatus() : null; if ( @@ -131,6 +147,7 @@ class SubscriberSaveController { $subscriber = $this->createOrUpdate($data, $oldSubscriber); $this->updateCustomFields($data, $subscriber); + $this->updateTags($data, $subscriber); $segments = isset($data['segments']) ? $this->findSegments($data['segments']) : null; // check for status change @@ -277,4 +294,27 @@ class SubscriberSaveController { $this->subscriberCustomFieldRepository->createOrUpdate($subscriber, $customField, $customFieldsMap[$customField->getId()]); } } + + private function updateTags(array $data, SubscriberEntity $subscriber): void { + foreach ($subscriber->getSubscriberTags() as $subscriberTag) { + $tag = $subscriberTag->getTag(); + if (!$tag) { + continue; + } + if (!in_array($tag->getName(), $data['tags'], true)) { + $subscriber->getSubscriberTags()->removeElement($subscriberTag); + } + } + + foreach ($data['tags'] as $tagName) { + $tag = $this->tagRepository->createOrUpdate(['name' => $tagName]); + $subscriberTag = $subscriber->getSubscriberTag($tag); + if (!$subscriberTag) { + $subscriberTag = new SubscriberTagEntity($tag, $subscriber); + $subscriber->getSubscriberTags()->add($subscriberTag); + $this->subscriberTagRepository->persist($subscriberTag); + } + } + $this->subscriberTagRepository->flush(); + } } diff --git a/mailpoet/lib/Tags/TagRepository.php b/mailpoet/lib/Tags/TagRepository.php index 4d53170c87..422b7065ff 100644 --- a/mailpoet/lib/Tags/TagRepository.php +++ b/mailpoet/lib/Tags/TagRepository.php @@ -12,4 +12,24 @@ class TagRepository extends Repository { protected function getEntityClassName() { return TagEntity::class; } + + public function createOrUpdate(array $data = []): TagEntity { + if (!$data['name']) { + throw new \InvalidArgumentException('Missing name'); + } + $tag = $this->findOneBy([ + 'name' => $data['name'], + ]); + if (!$tag) { + $tag = new TagEntity($data['name']); + $this->persist($tag); + } + + try { + $this->flush(); + } catch (\Exception $e) { + throw new \RuntimeException("Error when saving tag " . $data['name']); + } + return $tag; + } }