oont-contents/plugins/mailpoet/lib/Automation/Integrations/WooCommerce/Triggers/AbandonedCart/AbandonedCartHandler.php
2025-02-08 15:10:23 +01:00

165 lines
5.1 KiB
PHP

<?php declare(strict_types = 1);
namespace MailPoet\Automation\Integrations\WooCommerce\Triggers\AbandonedCart;
if (!defined('ABSPATH')) exit;
use MailPoet\AutomaticEmails\WooCommerce\Events\AbandonedCart;
use MailPoet\Automation\Engine\Data\Automation;
use MailPoet\Automation\Engine\Exceptions\InvalidStateException;
use MailPoet\Automation\Engine\Storage\AutomationStorage;
use MailPoet\Automation\Engine\WordPress;
use MailPoet\Cron\Workers\Automations\AbandonedCartWorker;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\ScheduledTaskSubscriberEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
use MailPoet\Newsletter\Sending\ScheduledTaskSubscribersRepository;
use MailPoetVendor\Carbon\Carbon;
class AbandonedCartHandler {
const TASK_ABANDONED_CART = 'automation_abandoned_cart';
/** @var WordPress */
private $wp;
/** @var ScheduledTasksRepository */
private $tasksRepository;
/** @var ScheduledTaskSubscribersRepository */
private $taskSubscribersRepository;
/** @var AutomationStorage */
private $automationStorage;
public function __construct(
WordPress $wp,
ScheduledTasksRepository $tasksRepository,
ScheduledTaskSubscribersRepository $taskSubscribersRepository,
AutomationStorage $automationStorage
) {
$this->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();
}
}