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 -366 10.10.2 → 11.1.1 View file →
@@ -1,366 +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 - $scenario->is_scenario = true;
69 - $scenario->triggers = [$scenario->trigger => 1];
70 - $execute = false;
71 - $options = $this->formatOptions($scenario->trigger_params, 'trigger');
72 - $options['userId'] = $userId;
73 - $options['time'] = time();
74 - acym_trigger('onAcymExecuteTrigger', [&$scenario, &$execute, &$options]);
75 -
76 - if (!$execute) {
77 - continue;
78 - }
79 -
80 - $firstStep = $this->scenarioStepClass->getFirstStepByScenarioId($scenario->id);
81 -
82 - if (empty($firstStep)) {
83 - acym_logError('ScenarioHelper::trigger - No first step found for scenario '.$scenario->id);
84 - continue;
85 - }
86 -
87 - $scenarioProcess = new \stdClass();
88 - $scenarioProcess->scenario_id = $scenario->id;
89 - $scenarioProcess->user_id = $userId;
90 - $scenarioProcess->start_at = acym_date('now', 'Y-m-d H:i:s', false);
91 - $scenarioProcess->id = $this->scenarioProcessClass->save($scenarioProcess);
92 -
93 - $this->createHistory($scenarioProcess->id, 'trigger', 'success');
94 -
95 - $this->handleStep($firstStep, $userId, $scenarioProcess->id);
96 - }
97 - }
98 -
99 - private function handleStep(object $step, int $userId, int $scenarioProcessId): void
100 - {
101 - switch ($step->type) {
102 - case ScenarioClass::TYPE_DELAY:
103 - $this->handleDelay($step, $userId, $scenarioProcessId);
104 - break;
105 - case ScenarioClass::TYPE_CONDITION:
106 - $this->handleCondition($step, $userId, $scenarioProcessId);
107 - break;
108 - case ScenarioClass::TYPE_ACTION:
109 - $this->handleAction($step, $userId, $scenarioProcessId);
110 - break;
111 - }
112 - }
113 -
114 - private function handleDelay(object $step, int $userId, int $scenarioProcessId): void
115 - {
116 - $nextStep = $this->scenarioStepClass->getStepByPreviousStepId($step->id);
117 -
118 - if (empty($nextStep)) {
119 - $this->ending($scenarioProcessId);
120 -
121 - return;
122 - }
123 -
124 - $scenarioQueue = new \stdClass();
125 - $scenarioQueue->scenario_process_id = $scenarioProcessId;
126 - $scenarioQueue->step_id = $nextStep->id;
127 - $timestampNextAction = time() + $this->calculateDelaySecondsToAdd($step->params);
128 - $scenarioQueue->execution_date = acym_date($timestampNextAction, 'Y-m-d H:i:s', false);
129 -
130 - $this->scenarioQueueClass->save($scenarioQueue);
131 - $this->scenarioQueueClass->deleteByStepIds([$step->id]);
132 -
133 - $this->createHistory($scenarioProcessId, ScenarioClass::TYPE_DELAY, 'success', $step->id, $step->params);
134 - }
135 -
136 - private function calculateDelaySecondsToAdd(array $stepDelayParams): int
137 - {
138 - if (empty($stepDelayParams['delay']) || empty($stepDelayParams['unit'])) {
139 - return 0;
140 - }
141 -
142 - return $stepDelayParams['delay'] * $stepDelayParams['unit'];
143 - }
144 -
145 - private function handleCondition(object $step, int $userId, int $scenarioProcessId): void
146 - {
147 - $conditionNotValidCount = 0;
148 -
149 - $query = new AutomationHelper();
150 - $query->where = ['user.id = '.$userId];
151 -
152 - $conditionOptions = $this->formatOptions($step->params['option'], $step->type);
153 - $number = 0;
154 - acym_trigger('onAcymProcessCondition_'.$step->params['condition'], [&$query, &$conditionOptions, &$number, &$conditionNotValidCount]);
155 - $this->scenarioQueueClass->deleteByStepIds([$step->id]);
156 -
157 - $conditionValid = $conditionNotValidCount === 0;
158 -
159 - $historyOptions = array_merge($conditionOptions, ['scenario_condition' => $step->params['condition']]);
160 - $this->createHistory($scenarioProcessId, ScenarioClass::TYPE_CONDITION, 'Condition is '.($conditionValid ? 'valid' : 'not valid'), $step->id, $historyOptions);
161 -
162 - $nextStep = $this->scenarioStepClass->getStepByPreviousConditionId($step->id, $conditionValid);
163 -
164 - if (empty($nextStep)) {
165 - $this->ending($scenarioProcessId);
166 -
167 - return;
168 - }
169 -
170 - $this->handleStep($nextStep, $userId, $scenarioProcessId);
171 - }
172 -
173 - private function formatOptions(array $options, string $type): array
174 - {
175 - $formattedOptions = [];
176 -
177 - switch ($type) {
178 - case ScenarioClass::TYPE_CONDITION:
179 - $regex = '/acym_condition\[conditions\]\[__numor__\]\[__numand__\]\[(.+)\]\[(.+)\]/';
180 - break;
181 - case ScenarioClass::TYPE_ACTION:
182 - $regex = '/acym_action\[actions\]\[__and__\]\[(.+)\]\[(.+)\]/';
183 - break;
184 - case 'trigger':
185 - $regex = '/\[triggers\]\[user\]\[(.+)\]\[(.+)\]/';
186 - break;
187 - default:
188 - $regex = '';
189 - }
190 -
191 - if (empty($regex)) {
192 - return $formattedOptions;
193 - }
194 -
195 - foreach ($options as $key => $option) {
196 - $formattedKey = preg_replace($regex, '$2', $key);
197 - if ($formattedKey === $key) {
198 - continue;
199 - }
200 - $formattedOptions[$formattedKey] = $option;
201 - }
202 -
203 - return $formattedOptions;
204 - }
205 -
206 - private function handleAction(object $step, int $userId, int $scenarioProcessId): void
207 - {
208 - $scenarioClass = new ScenarioClass();
209 - $markUnsubscribed = $scenarioClass->checkUserMarkedUnsubscribed($userId, $scenarioProcessId);
210 - if ($markUnsubscribed && $step->params['action'] === 'acy_send_email') {
211 - $historyClass = new HistoryClass();
212 - $historyClass->insert($userId, 'unsubscribed', [acym_translation('ACYM_SCENARIO_USER_UNSUBSCRIBED')]);
213 -
214 - return;
215 - }
216 -
217 - $query = new AutomationHelper();
218 - $query->where = ['user.id = '.$userId];
219 -
220 - $actionOptions = $this->formatOptions($step->params['option'], $step->type);
221 - $log = '';
222 - $report = '';
223 - try {
224 - $report = acym_trigger('onAcymProcessAction_'.$step->params['action'], [&$query, &$actionOptions]);
225 - $report = is_array($report) ? implode(', ', $report) : $report;
226 - } catch (\Exception $e) {
227 - $log = $e->getMessage();
228 - }
229 -
230 - $this->scenarioQueueClass->deleteByStepIds([$step->id]);
231 -
232 - $historyOptions = array_merge($actionOptions, ['scenario_action' => $step->params['action']]);
233 - $this->createHistory($scenarioProcessId, ScenarioClass::TYPE_CONDITION, 'Action completed: '.$report, $step->id, $historyOptions, $log);
234 -
235 - $nextStep = $this->scenarioStepClass->getStepByPreviousStepId($step->id);
236 -
237 - if (empty($nextStep)) {
238 - $this->ending($scenarioProcessId);
239 -
240 - return;
241 - }
242 -
243 - $this->handleStep($nextStep, $userId, $scenarioProcessId);
244 - }
245 -
246 - private function ending(int $scenarioProcessId): void
247 - {
248 - $this->createHistory($scenarioProcessId, 'ending', acym_translation('ACYM_SCENARIO_ENDED'));
249 -
250 - $this->scenarioProcessClass->endProcess($scenarioProcessId);
251 - }
252 -
253 - public function executeAvailableSteps(): void
254 - {
255 - $dateNowUtc = acym_date('now', 'Y-m-d H:i:s', false);
256 -
257 - $steps = $this->scenarioStepClass->getAvailableStepsByDate($dateNowUtc);
258 -
259 - if (empty($steps)) {
260 - return;
261 - }
262 -
263 - foreach ($steps as $step) {
264 - $this->handleStep($step, $step->user_id, $step->scenario_process_id);
265 - }
266 - }
267 -
268 - public function triggerTimeScenarios(): void
269 - {
270 - $userStatusTriggers = [];
271 - acym_trigger('onAcymDefineUserStatusCheckTriggers', [&$userStatusTriggers]);
272 -
273 - if (empty($userStatusTriggers)) {
274 - return;
275 - }
276 -
277 - $scenarioClass = new ScenarioClass();
278 - $scenarios = $scenarioClass->getAllActiveByTriggers($userStatusTriggers);
279 -
280 - if (empty($scenarios)) {
281 - return;
282 - }
283 -
284 - foreach ($scenarios as $scenario) {
285 - $nextExecution = $scenario->trigger_params['next_execution'] ?? null;
286 - $scenario->next_execution = $nextExecution;
287 -
288 - if (!empty($nextExecution) && $nextExecution > time()) {
289 - continue;
290 - }
291 -
292 - $firstStep = $this->scenarioStepClass->getFirstStepByScenarioId($scenario->id);
293 - if (empty($firstStep)) {
294 - acym_logError('ScenarioHelper::triggerTimeScenarios - No first step found for scenario '.$scenario->id);
295 - continue;
296 - }
297 -
298 - $execute = false;
299 - $options = $this->formatOptions($scenario->trigger_params['option'] ?? [], 'trigger');
300 - $options['time'] = time();
301 -
302 - $scenario->is_scenario = true;
303 - $scenario->triggers = [$scenario->trigger => $options];
304 -
305 - acym_trigger('onAcymExecuteTrigger', [&$scenario, &$execute, &$options]);
306 -
307 - if ($nextExecution !== $scenario->next_execution) {
308 - $scenario->trigger_params['next_execution'] = $scenario->next_execution;
309 - $scenarioClass->save($scenario);
310 - }
311 -
312 - if (empty($options['userIds'])) {
313 - continue;
314 - }
315 -
316 - foreach ($options['userIds'] as $userId) {
317 - if ($scenario->trigger_once && $this->scenarioProcessClass->hasUserProcess($scenario->id, $userId)) {
318 - continue;
319 - }
320 -
321 - $scenarioProcess = new \stdClass();
322 - $scenarioProcess->scenario_id = $scenario->id;
323 - $scenarioProcess->user_id = $userId;
324 - $scenarioProcess->start_at = acym_date('now', 'Y-m-d H:i:s', false);
325 - $scenarioProcess->id = $this->scenarioProcessClass->save($scenarioProcess);
326 -
327 - $this->createHistory($scenarioProcess->id, 'trigger', 'success');
328 -
329 - $this->handleStep($firstStep, $userId, $scenarioProcess->id);
330 - }
331 - }
332 - }
333 -
334 - private function createHistory(int $scenarioProcessId, string $type, string $result, string $scenarioStepId = '', array $params = [], string $log = ''): void
335 - {
336 - $scenarioHistoryLine = new \stdClass();
337 - $scenarioHistoryLine->scenario_process_id = $scenarioProcessId;
338 - $scenarioHistoryLine->date = acym_date('now', 'Y-m-d H:i:s', false);
339 - $scenarioHistoryLine->type = $type;
340 - $scenarioHistoryLine->result = $result;
341 -
342 - if (!empty($scenarioStepId)) {
343 - $scenarioHistoryLine->scenario_step_id = $scenarioStepId;
344 - }
345 -
346 - if (!empty($params)) {
347 - $scenarioHistoryLine->params = $params;
348 - }
349 -
350 - if (!empty($log)) {
351 - $scenarioHistoryLine->log = $log;
352 - }
353 -
354 - $this->scenarioHistoryLineClass->save($scenarioHistoryLine);
355 - }
356 -
357 - public function getConditionValue(object $step): string
358 - {
359 - return $step->params['condition'];
360 - }
361 -
362 - public function getActionValue(object $step): string
363 - {
364 - return $step->params['action'];
365 - }
366 -}