PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.1
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Helpers/ScenarioHelper.php +0 -370 11.0.2 → 11.1.1 View file →
@@ -1,370 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Helpers;
4 -
5 -use AcyMailing\Classes\HistoryClass;
6 -use AcyMailing\Classes\ScenarioClass;
7 -use AcyMailing\Classes\ScenarioHistoryLineClass;
8 -use AcyMailing\Classes\ScenarioProcessClass;
9 -use AcyMailing\Classes\ScenarioStepClass;
10 -use AcyMailing\Classes\ScenarioQueueClass;
11 -use AcyMailing\Classes\UserClass;
12 -use AcyMailing\Core\AcymObject;
13 -
14 -class ScenarioHelper extends AcymObject
15 -{
16 - private ScenarioClass $scenarioClass;
17 - private ScenarioStepClass $scenarioStepClass;
18 - private ScenarioQueueClass $scenarioQueueClass;
19 - private ScenarioHistoryLineClass $scenarioHistoryLineClass;
20 - private ScenarioProcessClass $scenarioProcessClass;
21 -
22 - public function __construct()
23 - {
24 - parent::__construct();
25 - $this->scenarioClass = new ScenarioClass();
26 - $this->scenarioStepClass = new ScenarioStepClass();
27 - $this->scenarioQueueClass = new ScenarioQueueClass();
28 - $this->scenarioHistoryLineClass = new ScenarioHistoryLineClass();
29 - $this->scenarioProcessClass = new ScenarioProcessClass();
30 - }
31 -
32 - public function trigger(string $trigger, array $options): void
33 - {
34 - if (!acym_level(ACYM_ENTERPRISE)) {
35 - return;
36 - }
37 -
38 - if (empty($trigger)) {
39 - acym_logError('ScenarioHelper::trigger - Missing trigger for options: '.json_encode($options));
40 -
41 - return;
42 - }
43 -
44 - if (empty($options['userId'])) {
45 - acym_logError('ScenarioHelper::trigger - Missing userId, trigger: '.$trigger);
46 -
47 - return;
48 - }
49 -
50 - $userId = intval($options['userId']);
51 -
52 - $userClass = new UserClass();
53 - if (empty($userClass->getOneById($userId))) {
54 - acym_logError('ScenarioHelper::trigger - User not found, userId: '.$userId);
55 -
56 - return;
57 - }
58 -
59 - $scenarios = $this->scenarioClass->getAllActiveByTriggers([$trigger]);
60 -
61 - foreach ($scenarios as $scenario) {
62 - if ($scenario->trigger_once) {
63 - if ($this->scenarioProcessClass->hasUserProcess($scenario->id, $userId)) {
64 - continue;
65 - }
66 - }
67 -
68 - // For the trigger TimeAutomationTriggers, this way we know if we are triggering a scenario or not
69 - $scenario->is_scenario = true;
70 - $scenario->triggers = [$scenario->trigger => 1];
71 - $execute = false;
72 - $options = $this->formatOptions($scenario->trigger_params, 'trigger');
73 - $options['userId'] = $userId;
74 - $options['time'] = time();
75 - acym_trigger('onAcymExecuteTrigger', [&$scenario, &$execute, &$options]);
76 -
77 - if (!$execute) {
78 - continue;
79 - }
80 -
81 - $firstStep = $this->scenarioStepClass->getFirstStepByScenarioId($scenario->id);
82 -
83 - if (empty($firstStep)) {
84 - acym_logError('ScenarioHelper::trigger - No first step found for scenario '.$scenario->id);
85 - continue;
86 - }
87 -
88 - $scenarioProcess = new \stdClass();
89 - $scenarioProcess->scenario_id = $scenario->id;
90 - $scenarioProcess->user_id = $userId;
91 - $scenarioProcess->start_at = acym_date('now', 'Y-m-d H:i:s', false);
92 - $scenarioProcess->id = $this->scenarioProcessClass->save($scenarioProcess);
93 -
94 - $this->createHistory($scenarioProcess->id, 'trigger', 'success');
95 -
96 - $this->handleStep($firstStep, $userId, $scenarioProcess->id);
97 - }
98 - }
99 -
100 - private function handleStep(object $step, int $userId, int $scenarioProcessId): void
101 - {
102 - switch ($step->type) {
103 - case ScenarioClass::TYPE_DELAY:
104 - $this->handleDelay($step, $userId, $scenarioProcessId);
105 - break;
106 - case ScenarioClass::TYPE_CONDITION:
107 - $this->handleCondition($step, $userId, $scenarioProcessId);
108 - break;
109 - case ScenarioClass::TYPE_ACTION:
110 - $this->handleAction($step, $userId, $scenarioProcessId);
111 - break;
112 - }
113 - }
114 -
115 - private function handleDelay(object $step, int $userId, int $scenarioProcessId): void
116 - {
117 - $nextStep = $this->scenarioStepClass->getStepByPreviousStepId($step->id);
118 -
119 - if (empty($nextStep)) {
120 - $this->ending($scenarioProcessId);
121 -
122 - return;
123 - }
124 -
125 - $scenarioQueue = new \stdClass();
126 - $scenarioQueue->scenario_process_id = $scenarioProcessId;
127 - $scenarioQueue->step_id = $nextStep->id;
128 - $timestampNextAction = time() + $this->calculateDelaySecondsToAdd($step->params);
129 - $scenarioQueue->execution_date = acym_date($timestampNextAction, 'Y-m-d H:i:s', false);
130 -
131 - $this->scenarioQueueClass->save($scenarioQueue);
132 - $this->scenarioQueueClass->deleteByStepIds([$step->id]);
133 -
134 - $this->createHistory($scenarioProcessId, ScenarioClass::TYPE_DELAY, 'success', $step->id, $step->params);
135 - }
136 -
137 - private function calculateDelaySecondsToAdd(array $stepDelayParams): int
138 - {
139 - if (empty($stepDelayParams['delay']) || empty($stepDelayParams['unit'])) {
140 - return 0;
141 - }
142 -
143 - return $stepDelayParams['delay'] * $stepDelayParams['unit'];
144 - }
145 -
146 - private function handleCondition(object $step, int $userId, int $scenarioProcessId): void
147 - {
148 - $conditionNotValidCount = 0;
149 -
150 - $query = new AutomationHelper();
151 - $query->where = ['user.id = '.$userId];
152 -
153 - $conditionOptions = $this->formatOptions($step->params['option'], $step->type);
154 - // Unused variable
155 - $number = 0;
156 - acym_trigger('onAcymProcessCondition_'.$step->params['condition'], [&$query, &$conditionOptions, &$number, &$conditionNotValidCount]);
157 - $this->scenarioQueueClass->deleteByStepIds([$step->id]);
158 -
159 - $conditionValid = $conditionNotValidCount === 0;
160 -
161 - $historyOptions = array_merge($conditionOptions, ['scenario_condition' => $step->params['condition']]);
162 - $this->createHistory($scenarioProcessId, ScenarioClass::TYPE_CONDITION, 'Condition is '.($conditionValid ? 'valid' : 'not valid'), $step->id, $historyOptions);
163 -
164 - $nextStep = $this->scenarioStepClass->getStepByPreviousConditionId($step->id, $conditionValid);
165 -
166 - if (empty($nextStep)) {
167 - $this->ending($scenarioProcessId);
168 -
169 - return;
170 - }
171 -
172 - $this->handleStep($nextStep, $userId, $scenarioProcessId);
173 - }
174 -
175 - private function formatOptions(array $options, string $type): array
176 - {
177 - $formattedOptions = [];
178 -
179 - switch ($type) {
180 - case ScenarioClass::TYPE_CONDITION:
181 - $regex = '/acym_condition\[conditions\]\[__numor__\]\[__numand__\]\[(.+)\]\[(.+)\]/';
182 - break;
183 - case ScenarioClass::TYPE_ACTION:
184 - $regex = '/acym_action\[actions\]\[__and__\]\[(.+)\]\[(.+)\]/';
185 - break;
186 - case 'trigger':
187 - $regex = '/\[triggers\]\[user\]\[(.+)\]\[(.+)\]/';
188 - break;
189 - default:
190 - $regex = '';
191 - }
192 -
193 - if (empty($regex)) {
194 - return $formattedOptions;
195 - }
196 -
197 - foreach ($options as $key => $option) {
198 - $formattedKey = preg_replace($regex, '$2', $key);
199 - if ($formattedKey === $key) {
200 - continue;
201 - }
202 - $formattedOptions[$formattedKey] = $option;
203 - }
204 -
205 - return $formattedOptions;
206 - }
207 -
208 - private function handleAction(object $step, int $userId, int $scenarioProcessId): void
209 - {
210 - $scenarioClass = new ScenarioClass();
211 - $markUnsubscribed = $scenarioClass->checkUserMarkedUnsubscribed($userId, $scenarioProcessId);
212 - if ($markUnsubscribed && $step->params['action'] === 'acy_send_email') {
213 - $historyClass = new HistoryClass();
214 - $historyClass->insert($userId, 'unsubscribed', [acym_translation('ACYM_SCENARIO_USER_UNSUBSCRIBED')]);
215 -
216 - return;
217 - }
218 -
219 - $query = new AutomationHelper();
220 - $query->where = ['user.id = '.$userId];
221 -
222 - $actionOptions = $this->formatOptions($step->params['option'], $step->type);
223 - $log = '';
224 - $report = '';
225 - try {
226 - $report = acym_trigger('onAcymProcessAction_'.$step->params['action'], [&$query, &$actionOptions]);
227 - $report = is_array($report) ? implode(', ', $report) : $report;
228 - } catch (\Exception $e) {
229 - $log = $e->getMessage();
230 - }
231 -
232 - $this->scenarioQueueClass->deleteByStepIds([$step->id]);
233 -
234 - $historyOptions = array_merge($actionOptions, ['scenario_action' => $step->params['action']]);
235 - $this->createHistory($scenarioProcessId, ScenarioClass::TYPE_CONDITION, 'Action completed: '.$report, $step->id, $historyOptions, $log);
236 -
237 - $nextStep = $this->scenarioStepClass->getStepByPreviousStepId($step->id);
238 -
239 - if (empty($nextStep)) {
240 - $this->ending($scenarioProcessId);
241 -
242 - return;
243 - }
244 -
245 - $this->handleStep($nextStep, $userId, $scenarioProcessId);
246 - }
247 -
248 - private function ending(int $scenarioProcessId): void
249 - {
250 - $this->createHistory($scenarioProcessId, 'ending', acym_translation('ACYM_SCENARIO_ENDED'));
251 -
252 - $this->scenarioProcessClass->endProcess($scenarioProcessId);
253 - }
254 -
255 - public function executeAvailableSteps(): void
256 - {
257 - $dateNowUtc = acym_date('now', 'Y-m-d H:i:s', false);
258 -
259 - $steps = $this->scenarioStepClass->getAvailableStepsByDate($dateNowUtc);
260 -
261 - if (empty($steps)) {
262 - return;
263 - }
264 -
265 - foreach ($steps as $step) {
266 - $this->handleStep($step, $step->user_id, $step->scenario_process_id);
267 - }
268 - }
269 -
270 - public function triggerTimeScenarios(): void
271 - {
272 - $userStatusTriggers = [];
273 - acym_trigger('onAcymDefineUserStatusCheckTriggers', [&$userStatusTriggers]);
274 -
275 - if (empty($userStatusTriggers)) {
276 - return;
277 - }
278 -
279 - $scenarioClass = new ScenarioClass();
280 - $scenarios = $scenarioClass->getAllActiveByTriggers($userStatusTriggers);
281 -
282 - if (empty($scenarios)) {
283 - return;
284 - }
285 -
286 - foreach ($scenarios as $scenario) {
287 - $nextExecution = $scenario->trigger_params['next_execution'] ?? null;
288 - $scenario->next_execution = $nextExecution;
289 -
290 - if (!empty($nextExecution) && $nextExecution > time()) {
291 - continue;
292 - }
293 -
294 - $firstStep = $this->scenarioStepClass->getFirstStepByScenarioId($scenario->id);
295 - if (empty($firstStep)) {
296 - acym_logError('ScenarioHelper::triggerTimeScenarios - No first step found for scenario '.$scenario->id);
297 - continue;
298 - }
299 -
300 - $execute = false;
301 - $options = $this->formatOptions($scenario->trigger_params['option'] ?? [], 'trigger');
302 - $options['time'] = time();
303 -
304 - $scenario->is_scenario = true;
305 - $scenario->triggers = [$scenario->trigger => $options];
306 -
307 - // Get the users matching the trigger
308 - acym_trigger('onAcymExecuteTrigger', [&$scenario, &$execute, &$options]);
309 -
310 - if ($nextExecution !== $scenario->next_execution) {
311 - $scenario->trigger_params['next_execution'] = $scenario->next_execution;
312 - $scenarioClass->save($scenario);
313 - }
314 -
315 - if (empty($options['userIds'])) {
316 - continue;
317 - }
318 -
319 - foreach ($options['userIds'] as $userId) {
320 - if ($scenario->trigger_once && $this->scenarioProcessClass->hasUserProcess($scenario->id, $userId)) {
321 - continue;
322 - }
323 -
324 - $scenarioProcess = new \stdClass();
325 - $scenarioProcess->scenario_id = $scenario->id;
326 - $scenarioProcess->user_id = $userId;
327 - $scenarioProcess->start_at = acym_date('now', 'Y-m-d H:i:s', false);
328 - $scenarioProcess->id = $this->scenarioProcessClass->save($scenarioProcess);
329 -
330 - $this->createHistory($scenarioProcess->id, 'trigger', 'success');
331 -
332 - $this->handleStep($firstStep, $userId, $scenarioProcess->id);
333 - }
334 - }
335 - }
336 -
337 - private function createHistory(int $scenarioProcessId, string $type, string $result, string $scenarioStepId = '', array $params = [], string $log = ''): void
338 - {
339 - $scenarioHistoryLine = new \stdClass();
340 - $scenarioHistoryLine->scenario_process_id = $scenarioProcessId;
341 - $scenarioHistoryLine->date = acym_date('now', 'Y-m-d H:i:s', false);
342 - $scenarioHistoryLine->type = $type;
343 - //TODO maybe add something more specific
344 - $scenarioHistoryLine->result = $result;
345 -
346 - if (!empty($scenarioStepId)) {
347 - $scenarioHistoryLine->scenario_step_id = $scenarioStepId;
348 - }
349 -
350 - if (!empty($params)) {
351 - $scenarioHistoryLine->params = $params;
352 - }
353 -
354 - if (!empty($log)) {
355 - $scenarioHistoryLine->log = $log;
356 - }
357 -
358 - $this->scenarioHistoryLineClass->save($scenarioHistoryLine);
359 - }
360 -
361 - public function getConditionValue(object $step): string
362 - {
363 - return $step->params['condition'];
364 - }
365 -
366 - public function getActionValue(object $step): string
367 - {
368 - return $step->params['action'];
369 - }
370 -}