loggerFactory = LoggerFactory::getInstance(); $this->newslettersRepository = $newslettersRepository; $this->newsletterOptionsRepository = $newsletterOptionsRepository; $this->newsletterOptionFieldsRepository = $newsletterOptionFieldsRepository; $this->newsletterPostsRepository = $newsletterPostsRepository; $this->scheduler = $scheduler; $this->scheduledTasksRepository = $scheduledTasksRepository; $this->sendingQueuesRepository = $sendingQueuesRepository; } public function transitionHook($newStatus, $oldStatus, $post) { $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->info( 'transition post notification hook initiated', [ 'post_id' => $post->ID, 'new_status' => $newStatus, 'old_status' => $oldStatus, ] ); $types = Posts::getTypes(); if (($newStatus !== 'publish') || !isset($types[$post->post_type])) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps return; } $this->schedulePostNotification($post->ID); } public function schedulePostNotification($postId) { $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->info( 'schedule post notification hook', ['post_id' => $postId] ); $newsletters = $this->newslettersRepository->findActiveByTypes([NewsletterEntity::TYPE_NOTIFICATION]); $this->newslettersRepository->prefetchOptions($newsletters); if (!count($newsletters)) { return false; } foreach ($newsletters as $newsletter) { $post = $this->newsletterPostsRepository->findOneBy([ 'newsletter' => $newsletter, 'postId' => $postId, ]); if ($post === null) { $this->createPostNotificationSendingTask($newsletter); } } } public function createPostNotificationSendingTask(NewsletterEntity $newsletter): ?ScheduledTaskEntity { $notificationHistory = $this->newslettersRepository->findSendingNotificationHistoryWithoutPausedTask($newsletter); if (count($notificationHistory) > 0) { return null; } $scheduleOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_SCHEDULE); if (!$scheduleOption) { return null; } $nextRunDate = $this->scheduler->getNextRunDateTime($scheduleOption->getValue()); if (!$nextRunDate) { return null; } // do not schedule duplicate queues for the same time $lastQueue = $newsletter->getLatestQueue(); $task = $lastQueue !== null ? $lastQueue->getTask() : null; $scheduledAt = $task !== null ? $task->getScheduledAt() : null; if ($scheduledAt && $scheduledAt->format('Y-m-d H:i:s') === $nextRunDate->format('Y-m-d H:i:s')) { return null; } $scheduledTask = new ScheduledTaskEntity(); $scheduledTask->setType(SendingQueue::TASK_TYPE); $scheduledTask->setStatus(ScheduledTaskEntity::STATUS_SCHEDULED); $scheduledTask->setScheduledAt($nextRunDate); $scheduledTask->setPriority(ScheduledTaskEntity::PRIORITY_MEDIUM); $this->scheduledTasksRepository->persist($scheduledTask); $this->scheduledTasksRepository->flush(); $sendingQueue = new SendingQueueEntity(); $sendingQueue->setNewsletter($newsletter); $sendingQueue->setTask($scheduledTask); $this->sendingQueuesRepository->persist($sendingQueue); $this->sendingQueuesRepository->flush(); $scheduledTask->setSendingQueue($sendingQueue); $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->info( 'schedule post notification', [ 'sending_task' => $scheduledTask->getId(), 'scheduled_at' => $nextRunDate->format(DateTime::DEFAULT_DATE_TIME_FORMAT), ] ); return $scheduledTask; } public function processPostNotificationSchedule(NewsletterEntity $newsletter) { $intervalTypeOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_INTERVAL_TYPE); $intervalType = $intervalTypeOption ? $intervalTypeOption->getValue() : null; $timeOfDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_TIME_OF_DAY); $hour = $timeOfDayOption ? (int)floor((int)$timeOfDayOption->getValue() / self::SECONDS_IN_HOUR) : null; $minute = $timeOfDayOption ? ((int)$timeOfDayOption->getValue() - (int)($hour * self::SECONDS_IN_HOUR)) / self::SECONDS_IN_MINUTE : null; $weekDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_WEEK_DAY); $weekDay = $weekDayOption ? $weekDayOption->getValue() : null; $monthDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_MONTH_DAY); $monthDay = $monthDayOption ? $monthDayOption->getValue() : null; $nthWeekDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_NTH_WEEK_DAY); $nthWeekDay = $nthWeekDayOption ? $nthWeekDayOption->getValue() : null; $nthWeekDay = ($nthWeekDay === self::LAST_WEEKDAY_FORMAT) ? $nthWeekDay : '#' . $nthWeekDay; switch ($intervalType) { case self::INTERVAL_IMMEDIATE: case self::INTERVAL_DAILY: $schedule = sprintf('%s %s * * *', $minute, $hour); break; case self::INTERVAL_WEEKLY: $schedule = sprintf('%s %s * * %s', $minute, $hour, $weekDay); break; case self::INTERVAL_NTHWEEKDAY: $schedule = sprintf('%s %s ? * %s%s', $minute, $hour, $weekDay, $nthWeekDay); break; case self::INTERVAL_MONTHLY: $schedule = sprintf('%s %s %s * *', $minute, $hour, $monthDay); break; case self::INTERVAL_IMMEDIATELY: default: $schedule = '* * * * *'; break; } $optionField = $this->newsletterOptionFieldsRepository->findOneBy([ 'name' => NewsletterOptionFieldEntity::NAME_SCHEDULE, ]); if (!$optionField instanceof NewsletterOptionFieldEntity) { throw new \Exception('NewsletterOptionField for schedule doesn’t exist.'); } $scheduleOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_SCHEDULE); if ($scheduleOption === null) { $scheduleOption = new NewsletterOptionEntity($newsletter, $optionField); $newsletter->getOptions()->add($scheduleOption); } $scheduleOption->setValue($schedule); $this->newsletterOptionsRepository->persist($scheduleOption); $this->newsletterOptionsRepository->flush(); return $scheduleOption->getValue(); } }