PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.0.2
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.0.2
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
acymailing / back / Classes / AutomationClass.php

AutomationClass.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 11.0.2, at back/Classes/AutomationClass.php

370 lines 12.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace AcyMailing\Classes;
4
5 use AcyMailing\Helpers\AutomationHelper;
6 use AcyMailing\Helpers\PaginationHelper;
7 use AcyMailing\Core\AcymClass;
8
9 class AutomationClass extends AcymClass
10 {
11 const ACTIONS_TO_SKIP = ['acy_send_email'];
12
13 public bool $didAnAction = false;
14 public array $report = [];
15
16 public function __construct()
17 {
18 parent::__construct();
19
20 $this->table = 'automation';
21 $this->pkey = 'id';
22 $this->intColumns = [
23 'id',
24 'active',
25 'admin',
26 ];
27 }
28
29 public function getMatchingElements(array $settings = []): array
30 {
31 $query = 'SELECT * FROM #__acym_automation';
32 $queryCount = 'SELECT COUNT(id) AS total, SUM(active) AS totalActive FROM #__acym_automation';
33 $filters = [];
34
35 if (!empty($settings['search'])) {
36 $filters[] = 'name LIKE '.acym_escapeDB('%'.$settings['search'].'%');
37 }
38
39 if (!empty($filters)) {
40 $query .= ' WHERE ('.implode(') AND (', $filters).')';
41 $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
42 }
43
44 if (!empty($settings['status'])) {
45 $query .= empty($filters) ? ' WHERE ' : ' AND ';
46 $query .= 'active = '.($settings['status'] === 'active' ? '1' : '0');
47 }
48
49 if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) {
50 $query .= ' ORDER BY '.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn(strtoupper($settings['ordering_sort_order']));
51 } else {
52 $query .= ' ORDER BY ordering asc';
53 }
54
55 if (empty($settings['offset']) || $settings['offset'] < 0) {
56 $settings['offset'] = 0;
57 }
58
59 if (empty($settings['elementsPerPage']) || $settings['elementsPerPage'] < 1) {
60 $pagination = new PaginationHelper();
61 $settings['elementsPerPage'] = $pagination->getListLimit();
62 }
63
64 $elements = acym_loadObjectList($query, '', $settings['offset'], $settings['elementsPerPage']);
65 array_map([$this, 'fixTypes'], $elements);
66
67 return [
68 'elements' => $elements,
69 'total' => acym_loadObject($queryCount),
70 ];
71 }
72
73 public function save(object $element): ?int
74 {
75 foreach ($element as $oneAttribute => $value) {
76 if (empty($value)) {
77 continue;
78 }
79
80 $element->$oneAttribute = is_array($value) ? json_encode($value) : acym_stripTags($value);
81 }
82
83 return parent::save($element);
84 }
85
86 public function delete(array $elements): int
87 {
88 if (empty($elements)) return 0;
89
90 acym_arrayToInteger($elements);
91
92 $steps = acym_loadResultArray('SELECT id FROM #__acym_step WHERE automation_id IN ('.implode(',', $elements).')');
93 $stepClass = new StepClass();
94 $stepClass->delete($steps);
95
96 return parent::delete($elements);
97 }
98
99 /**
100 * @param mixed $trigger The identifier of the trigger
101 * @param array $data An array with data for user-type triggers (user id, order, event...)
102 */
103 public function trigger($triggers, array $data = []): void
104 {
105 if (!acym_level(ACYM_ENTERPRISE) || empty($triggers)) {
106 return;
107 }
108
109 if (!is_array($triggers)) {
110 $triggers = [$triggers];
111 }
112
113 $stepClass = new StepClass();
114 $actionClass = new ActionClass();
115 $conditionClass = new ConditionClass();
116
117 $steps = $stepClass->getActiveStepByTrigger($triggers);
118
119 $data['time'] = time();
120 foreach ($steps as $step) {
121 $newData = $data;
122 $execute = false;
123
124 // If we reached the next execution time we execute
125 // next_execution is only set if one of the time triggers like "asap" or "day" is selected in the automation
126 if (!empty($step->next_execution) && $step->next_execution <= $newData['time']) {
127 $execute = true;
128 }
129
130 // Call the triggers to set the next execution time
131 acym_trigger('onAcymExecuteTrigger', [&$step, &$execute, &$newData]);
132
133 $newData['automation'] = $this->getOneById($step->automation_id);
134
135 if ($execute) {
136 $step->last_execution = $newData['time'];
137 $conditions = $conditionClass->getConditionsByStepId($step->id);
138 if (!empty($conditions)) {
139 foreach ($conditions as $condition) {
140 if (!$this->verifyCondition($condition->conditions, $newData)) {
141 continue;
142 }
143
144 $actions = $actionClass->getActionsByStepId($step->id);
145 if (empty($actions)) continue;
146
147 foreach ($actions as $action) {
148 $this->execute($action, $newData);
149 }
150 }
151 }
152 }
153
154 $stepClass->save($step);
155 }
156 }
157
158 public function execute(object $action, array $data = []): bool
159 {
160 $usersTriggeringAction = empty($data['userIds']) ? [] : $data['userIds'];
161 $userTriggeringAction = empty($data['userId']) ? 0 : $data['userId'];
162
163 $action->actions = json_decode($action->actions ?? '[]', true);
164 if (empty($action->actions)) return false;
165
166 $isMassAction = false;
167 static $massAction = 0;
168 if (empty($action->id)) {
169 $action->id = $massAction--;
170 $isMassAction = true;
171 }
172
173 $action->filters = json_decode($action->filters ?? '[]', true);
174 if (empty($action->filters)) return false;
175
176
177 $initialWhere = ['1 = 1'];
178 $query = new AutomationHelper();
179 $query->removeFlag($action->id);
180
181 if (!empty($action->filters['type_filter']) && $action->filters['type_filter'] == 'user') {
182 if (empty($usersTriggeringAction)) {
183 if (empty($userTriggeringAction)) return false;
184
185 $initialWhere = ['user.id = '.intval($userTriggeringAction)];
186 } else {
187 acym_arrayToInteger($usersTriggeringAction);
188 $initialWhere = ['user.id IN ('.implode(', ', $usersTriggeringAction).')'];
189 }
190 }
191
192 $typeFilter = $action->filters['type_filter'] ?? null;
193
194 unset($action->filters['type_filter']);
195 if (empty($action->filters)) {
196 $query->where = $initialWhere;
197 }
198
199 //We do the or first
200 foreach ($action->filters as $or => $orValue) {
201 if (empty($orValue)) {
202 continue;
203 }
204 $num = 0;
205 $query->where = $initialWhere;
206 //Next the and
207 foreach ($orValue as $and => $andValue) {
208 $num++;
209 //Finally we have all names filter
210 foreach ($andValue as $filterName => $filterOptions) {
211 acym_trigger('onAcymProcessFilter_'.$filterName, [&$query, &$filterOptions, &$num]);
212 }
213 }
214
215 $query->addFlag($action->id);
216 }
217
218 $this->didAnAction = $this->didAnAction || $query->count() > 0;
219 foreach ($action->actions as $and => $andValue) {
220 foreach ($andValue as $actionName => $actionOptions) {
221 $this->report = array_merge(
222 $this->report,
223 acym_trigger(
224 'onAcymProcessAction_'.$actionName,
225 [&$query, &$actionOptions, ['automationAdmin' => !empty($data['automation']->admin), 'user_id' => $userTriggeringAction]]
226 )
227 );
228 $action->actions[$and][$actionName] = $actionOptions;
229 }
230 }
231
232 if (!$isMassAction) {
233 if ($typeFilter !== null) {
234 $action->filters['type_filter'] = $typeFilter;
235 }
236 $action->filters = json_encode($action->filters);
237 $action->actions = json_encode($action->actions);
238 $actionClass = new ActionClass();
239 $actionClass->save($action);
240 }
241
242 $query->removeFlag($action->id);
243
244 return $this->didAnAction;
245 }
246
247 private function verifyCondition(array $conditions, array $data = []): bool
248 {
249 if (empty($conditions)) {
250 return true;
251 }
252
253 $userTriggeringAction = empty($data['userId']) ? 0 : $data['userId'];
254 $usersTriggeringAction = empty($data['userIds']) ? [] : $data['userIds'];
255
256 $query = new AutomationHelper();
257 $initialWhere = ['1 = 1'];
258 if (!empty($conditions['type_condition']) && $conditions['type_condition'] == 'user') {
259 if (empty($usersTriggeringAction)) {
260 if (empty($userTriggeringAction)) return false;
261
262 $initialWhere = ['user.id = '.intval($userTriggeringAction)];
263 } else {
264 acym_arrayToInteger($usersTriggeringAction);
265 $initialWhere = ['user.id IN ('.implode(', ', $usersTriggeringAction).')'];
266 }
267 }
268 unset($conditions['type_condition']);
269
270 if (empty($conditions)) return true;
271
272 foreach ($conditions as $or => $orValue) {
273 if (empty($orValue)) continue;
274
275 // we increment id condition not validate
276 $conditionNotValid = 0;
277 $num = 0;
278 //Next the and
279 foreach ($orValue as $and => $andValue) {
280 $num++;
281 $query->where = $initialWhere;
282 //Finally we have all names condition
283 foreach ($andValue as $filterName => $filterOptions) {
284 acym_trigger('onAcymProcessCondition_'.$filterName, [&$query, &$filterOptions, &$num, &$conditionNotValid]);
285 }
286 }
287
288 if ($conditionNotValid == 0) return true;
289 }
290
291 return false;
292 }
293
294 public function triggerManual(array $automationIds): array
295 {
296 if (!acym_level(ACYM_ENTERPRISE) || empty($automationIds)) {
297 return [];
298 }
299
300 acym_arrayToInteger($automationIds);
301
302 $actionClass = new ActionClass();
303 $conditionClass = new ConditionClass();
304 $stepClass = new StepClass();
305
306 $executedCount = 0;
307 $skippedCount = 0;
308
309 foreach ($automationIds as $automationId) {
310 $steps = $stepClass->getStepsByAutomationId($automationId);
311 if (empty($steps)) {
312 continue;
313 }
314
315 $step = $steps[0];
316 if (!empty($step->triggers)) {
317 $step->triggers = json_decode($step->triggers, true);
318 }
319
320 if (!empty($step->triggers['type_trigger']) && $step->triggers['type_trigger'] !== 'classic') {
321 $skippedCount++;
322 continue;
323 }
324
325 $data = ['time' => time()];
326 $data['automation'] = $this->getOneById($step->automation_id);
327
328 $conditions = $conditionClass->getConditionsByStepId($step->id);
329 if (!empty($conditions)) {
330 foreach ($conditions as $condition) {
331 if (!$this->verifyCondition($condition->conditions, $data)) {
332 continue;
333 }
334
335 $actions = $actionClass->getActionsByStepId($step->id);
336 if (empty($actions)) {
337 continue;
338 }
339
340 foreach ($actions as $action) {
341 $this->execute($action, $data);
342 }
343 }
344 }
345
346 $executedCount++;
347 }
348
349 return [
350 'executed' => $executedCount,
351 'skipped' => $skippedCount,
352 ];
353 }
354
355 public function getAutomationsAdmin(array $ids = []): array
356 {
357 acym_arrayToInteger($ids);
358
359 $query = 'SELECT * FROM #__acym_automation WHERE `admin` = 1';
360 if (!empty($ids)) {
361 $query .= ' AND `id` IN ('.implode(', ', $ids).')';
362 }
363
364 $automations = acym_loadObjectList($query, 'name');
365 array_map([$this, 'fixTypes'], $automations);
366
367 return $automations;
368 }
369 }
370