PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.11.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.11.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
acymailing / back / Classes / ScenarioClass.php

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

321 lines 10.7 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\PaginationHelper;
6 use AcyMailing\Core\AcymClass;
7
8 class ScenarioClass extends AcymClass
9 {
10 const TYPE_DELAY = 'delay';
11 const TYPE_CONDITION = 'condition';
12 const TYPE_ACTION = 'action';
13
14 private ScenarioStepClass $scenarioStepClass;
15
16 private array $stepIdsToKeep = [];
17
18 public function __construct()
19 {
20 parent::__construct();
21
22 $this->table = 'scenario';
23 $this->pkey = 'id';
24 $this->scenarioStepClass = new ScenarioStepClass();
25 }
26
27 public function getMatchingElements(array $settings = []): array
28 {
29 $query = 'SELECT DISTINCT scenario.* FROM #__acym_scenario AS `scenario`';
30 $queryCount = 'SELECT COUNT(DISTINCT scenario.id) AS total FROM #__acym_scenario AS scenario';
31 $queryStatus = 'SELECT COUNT(DISTINCT scenario.id) AS `all`, SUM(`scenario`.`active`) AS active, SUM(IF(`scenario`.`active` = 0, 1, 0)) AS inactive FROM #__acym_scenario AS `scenario`';
32 $filters = [];
33
34 if (!empty($settings['search'])) {
35 $searchValue = acym_escapeDB('%'.$settings['search'].'%');
36 $filters[] = 'scenario.name LIKE '.$searchValue.' OR scenario.id = '.intval($settings['search']);
37 }
38
39 if (!empty($filters)) {
40 $queryStatus .= ' WHERE ('.implode(') AND (', $filters).')';
41 }
42
43 if (!empty($settings['status'])) {
44 switch ($settings['status']) {
45 case 'active':
46 $filters[] = 'scenario.active = 1';
47 break;
48 case 'inactive':
49 $filters[] = 'scenario.active = 0';
50 }
51 }
52
53 if (!empty($filters)) {
54 $query .= ' WHERE ('.implode(') AND (', $filters).')';
55 $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
56 }
57
58 if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) {
59 $query .= ' ORDER BY scenario.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn(strtoupper($settings['ordering_sort_order']));
60 }
61
62 if (empty($settings['offset']) || $settings['offset'] < 0) {
63 $settings['offset'] = 0;
64 }
65
66 if (empty($settings['elementsPerPage']) || $settings['elementsPerPage'] < 1) {
67 $pagination = new PaginationHelper();
68 $settings['elementsPerPage'] = $pagination->getListLimit();
69 }
70
71 return [
72 'elements' => acym_loadObjectList($query, 'id', $settings['offset'], $settings['elementsPerPage']),
73 'total' => acym_loadObject($queryCount),
74 'totalOverall' => acym_loadResult('SELECT COUNT(id) FROM #__acym_scenario'),
75 'scenariosNumberStatus' => acym_loadObjectList($queryStatus)[0],
76 ];
77 }
78
79 public function save(object $element): ?int
80 {
81 $flow = [];
82 if (!empty($element->flow)) {
83 $flow = json_decode($element->flow, true);
84
85 if (empty($flow[0]['params'])) {
86 return 0;
87 }
88
89 $element->trigger = $flow[0]['params']['trigger'];
90
91 if (!empty($element->id)) {
92 $scenario = $this->getOneById($element->id);
93 if (!empty($scenario->trigger_params['next_execution'])) {
94 $flow[0]['params']['next_execution'] = $scenario->trigger_params['next_execution'];
95 }
96 }
97
98 $element->trigger_params = json_encode($flow[0]['params']);
99 } elseif (!empty($element->trigger_params) && is_array($element->trigger_params)) {
100 $element->trigger_params = json_encode($element->trigger_params);
101 }
102
103 unset($element->flow);
104
105 $element->id = parent::save($element);
106
107 if (!empty($flow) && !empty($element->id)) {
108 $this->saveFlow($flow, $element->id);
109 }
110
111 return $element->id;
112 }
113
114 public function getOneById(int $id): ?object
115 {
116 $scenario = parent::getOneById($id);
117
118 if (empty($scenario->trigger_params)) {
119 return $scenario;
120 }
121
122 $scenario->trigger_params = json_decode($scenario->trigger_params, true);
123
124 return $scenario;
125 }
126
127 private function saveFlow(array $flow, int $scenarioId): void
128 {
129 if (!empty($flow[0]['children'][0])) {
130 $this->saveStep($flow[0]['children'][0], $scenarioId);
131 }
132 $this->cleanSteps($scenarioId);
133 }
134
135 private function saveStep(array $currentStep, int $scenarioId, ?string $previousStepId = null, ?int $conditionValid = null): void
136 {
137 if (isset($currentStep['conditionEnd'])) {
138 if ($currentStep['conditionEnd'] && !empty($currentStep['children'])) {
139 $isConditionValid = empty($currentStep['conditionValid']) ? 0 : 1;
140 $this->saveStep($currentStep['children'][0], $scenarioId, $previousStepId, $isConditionValid);
141 }
142
143 return;
144 }
145
146 switch ($currentStep['params']['type']) {
147 case self::TYPE_DELAY:
148 $type = self::TYPE_DELAY;
149 break;
150 case self::TYPE_CONDITION:
151 $type = self::TYPE_CONDITION;
152 break;
153 case self::TYPE_ACTION:
154 $type = self::TYPE_ACTION;
155 break;
156 default:
157 acym_enqueueMessage(acym_translation('ACYM_INVALID_STEP_TYPE'), 'error');
158
159 return;
160 }
161
162 $step = new \stdClass();
163 $step->id = $currentStep['slug'];
164 $step->previous_id = $previousStepId;
165 $step->type = $type;
166 $step->params = $currentStep['params'];
167 $step->scenario_id = $scenarioId;
168 $step->condition_valid = $conditionValid;
169
170 $this->scenarioStepClass->save($step);
171
172 $this->stepIdsToKeep[] = $step->id;
173
174 if (!empty($currentStep['children'])) {
175 foreach ($currentStep['children'] as $child) {
176 $this->saveStep($child, $scenarioId, $currentStep['slug']);
177 }
178 }
179 }
180
181 private function cleanSteps(int $scenarioId): void
182 {
183 $stepIdsToDelete = $this->scenarioStepClass->getAllStepsToDelete($scenarioId, $this->stepIdsToKeep);
184
185 if (empty($stepIdsToDelete)) {
186 return;
187 }
188
189 $scenarioQueueClass = new ScenarioQueueClass();
190 $scenarioQueueClass->deleteByStepIds($stepIdsToDelete);
191 $this->scenarioStepClass->delete($stepIdsToDelete);
192 }
193
194 private function formatScenario(object $scenario): ?object
195 {
196 if (empty($scenario)) {
197 return null;
198 }
199
200 $scenario->trigger_params = json_decode($scenario->trigger_params, true);
201
202 return $scenario;
203 }
204
205 public function getAllActiveByTriggers(array $triggerTypes): array
206 {
207 if (empty($triggerTypes)) {
208 return [];
209 }
210
211 $triggerTypes = array_map('acym_escapeDB', $triggerTypes);
212 $query = 'SELECT * FROM #__acym_scenario WHERE active = 1 AND `trigger` IN ('.implode(', ', $triggerTypes).') ORDER BY `ordering` ASC';
213
214 return array_map([$this, 'formatScenario'], acym_loadObjectList($query));
215 }
216
217 public function delete(array $elements): int
218 {
219 if (empty($elements)) {
220 return 0;
221 }
222
223 $escapedElements = array_map('acym_escapeDB', $elements);
224
225 $scenarioHistoryLineQuery = 'DELETE FROM #__acym_scenario_history_line WHERE scenario_process_id IN (SELECT id FROM #__acym_scenario_process WHERE scenario_id IN ('.implode(
226 ',',
227 $escapedElements
228 ).'))';
229 $scenarioQueueQuery = 'DELETE FROM #__acym_scenario_queue WHERE scenario_process_id IN (SELECT id FROM #__acym_scenario_process WHERE scenario_id IN ('.implode(
230 ',',
231 $escapedElements
232 ).'))';
233 $scenarioProcessQuery = 'DELETE FROM #__acym_scenario_process WHERE scenario_id IN ('.implode(',', $escapedElements).')';
234 $scenarioStepQuery = 'DELETE FROM #__acym_scenario_step WHERE scenario_id IN ('.implode(',', $escapedElements).')';
235 acym_query($scenarioHistoryLineQuery);
236 acym_query($scenarioQueueQuery);
237 acym_query($scenarioProcessQuery);
238 acym_query($scenarioStepQuery);
239
240 return parent::delete($elements);
241 }
242
243 public function duplicate(int $scenarioId): void
244 {
245 $scenarioStepClass = new ScenarioStepClass();
246
247 $scenario = $this->getOneById($scenarioId);
248
249 if (empty($scenario)) {
250 return;
251 }
252
253 unset($scenario->id);
254 $scenario->name = $scenario->name.' - '.acym_translation('ACYM_COPY');
255
256 $scenario->id = $this->save($scenario);
257
258 $scenarioSteps = $scenarioStepClass->getAllByScenarioId($scenarioId);
259
260 if (empty($scenarioSteps)) {
261 return;
262 }
263
264 $allStepIds = $scenarioStepClass->getAllStepIds();
265
266 $stepCorrespondence = [];
267
268 foreach ($scenarioSteps as $scenarioStep) {
269 $stepCorrespondence[$scenarioStep->id] = $scenarioStepClass->generateNewStepId($allStepIds);
270 $allStepIds[] = $stepCorrespondence[$scenarioStep->id];
271 }
272
273 foreach ($scenarioSteps as $scenarioStep) {
274 $scenarioStep->id = $stepCorrespondence[$scenarioStep->id];
275 $scenarioStep->previous_id = $stepCorrespondence[$scenarioStep->previous_id] ?? null;
276 $scenarioStep->scenario_id = $scenario->id;
277 $scenarioStepClass->save($scenarioStep);
278 }
279 }
280
281 public function markUserUnsubscribeFromScenario(int $userId, int $scenarioId): void
282 {
283 $query = 'UPDATE #__acym_scenario_process SET unsubscribed = 1 WHERE scenario_id = '.intval($scenarioId).' AND user_id = '.intval($userId);
284
285
286 acym_query($query);
287 }
288
289 public function getScenarioIdByMailId(int $mailId): ?int
290 {
291 $query = 'SELECT scenario_id
292 FROM #__acym_scenario_step
293 WHERE type = '.acym_escapeDB(self::TYPE_ACTION).'
294 AND params LIKE '.acym_escapeDB('%[mail_id]":"'.$mailId.'"%').'
295 LIMIT 1';
296
297 return acym_loadResult($query);
298 }
299
300 public function checkUserMarkedUnsubscribed(int $userId, int $scenarioProcessId): bool
301 {
302 $queryScenId = 'SELECT scenario_id
303 FROM #__acym_scenario_process
304 WHERE id = '.intval($scenarioProcessId).'
305 AND user_id = '.intval($userId).'
306 LIMIT 1';
307
308 $scenarioId = acym_loadResult($queryScenId);
309
310 $queryUnsubscribed = 'SELECT unsubscribed
311 FROM #__acym_scenario_process
312 WHERE scenario_id = '.intval($scenarioId).'
313 AND user_id = '.intval($userId).'
314 LIMIT 1';
315
316 $result = acym_loadResult($queryUnsubscribed);
317
318 return !empty($result);
319 }
320 }
321