AutomaticEmailScheduler.php
2 years ago
AutomationEmailScheduler.php
1 year ago
PostNotificationScheduler.php
2 years ago
ReEngagementScheduler.php
1 year ago
Scheduler.php
1 year ago
WelcomeScheduler.php
2 years ago
index.php
3 years ago
AutomaticEmailScheduler.php
196 lines
| 1 | <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing |
| 2 | |
| 3 | namespace MailPoet\Newsletter\Scheduler; |
| 4 | |
| 5 | if (!defined('ABSPATH')) exit; |
| 6 | |
| 7 | |
| 8 | use MailPoet\Cron\Workers\SendingQueue\SendingQueue; |
| 9 | use MailPoet\Entities\NewsletterEntity; |
| 10 | use MailPoet\Entities\NewsletterOptionFieldEntity; |
| 11 | use MailPoet\Entities\ScheduledTaskEntity; |
| 12 | use MailPoet\Entities\ScheduledTaskSubscriberEntity; |
| 13 | use MailPoet\Entities\SendingQueueEntity; |
| 14 | use MailPoet\Entities\SubscriberEntity; |
| 15 | use MailPoet\Newsletter\Sending\ScheduledTasksRepository; |
| 16 | use MailPoet\Newsletter\Sending\ScheduledTaskSubscribersRepository; |
| 17 | use MailPoet\Newsletter\Sending\SendingQueuesRepository; |
| 18 | |
| 19 | class AutomaticEmailScheduler { |
| 20 | |
| 21 | /** @var Scheduler */ |
| 22 | private $scheduler; |
| 23 | |
| 24 | /** @var ScheduledTasksRepository */ |
| 25 | private $scheduledTasksRepository; |
| 26 | |
| 27 | /** @var SendingQueuesRepository */ |
| 28 | private $sendingQueuesRepository; |
| 29 | |
| 30 | /** @var ScheduledTaskSubscribersRepository */ |
| 31 | private $scheduledTaskSubscribersRepository; |
| 32 | |
| 33 | public function __construct( |
| 34 | Scheduler $scheduler, |
| 35 | ScheduledTasksRepository $scheduledTasksRepository, |
| 36 | ScheduledTaskSubscribersRepository $scheduledTaskSubscribersRepository, |
| 37 | SendingQueuesRepository $sendingQueuesRepository |
| 38 | ) { |
| 39 | $this->scheduler = $scheduler; |
| 40 | $this->scheduledTasksRepository = $scheduledTasksRepository; |
| 41 | $this->scheduledTaskSubscribersRepository = $scheduledTaskSubscribersRepository; |
| 42 | $this->sendingQueuesRepository = $sendingQueuesRepository; |
| 43 | } |
| 44 | |
| 45 | public function scheduleAutomaticEmail( |
| 46 | string $group, |
| 47 | string $event, |
| 48 | ?callable $schedulingCondition = null, |
| 49 | ?SubscriberEntity $subscriber = null, |
| 50 | ?array $meta = null, |
| 51 | ?callable $metaModifier = null |
| 52 | ) { |
| 53 | $newsletters = $this->scheduler->getNewsletters(NewsletterEntity::TYPE_AUTOMATIC, $group); |
| 54 | if (empty($newsletters)) return false; |
| 55 | foreach ($newsletters as $newsletter) { |
| 56 | if ($newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_EVENT) !== $event) continue; |
| 57 | if (is_callable($schedulingCondition) && !$schedulingCondition($newsletter)) continue; |
| 58 | |
| 59 | /** |
| 60 | * $meta will be the same for all newsletters by default. If we need to store newsletter-specific meta, the |
| 61 | * $metaModifier callback can be used. |
| 62 | * |
| 63 | * This was introduced because of WooCommerce product purchase automatic emails. We only want to store the |
| 64 | * product IDs that specifically triggered a newsletter, but $meta includes ALL the product IDs |
| 65 | * or category IDs from an order. |
| 66 | */ |
| 67 | if (is_callable($metaModifier)) { |
| 68 | $meta = $metaModifier($newsletter, $meta); |
| 69 | } |
| 70 | $this->createAutomaticEmailScheduledTask($newsletter, $subscriber, $meta); |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | public function scheduleOrRescheduleAutomaticEmail(string $group, string $event, SubscriberEntity $subscriber, array $meta): void { |
| 75 | $newsletters = $this->scheduler->getNewsletters(NewsletterEntity::TYPE_AUTOMATIC, $group); |
| 76 | if (empty($newsletters)) { |
| 77 | return; |
| 78 | } |
| 79 | |
| 80 | foreach ($newsletters as $newsletter) { |
| 81 | if ($newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_EVENT) !== $event) { |
| 82 | continue; |
| 83 | } |
| 84 | |
| 85 | // try to find existing scheduled task for given subscriber |
| 86 | $task = $this->scheduledTasksRepository->findOneScheduledByNewsletterAndSubscriber($newsletter, $subscriber); |
| 87 | if ($task) { |
| 88 | $this->rescheduleAutomaticEmailSendingTask($newsletter, $task, $meta); |
| 89 | } else { |
| 90 | $this->createAutomaticEmailScheduledTask($newsletter, $subscriber, $meta); |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | public function rescheduleAutomaticEmail(string $group, string $event, SubscriberEntity $subscriber): void { |
| 96 | $newsletters = $this->scheduler->getNewsletters(NewsletterEntity::TYPE_AUTOMATIC, $group); |
| 97 | if (empty($newsletters)) { |
| 98 | return; |
| 99 | } |
| 100 | |
| 101 | foreach ($newsletters as $newsletter) { |
| 102 | if ($newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_EVENT) !== $event) { |
| 103 | continue; |
| 104 | } |
| 105 | |
| 106 | // try to find existing scheduled task for given subscriber |
| 107 | $task = $this->scheduledTasksRepository->findOneScheduledByNewsletterAndSubscriber($newsletter, $subscriber); |
| 108 | if ($task) { |
| 109 | $this->rescheduleAutomaticEmailSendingTask($newsletter, $task); |
| 110 | } |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | public function cancelAutomaticEmail(string $group, string $event, SubscriberEntity $subscriber): void { |
| 115 | $newsletters = $this->scheduler->getNewsletters(NewsletterEntity::TYPE_AUTOMATIC, $group); |
| 116 | if (empty($newsletters)) { |
| 117 | return; |
| 118 | } |
| 119 | |
| 120 | foreach ($newsletters as $newsletter) { |
| 121 | if ($newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_EVENT) !== $event) { |
| 122 | continue; |
| 123 | } |
| 124 | |
| 125 | // try to find existing scheduled task for given subscriber |
| 126 | $task = $this->scheduledTasksRepository->findOneScheduledByNewsletterAndSubscriber($newsletter, $subscriber); |
| 127 | if ($task) { |
| 128 | $queue = $task->getSendingQueue(); |
| 129 | if ($queue instanceof SendingQueueEntity) { |
| 130 | $this->sendingQueuesRepository->remove($queue); |
| 131 | } |
| 132 | $this->scheduledTaskSubscribersRepository->deleteByScheduledTask($task); |
| 133 | $this->scheduledTasksRepository->remove($task); |
| 134 | $this->scheduledTasksRepository->flush(); |
| 135 | } |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | public function createAutomaticEmailScheduledTask(NewsletterEntity $newsletter, ?SubscriberEntity $subscriber, ?array $meta = null): ScheduledTaskEntity { |
| 140 | $scheduledTask = new ScheduledTaskEntity(); |
| 141 | $scheduledTask->setType(SendingQueue::TASK_TYPE); |
| 142 | $scheduledTask->setStatus(SendingQueueEntity::STATUS_SCHEDULED); |
| 143 | $scheduledTask->setPriority(ScheduledTaskEntity::PRIORITY_MEDIUM); |
| 144 | |
| 145 | $scheduledTask->setScheduledAt($this->scheduler->getScheduledTimeWithDelay( |
| 146 | $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_TYPE), |
| 147 | $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_NUMBER) |
| 148 | )); |
| 149 | $this->scheduledTasksRepository->persist($scheduledTask); |
| 150 | $this->scheduledTasksRepository->flush(); |
| 151 | |
| 152 | $sendingQueue = new SendingQueueEntity(); |
| 153 | $sendingQueue->setNewsletter($newsletter); |
| 154 | $sendingQueue->setTask($scheduledTask); |
| 155 | // Because we changed the way how to updateCounts after sending we need to set initial counts |
| 156 | $sendingQueue->setCountTotal($subscriber ? 1 : 0); |
| 157 | $sendingQueue->setCountToProcess($subscriber ? 1 : 0); |
| 158 | $scheduledTask->setSendingQueue($sendingQueue); |
| 159 | |
| 160 | if ($meta) { |
| 161 | $scheduledTask->setMeta($meta); |
| 162 | $sendingQueue->setMeta($meta); |
| 163 | } |
| 164 | |
| 165 | $this->sendingQueuesRepository->persist($sendingQueue); |
| 166 | $this->sendingQueuesRepository->flush(); |
| 167 | |
| 168 | if ($newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_SEND_TO) === 'user' && $subscriber) { |
| 169 | $scheduledTaskSubscriber = new ScheduledTaskSubscriberEntity($scheduledTask, $subscriber); |
| 170 | $this->scheduledTaskSubscribersRepository->persist($scheduledTaskSubscriber); |
| 171 | $this->scheduledTaskSubscribersRepository->flush(); |
| 172 | $scheduledTask->getSubscribers()->add($scheduledTaskSubscriber); |
| 173 | } |
| 174 | |
| 175 | return $scheduledTask; |
| 176 | } |
| 177 | |
| 178 | private function rescheduleAutomaticEmailSendingTask(NewsletterEntity $newsletter, ScheduledTaskEntity $scheduledTask, ?array $meta = null): void { |
| 179 | $sendingQueue = $this->sendingQueuesRepository->findOneBy(['task' => $scheduledTask]); |
| 180 | if (!$sendingQueue) { |
| 181 | return; |
| 182 | } |
| 183 | |
| 184 | if ($meta) { |
| 185 | $sendingQueue->setMeta($meta); |
| 186 | $scheduledTask->setMeta($meta); |
| 187 | } |
| 188 | // compute new 'scheduled_at' from now |
| 189 | $scheduledTask->setScheduledAt($this->scheduler->getScheduledTimeWithDelay( |
| 190 | $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_TYPE), |
| 191 | $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AFTER_TIME_NUMBER) |
| 192 | )); |
| 193 | $this->sendingQueuesRepository->flush(); |
| 194 | } |
| 195 | } |
| 196 |