PluginProbe
MailPoet – Newsletters, Email Marketing, and Automation / 5.33.1
MailPoet – Newsletters, Email Marketing, and Automation v5.33.1
5.38.0 5.37.0 5.36.1 5.36.0 5.35.1 5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 All 542 releases
mailpoet / lib / Automation / Integrations / MailPoet / Hooks / CreateAutomationRunHook.php
CreateAutomationRunHook.php
68 lines 2.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Automation\Integrations\MailPoet\Hooks;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Automation\Engine\Data\StepRunArgs;
9 use MailPoet\Automation\Engine\Hooks;
10 use MailPoet\Automation\Engine\Storage\AutomationRunStorage;
11 use MailPoet\Automation\Integrations\MailPoet\Subjects\SubscriberSubject;
12 use MailPoet\Util\Security;
13 use MailPoet\WP\Functions as WPFunctions;
14
15 class CreateAutomationRunHook {
16 private AutomationRunStorage $automationRunStorage;
17 private WPFunctions $wp;
18
19 public function __construct(
20 AutomationRunStorage $automationRunStorage,
21 WPFunctions $wp
22 ) {
23 $this->automationRunStorage = $automationRunStorage;
24 $this->wp = $wp;
25 }
26
27 public function init(): void {
28 $this->wp->addAction(Hooks::AUTOMATION_RUN_CREATE, [$this, 'createAutomationRun'], 5, 2);
29 }
30
31 public function createAutomationRun(bool $result, StepRunArgs $args): bool {
32 if (!$result) {
33 return $result;
34 }
35
36 $automation = $args->getAutomation();
37 $runOnlyOnce = $automation->getMeta('mailpoet:run-once-per-subscriber');
38 if (!$runOnlyOnce) {
39 return true;
40 }
41
42 $subscriberSubject = array_values($args->getAutomationRun()->getSubjects(SubscriberSubject::KEY))[0] ?? null;
43 if (!$subscriberSubject) {
44 return true;
45 }
46
47 // Use locking mechanism to minimize the risk of race conditions.
48 // WP transients don't provide atomic operations, so we can't guarantee
49 // race-condition safety with a 100% certainty, but we can significantly
50 // minimize the risk by generating and re-checking a unique lock value.
51 $key = sprintf('mailpoet:run-once-per-subscriber:[%s][%s]', $automation->getId(), $subscriberSubject->getHash());
52
53 // 1. If lock already exists, do not create automation run.
54 $value = $this->wp->getTransient($key);
55 if ($value) {
56 return false;
57 }
58
59 // 2. If lock does not exist, create it with a unique value.
60 $value = Security::generateRandomString(16);
61 $this->wp->setTransient($key, $value, MINUTE_IN_SECONDS);
62
63 // 3. If no automation run exist, ensure that the lock wasn't updated by another process.
64 $count = $this->automationRunStorage->getCountByAutomationAndSubject($automation, $subscriberSubject);
65 return $count === 0 && $this->wp->getTransient($key) === $value;
66 }
67 }
68