Нет описания

PostNotificationScheduler.php 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php
  2. namespace MailPoet\Newsletter\Scheduler;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoet\Entities\NewsletterEntity;
  5. use MailPoet\Entities\NewsletterOptionEntity;
  6. use MailPoet\Entities\NewsletterOptionFieldEntity;
  7. use MailPoet\Logging\LoggerFactory;
  8. use MailPoet\Models\SendingQueue;
  9. use MailPoet\Newsletter\NewsletterPostsRepository;
  10. use MailPoet\Newsletter\NewslettersRepository;
  11. use MailPoet\Newsletter\Options\NewsletterOptionFieldsRepository;
  12. use MailPoet\Newsletter\Options\NewsletterOptionsRepository;
  13. use MailPoet\Tasks\Sending as SendingTask;
  14. use MailPoet\WP\Posts;
  15. class PostNotificationScheduler {
  16. const SECONDS_IN_HOUR = 3600;
  17. const LAST_WEEKDAY_FORMAT = 'L';
  18. const INTERVAL_DAILY = 'daily';
  19. const INTERVAL_IMMEDIATELY = 'immediately';
  20. const INTERVAL_NTHWEEKDAY = 'nthWeekDay';
  21. const INTERVAL_WEEKLY = 'weekly';
  22. const INTERVAL_IMMEDIATE = 'immediate';
  23. const INTERVAL_MONTHLY = 'monthly';
  24. /** @var LoggerFactory */
  25. private $loggerFactory;
  26. /** @var NewslettersRepository */
  27. private $newslettersRepository;
  28. /** @var NewsletterOptionsRepository */
  29. private $newsletterOptionsRepository;
  30. /** @var NewsletterOptionFieldsRepository */
  31. private $newsletterOptionFieldsRepository;
  32. /** @var NewsletterPostsRepository */
  33. private $newsletterPostsRepository;
  34. public function __construct(
  35. NewslettersRepository $newslettersRepository,
  36. NewsletterOptionsRepository $newsletterOptionsRepository,
  37. NewsletterOptionFieldsRepository $newsletterOptionFieldsRepository,
  38. NewsletterPostsRepository $newsletterPostsRepository
  39. ) {
  40. $this->loggerFactory = LoggerFactory::getInstance();
  41. $this->newslettersRepository = $newslettersRepository;
  42. $this->newsletterOptionsRepository = $newsletterOptionsRepository;
  43. $this->newsletterOptionFieldsRepository = $newsletterOptionFieldsRepository;
  44. $this->newsletterPostsRepository = $newsletterPostsRepository;
  45. }
  46. public function transitionHook($newStatus, $oldStatus, $post) {
  47. $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->addInfo(
  48. 'transition post notification hook initiated',
  49. [
  50. 'post_id' => $post->ID,
  51. 'new_status' => $newStatus,
  52. 'old_status' => $oldStatus,
  53. ]
  54. );
  55. $types = Posts::getTypes();
  56. if (($newStatus !== 'publish') || !isset($types[$post->post_type])) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
  57. return;
  58. }
  59. $this->schedulePostNotification($post->ID);
  60. }
  61. public function schedulePostNotification($postId) {
  62. $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->addInfo(
  63. 'schedule post notification hook',
  64. ['post_id' => $postId]
  65. );
  66. $newsletters = $this->newslettersRepository->findActiveByTypes([NewsletterEntity::TYPE_NOTIFICATION]);
  67. $this->newslettersRepository->prefetchOptions($newsletters);
  68. if (!count($newsletters)) {
  69. return false;
  70. }
  71. foreach ($newsletters as $newsletter) {
  72. $post = $this->newsletterPostsRepository->findOneBy([
  73. 'newsletter' => $newsletter,
  74. 'postId' => $postId,
  75. ]);
  76. if ($post === null) {
  77. $this->createPostNotificationSendingTask($newsletter);
  78. }
  79. }
  80. }
  81. public function createPostNotificationSendingTask(NewsletterEntity $newsletter): ?SendingTask {
  82. $notificationHistory = $this->newslettersRepository->findSendigNotificationHistoryWithPausedTask($newsletter);
  83. if (count($notificationHistory) > 0) {
  84. return null;
  85. }
  86. $scheduleOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_SCHEDULE);
  87. if (!$scheduleOption) {
  88. return null;
  89. }
  90. $nextRunDate = Scheduler::getNextRunDate($scheduleOption->getValue());
  91. if (!$nextRunDate) {
  92. return null;
  93. }
  94. // do not schedule duplicate queues for the same time
  95. $lastQueue = $newsletter->getLatestQueue();
  96. $task = $lastQueue !== null ? $lastQueue->getTask() : null;
  97. $scheduledAt = $task !== null ? $task->getScheduledAt() : null;
  98. if ($scheduledAt && $scheduledAt->format('Y-m-d H:i:s') === $nextRunDate) {
  99. return null;
  100. }
  101. $sendingTask = SendingTask::create();
  102. $sendingTask->newsletterId = $newsletter->getId();
  103. $sendingTask->status = SendingQueue::STATUS_SCHEDULED;
  104. $sendingTask->scheduledAt = $nextRunDate;
  105. $sendingTask->save();
  106. $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->addInfo(
  107. 'schedule post notification',
  108. ['sending_task' => $sendingTask->id(), 'scheduled_at' => $nextRunDate]
  109. );
  110. return $sendingTask;
  111. }
  112. public function processPostNotificationSchedule(NewsletterEntity $newsletter) {
  113. $intervalTypeOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_INTERVAL_TYPE);
  114. $intervalType = $intervalTypeOption ? $intervalTypeOption->getValue() : null;
  115. $timeOfDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_TIME_OF_DAY);
  116. $hour = $timeOfDayOption ? (int)$timeOfDayOption->getValue() / self::SECONDS_IN_HOUR : null;
  117. $weekDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_WEK_DAY);
  118. $weekDay = $weekDayOption ? $weekDayOption->getValue() : null;
  119. $monthDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_MONTH_DAY);
  120. $monthDay = $monthDayOption ? $monthDayOption->getValue() : null;
  121. $nthWeekDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_NTH_WEEK_DAY);
  122. $nthWeekDay = $nthWeekDayOption ? $nthWeekDayOption->getValue() : null;
  123. $nthWeekDay = ($nthWeekDay === self::LAST_WEEKDAY_FORMAT) ? $nthWeekDay : '#' . $nthWeekDay;
  124. switch ($intervalType) {
  125. case self::INTERVAL_IMMEDIATE:
  126. case self::INTERVAL_DAILY:
  127. $schedule = sprintf('0 %s * * *', $hour);
  128. break;
  129. case self::INTERVAL_WEEKLY:
  130. $schedule = sprintf('0 %s * * %s', $hour, $weekDay);
  131. break;
  132. case self::INTERVAL_NTHWEEKDAY:
  133. $schedule = sprintf('0 %s ? * %s%s', $hour, $weekDay, $nthWeekDay);
  134. break;
  135. case self::INTERVAL_MONTHLY:
  136. $schedule = sprintf('0 %s %s * *', $hour, $monthDay);
  137. break;
  138. case self::INTERVAL_IMMEDIATELY:
  139. default:
  140. $schedule = '* * * * *';
  141. break;
  142. }
  143. $optionField = $this->newsletterOptionFieldsRepository->findOneBy([
  144. 'name' => NewsletterOptionFieldEntity::NAME_SCHEDULE,
  145. ]);
  146. if (!$optionField instanceof NewsletterOptionFieldEntity) {
  147. throw new \Exception('NewsletterOptionField for schedule doesn’t exist.');
  148. }
  149. $scheduleOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_SCHEDULE);
  150. if ($scheduleOption === null) {
  151. $scheduleOption = new NewsletterOptionEntity($newsletter, $optionField);
  152. $newsletter->getOptions()->add($scheduleOption);
  153. }
  154. $scheduleOption->setValue($schedule);
  155. $this->newsletterOptionsRepository->persist($scheduleOption);
  156. $this->newsletterOptionsRepository->flush();
  157. return $scheduleOption->getValue();
  158. }
  159. }