wp = $wp; $this->tasksRepository = $tasksRepository; $this->taskSubscribersRepository = $taskSubscribersRepository; $this->automationStorage = $automationStorage; } public function registerHooks(): void { $this->wp->addAction( AbandonedCart::HOOK_SCHEDULE, [ $this, 'schedule', ], 10, 2 ); $this->wp->addAction( AbandonedCart::HOOK_RE_SCHEDULE, [ $this, 'reschedule', ] ); $this->wp->addAction( AbandonedCart::HOOK_CANCEL, [ $this, 'cancel', ] ); } /** * @param SubscriberEntity $subscriber * @param int[] $productIds * @return void */ public function schedule(SubscriberEntity $subscriber, array $productIds) { $abandonedCartAutomations = $this->automationStorage->getActiveAutomationsByTriggerKey(AbandonedCartTrigger::KEY); $this->cancel($subscriber); array_map( function (Automation $automation) use ($subscriber, $productIds) { $this->scheduleForSingleAutomation($subscriber, $productIds, $automation); }, $abandonedCartAutomations ); } /** * @param SubscriberEntity $subscriber * @param int[] $productIds * @param Automation $automation * @return void * @throws InvalidStateException */ private function scheduleForSingleAutomation(SubscriberEntity $subscriber, array $productIds, Automation $automation) { $trigger = $automation->getTrigger(AbandonedCartTrigger::KEY); if (!$trigger) { throw new InvalidStateException(sprintf('Abandoned cart trigger is missing from automation %d', $automation->getId())); } $wait = $trigger->getArgs()['wait'] * 60; $scheduledAt = Carbon::now()->millisecond(0)->addSeconds($wait); $task = new ScheduledTaskEntity(); $task->setType(AbandonedCartWorker::TASK_TYPE); $lastActivity = Carbon::now()->millisecond(0); $task->setCreatedAt($lastActivity); $task->setPriority(ScheduledTaskEntity::PRIORITY_MEDIUM); $task->setMeta([ 'product_ids' => $productIds, 'automation_id' => $automation->getId(), 'automation_version' => $automation->getVersionId(), ]); $task->setStatus(ScheduledTaskEntity::STATUS_SCHEDULED); $task->setScheduledAt($scheduledAt); $this->tasksRepository->persist($task); $this->tasksRepository->flush(); $taskSubscriber = new ScheduledTaskSubscriberEntity($task, $subscriber); $task->getSubscribers()->add($taskSubscriber); $this->taskSubscribersRepository->persist($taskSubscriber); $this->taskSubscribersRepository->flush(); } public function reschedule(SubscriberEntity $subscriber): void { $tasks = $this->tasksRepository->findByTypeAndSubscriber(AbandonedCartWorker::TASK_TYPE, $subscriber); if (!$tasks) { return; } $this->cancel($subscriber); foreach ($tasks as $task) { $meta = $task->getMeta(); $automation = isset($meta['automation_id']) ? $this->automationStorage->getAutomation((int)$meta['automation_id']) : null; if (!$automation) { continue; } $this->scheduleForSingleAutomation($subscriber, $meta['product_ids'] ?? [], $automation); } } public function cancel(SubscriberEntity $subscriber): void { $existingTasks = $this->tasksRepository->findByTypeAndSubscriber(AbandonedCartWorker::TASK_TYPE, $subscriber); if (!$existingTasks) { return; } foreach ($existingTasks as $task) { if ($task->getStatus() !== ScheduledTaskEntity::STATUS_SCHEDULED) { continue; } foreach ($task->getSubscribers() as $taskSubscriber) { $this->taskSubscribersRepository->remove($taskSubscriber); } $this->tasksRepository->remove($task); } $this->tasksRepository->flush(); } }