| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- <?php
- namespace MailPoet\Cron\Workers;
- if (!defined('ABSPATH')) exit;
- use MailPoet\Cron\CronHelper;
- use MailPoet\Logging\LoggerFactory;
- use MailPoet\Models\Newsletter;
- use MailPoet\Models\ScheduledTask;
- use MailPoet\Models\Segment;
- use MailPoet\Models\Subscriber;
- use MailPoet\Models\SubscriberSegment;
- use MailPoet\Newsletter\Scheduler\PostNotificationScheduler;
- use MailPoet\Newsletter\Scheduler\Scheduler as NewsletterScheduler;
- use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
- use MailPoet\Segments\SubscribersFinder;
- use MailPoet\Tasks\Sending as SendingTask;
- class Scheduler {
- const TASK_BATCH_SIZE = 5;
- /** @var SubscribersFinder */
- private $subscribersFinder;
- /** @var LoggerFactory */
- private $loggerFactory;
- /** @var CronHelper */
- private $cronHelper;
- public function __construct(
- SubscribersFinder $subscribersFinder,
- LoggerFactory $loggerFactory,
- CronHelper $cronHelper
- ) {
- $this->cronHelper = $cronHelper;
- $this->subscribersFinder = $subscribersFinder;
- $this->loggerFactory = $loggerFactory;
- }
- public function process($timer = false) {
- $timer = $timer ?: microtime(true);
- // abort if execution limit is reached
- $this->cronHelper->enforceExecutionLimit($timer);
- $scheduledQueues = self::getScheduledQueues();
- if (!count($scheduledQueues)) return false;
- $this->updateTasks($scheduledQueues);
- foreach ($scheduledQueues as $i => $queue) {
- $newsletter = Newsletter::findOneWithOptions($queue->newsletterId);
- if (!$newsletter || $newsletter->deletedAt !== null) {
- $queue->delete();
- } elseif ($newsletter->status !== Newsletter::STATUS_ACTIVE && $newsletter->status !== Newsletter::STATUS_SCHEDULED) {
- continue;
- } elseif ($newsletter->type === Newsletter::TYPE_WELCOME) {
- $this->processWelcomeNewsletter($newsletter, $queue);
- } elseif ($newsletter->type === Newsletter::TYPE_NOTIFICATION) {
- $this->processPostNotificationNewsletter($newsletter, $queue);
- } elseif ($newsletter->type === Newsletter::TYPE_STANDARD) {
- $this->processScheduledStandardNewsletter($newsletter, $queue);
- } elseif ($newsletter->type === Newsletter::TYPE_AUTOMATIC) {
- $this->processScheduledAutomaticEmail($newsletter, $queue);
- }
- $this->cronHelper->enforceExecutionLimit($timer);
- }
- }
- public function processWelcomeNewsletter($newsletter, $queue) {
- $subscribers = $queue->getSubscribers();
- if (empty($subscribers[0])) {
- $queue->delete();
- return false;
- }
- $subscriberId = (int)$subscribers[0];
- if ($newsletter->event === 'segment') {
- if ($this->verifyMailpoetSubscriber($subscriberId, $newsletter, $queue) === false) {
- return false;
- }
- } else {
- if ($newsletter->event === 'user') {
- if ($this->verifyWPSubscriber($subscriberId, $newsletter, $queue) === false) {
- return false;
- }
- }
- }
- $queue->status = null;
- $queue->save();
- return true;
- }
- public function processPostNotificationNewsletter($newsletter, $queue) {
- $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->addInfo(
- 'process post notification in scheduler',
- ['newsletter_id' => $newsletter->id, 'task_id' => $queue->taskId]
- );
- // ensure that segments exist
- $segments = $newsletter->segments()->findMany();
- if (empty($segments)) {
- $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->addInfo(
- 'post notification no segments',
- ['newsletter_id' => $newsletter->id, 'task_id' => $queue->taskId]
- );
- return $this->deleteQueueOrUpdateNextRunDate($queue, $newsletter);
- }
- // ensure that subscribers are in segments
- $subscribersCount = $this->subscribersFinder->addSubscribersToTaskFromSegments($queue->task(), $segments);
- if (empty($subscribersCount)) {
- $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->addInfo(
- 'post notification no subscribers',
- ['newsletter_id' => $newsletter->id, 'task_id' => $queue->taskId]
- );
- return $this->deleteQueueOrUpdateNextRunDate($queue, $newsletter);
- }
- // create a duplicate newsletter that acts as a history record
- $notificationHistory = $this->createNotificationHistory($newsletter->id);
- if (!$notificationHistory) return false;
- // queue newsletter for delivery
- $queue->newsletterId = $notificationHistory->id;
- $queue->status = null;
- $queue->save();
- // update notification status
- $notificationHistory->setStatus(Newsletter::STATUS_SENDING);
- $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->addInfo(
- 'post notification set status to sending',
- ['newsletter_id' => $newsletter->id, 'task_id' => $queue->taskId]
- );
- return true;
- }
- public function processScheduledAutomaticEmail($newsletter, $queue) {
- if ($newsletter->sendTo === 'segment') {
- $segment = Segment::findOne($newsletter->segment);
- $result = $this->subscribersFinder->addSubscribersToTaskFromSegments($queue->task(), [$segment]);
- if (empty($result)) {
- $queue->delete();
- return false;
- }
- } else {
- $subscribers = $queue->getSubscribers();
- $subscriber = (!empty($subscribers) && is_array($subscribers)) ?
- Subscriber::findOne($subscribers[0]) :
- false;
- if (!$subscriber) {
- $queue->delete();
- return false;
- }
- if ($this->verifySubscriber($subscriber, $queue) === false) {
- return false;
- }
- }
- $queue->status = null;
- $queue->save();
- return true;
- }
- public function processScheduledStandardNewsletter($newsletter, SendingTask $task) {
- $segments = $newsletter->segments()->findMany();
- $this->subscribersFinder->addSubscribersToTaskFromSegments($task->task(), $segments);
- // update current queue
- $task->updateCount();
- $task->status = null;
- $task->save();
- // update newsletter status
- $newsletter->setStatus(Newsletter::STATUS_SENDING);
- return true;
- }
- public function verifyMailpoetSubscriber($subscriberId, $newsletter, $queue) {
- $subscriber = Subscriber::findOne($subscriberId);
- // check if subscriber is in proper segment
- $subscriberInSegment =
- SubscriberSegment::where('subscriber_id', $subscriberId)
- ->where('segment_id', $newsletter->segment)
- ->where('status', 'subscribed')
- ->findOne();
- if (!$subscriber || !$subscriberInSegment) {
- $queue->delete();
- return false;
- }
- return $this->verifySubscriber($subscriber, $queue);
- }
- public function verifyWPSubscriber($subscriberId, $newsletter, $queue) {
- // check if user has the proper role
- $subscriber = Subscriber::findOne($subscriberId);
- if (!$subscriber || $subscriber->isWPUser() === false) {
- $queue->delete();
- return false;
- }
- $wpUser = get_userdata($subscriber->wpUserId);
- if ($wpUser === false) {
- $queue->delete();
- return false;
- }
- if ($newsletter->role !== WelcomeScheduler::WORDPRESS_ALL_ROLES
- && !in_array($newsletter->role, ((array)$wpUser)['roles'])
- ) {
- $queue->delete();
- return false;
- }
- return $this->verifySubscriber($subscriber, $queue);
- }
- public function verifySubscriber($subscriber, $queue) {
- if ($subscriber->status === Subscriber::STATUS_UNCONFIRMED) {
- // reschedule delivery
- $queue->rescheduleProgressively();
- return false;
- } else if ($subscriber->status === Subscriber::STATUS_UNSUBSCRIBED) {
- $queue->delete();
- return false;
- }
- return true;
- }
- public function deleteQueueOrUpdateNextRunDate($queue, $newsletter) {
- if ($newsletter->intervalType === PostNotificationScheduler::INTERVAL_IMMEDIATELY) {
- $queue->delete();
- return;
- } else {
- $nextRunDate = NewsletterScheduler::getNextRunDate($newsletter->schedule);
- if (!$nextRunDate) {
- $queue->delete();
- return;
- }
- $queue->scheduledAt = $nextRunDate;
- $queue->save();
- }
- }
- public function createNotificationHistory($newsletterId) {
- $newsletter = Newsletter::findOne($newsletterId);
- if (!$newsletter instanceof Newsletter) {
- return false;
- }
- $notificationHistory = $newsletter->createNotificationHistory();
- return ($notificationHistory->getErrors() === false) ?
- $notificationHistory :
- false;
- }
- private function updateTasks(array $scheduledQueues) {
- $ids = array_map(function ($queue) {
- return $queue->taskId;
- }, $scheduledQueues);
- ScheduledTask::touchAllByIds($ids);
- }
- public static function getScheduledQueues() {
- return SendingTask::getScheduledQueues(self::TASK_BATCH_SIZE);
- }
- }
|