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/Classes/QueueClass.php +0 -737 11.0.5 → 11.1.1 View file →
@@ -1,737 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Classes;
4 -
5 -use AcyMailing\Controllers\SegmentsController;
6 -use AcyMailing\Helpers\AutomationHelper;
7 -use AcyMailing\Core\AcymClass;
8 -
9 -class QueueClass extends AcymClass
10 -{
11 - public array $emailtypes = [];
12 -
13 - /**
14 - * Get campaigns depending on filters (search, status, pagination)
15 - */
16 - public function getMatchingCampaigns(array $settings): array
17 - {
18 - $queuedMails = acym_loadResultArray('SELECT DISTINCT mail_id FROM #__acym_queue');
19 - if (empty($queuedMails)) {
20 - return [
21 - 'elements' => [],
22 - 'total' => (object)['total' => 0],
23 - 'status' => [
24 - 'all' => 0,
25 - 'sending' => 0,
26 - 'paused' => 0,
27 - 'automation' => 0,
28 - 'followup' => 0,
29 - ],
30 - ];
31 - }
32 -
33 - $campaignClass = new CampaignClass();
34 - $mailStatClass = new MailStatClass();
35 - $mailClass = new MailClass();
36 -
37 - $queryCount = 'SELECT COUNT(DISTINCT mail.id) AS total
38 - FROM #__acym_mail AS mail
39 - LEFT JOIN #__acym_campaign AS campaign ON campaign.mail_id = mail.id OR campaign.mail_id = mail.parent_id';
40 -
41 - $query = 'SELECT
42 - mail.name,
43 - mail.subject,
44 - mail.type,
45 - mail.id,
46 - campaign.id AS campaign,
47 - COALESCE(campaign.sending_date, queue.min_sending_date) AS sending_date,
48 - campaign.sending_type,
49 - campaign.active,
50 - campaign.sending_params AS sending_params,
51 - queue.nbqueued,
52 - mail.language,
53 - mail.parent_id
54 - FROM #__acym_mail AS mail
55 - JOIN (
56 - SELECT mail_id, COUNT(*) AS nbqueued, MIN(sending_date) AS min_sending_date
57 - FROM #__acym_queue
58 - GROUP BY mail_id
59 - ) AS queue ON mail.id = queue.mail_id
60 - LEFT JOIN #__acym_campaign AS campaign
61 - ON mail.id = campaign.mail_id
62 - OR mail.parent_id = campaign.mail_id';
63 -
64 - // This query returns an array like "number of mails" => score. cf the equivalent in the list class to understand how it works
65 - $queryStatus = 'SELECT COUNT(DISTINCT mail.id) AS number, campaign.active
66 - FROM #__acym_mail AS mail
67 - LEFT JOIN #__acym_campaign AS campaign ON mail.id = campaign.mail_id';
68 -
69 - if (!empty($settings['tag'])) {
70 - $tagJoin = ' JOIN #__acym_tag AS tag
71 - ON (mail.id = tag.id_element OR mail.parent_id = tag.id_element)
72 - AND tag.type = "mail"
73 - AND tag.name = '.acym_escapeDB($settings['tag']);
74 - $query .= $tagJoin;
75 - $queryCount .= $tagJoin;
76 - $queryStatus .= ' JOIN #__acym_tag AS tag ON mail.id = tag.id_element AND tag.type = "mail" AND tag.name = '.acym_escapeDB($settings['tag']);
77 - }
78 -
79 - $filters = [];
80 - $filters[] = 'campaign.id IS NULL OR campaign.draft = 0';
81 -
82 - if (!empty($settings['search'])) {
83 - $filters[] = 'mail.subject LIKE '.acym_escapeDB('%'.$settings['search'].'%').' OR mail.name LIKE '.acym_escapeDB('%'.$settings['search'].'%');
84 - }
85 -
86 - $queryStatus .= ' WHERE ('.implode(') AND (', $filters).') AND mail.id IN ('.implode(',', $queuedMails).')';
87 -
88 - if (!empty($settings['status'])) {
89 - $allowedStatus = [
90 - 'sending' => 'campaign.active = 1',
91 - 'paused' => 'campaign.active = 0',
92 - 'automation' => 'mail.type = '.acym_escapeDB(MailClass::TYPE_AUTOMATION),
93 - 'followup' => 'mail.type = '.acym_escapeDB(MailClass::TYPE_FOLLOWUP),
94 - ];
95 -
96 - if (empty($allowedStatus[$settings['status']])) {
97 - die('Unauthorized filter: '.esc_html($settings['status']));
98 - }
99 -
100 - $filters[] = $allowedStatus[$settings['status']];
101 - }
102 -
103 - $queryCount .= ' WHERE ('.implode(') AND (', $filters).') AND mail.id IN ('.implode(',', $queuedMails).')';
104 - $query .= ' WHERE ('.implode(') AND (', $filters).')';
105 - $query .= ' ORDER BY queue.min_sending_date ASC';
106 -
107 - acym_query('SET SQL_BIG_SELECTS=1;');
108 - $results = [
109 - 'elements' => $mailClass->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['campaignsPerPage'])),
110 - 'total' => acym_loadObject($queryCount),
111 - ];
112 -
113 - $isMultilingual = acym_isMultilingual();
114 - $campaignRecipientsMultilingual = [];
115 -
116 - // Get the recipients
117 - $specialTypes = [];
118 - acym_trigger('getCampaignTypes', [&$specialTypes]);
119 -
120 - foreach ($results['elements'] as $i => $oneMail) {
121 - $results['elements'][$i]->sending_params = empty($oneMail->sending_params) ? [] : json_decode($oneMail->sending_params, true);
122 - if (in_array($oneMail->sending_type, $specialTypes)) {
123 - $results['elements'][$i]->iscampaign = false;
124 - $results['elements'][$i]->lists = acym_translation('ACYM_SPECIAL_MAIL_SENT_TO');
125 - $results['elements'][$i]->recipients = acym_loadResult('SELECT COUNT(*) FROM #__acym_queue WHERE mail_id = '.intval($oneMail->id));
126 - } elseif (empty($oneMail->campaign)) {
127 - $results['elements'][$i]->iscampaign = false;
128 - if ($oneMail->type === MailClass::TYPE_FOLLOWUP) {
129 - $results['elements'][$i]->lists = acym_translation('ACYM_MAIL_FROM_FOLLOWUP_SENT_TO');
130 - } else {
131 - $results['elements'][$i]->lists = acym_translation('ACYM_MAIL_FROM_AUTOMATION_SENT_TO');
132 - }
133 - $results['elements'][$i]->recipients = acym_loadResult('SELECT COUNT(*) FROM #__acym_queue WHERE mail_id = '.intval($oneMail->id));
134 - } else {
135 - $mailId = empty($oneMail->parent_id) ? $oneMail->id : $oneMail->parent_id;
136 - $results['elements'][$i]->iscampaign = true;
137 - $results['elements'][$i]->lists = acym_loadObjectList(
138 - 'SELECT l.color, l.name , l.id
139 - FROM #__acym_list AS l
140 - JOIN #__acym_mail_has_list AS ml ON ml.list_id = l.id
141 - WHERE ml.mail_id = '.intval($mailId),
142 - 'id'
143 - );
144 -
145 - if (isset($results['elements'][$i]->sending_params['abtest'])) {
146 - $isVersionB = $results['elements'][$i]->sending_params['abtest']['B'] == $results['elements'][$i]->id;
147 -
148 - if (empty($results['elements'][$i]->parent_id) || $isVersionB) {
149 - $results['elements'][$i]->recipients = intval($mailStatClass->getTotalSubscribersByMailId($results['elements'][$i]->id));
150 - } else {
151 - $results['elements'][$i]->recipients = intval($mailStatClass->getTotalSubscribersByMailIdWithChild($mailId));
152 - }
153 - } elseif ($isMultilingual) {
154 - if (empty($campaignRecipientsMultilingual[$oneMail->campaign])) {
155 - $automationHelper = new AutomationHelper();
156 -
157 - $listIds = array_keys($results['elements'][$i]->lists);
158 - acym_arrayToInteger($listIds);
159 -
160 - $automationHelper->join['user_list'] = ' #__acym_user_has_list AS user_list ON user_list.user_id = user.id AND user_list.list_id IN ('.implode(
161 - ',',
162 - $listIds
163 - ).') and user_list.status = 1 ';
164 - $automationHelper->leftjoin['mail'] = '`#__acym_mail` AS mail ON `mail`.`language` = `user`.language AND `mail`.`parent_id` = '.intval($mailId);
165 - $automationHelper->where[] = '`user_list`.`list_id` IN ('.implode(',', $listIds).') AND `user_list`.`status` = 1';
166 -
167 - $filters = $campaignClass->getFilterCampaign($oneMail->sending_params);
168 - if (!empty($filters)) {
169 - foreach ($filters as $orValues) {
170 - if (empty($orValues)) continue;
171 -
172 - $automationHelperSegment = new AutomationHelper();
173 - foreach ($orValues as $and => $andValues) {
174 - $and = intval($and);
175 - foreach ($andValues as $filterName => $options) {
176 - acym_trigger('onAcymProcessFilter_'.$filterName, [&$automationHelperSegment, &$options, &$and]);
177 - }
178 - }
179 - $automationHelperSegment->addFlag(SegmentsController::FLAG_COUNT);
180 - }
181 -
182 - $segmentMatchingCondition = 'LIKE';
183 - if (!empty($oneMail->sending_params['segment']['invert']) && $oneMail->sending_params['segment']['invert'] === 'exclude') {
184 - $segmentMatchingCondition = 'NOT LIKE';
185 - }
186 - $automationHelper->where[] = 'user.automation '.$segmentMatchingCondition.' "%a'.intval(SegmentsController::FLAG_COUNT).'a%"';
187 - }
188 -
189 - $automationHelper->groupBy = 'mail_id';
190 - $campaignRecipientsMultilingual[$oneMail->campaign] = acym_loadObjectList(
191 - $automationHelper->getQuery(['COUNT(DISTINCT user_list.`user_id`) AS elements', 'IF(mail.id IS NULL, '.intval($mailId).', `mail`.`id`) AS mail_id']),
192 - 'mail_id'
193 - );
194 - $automationHelper->removeFlag(SegmentsController::FLAG_COUNT);
195 - }
196 - $results['elements'][$i]->recipients = intval($campaignRecipientsMultilingual[$oneMail->campaign][$oneMail->id]->elements);
197 - } else {
198 - $results['elements'][$i]->recipients = intval($mailStatClass->getTotalSubscribersByMailId($mailId));
199 - }
200 - }
201 - }
202 -
203 - $automationNumber = acym_loadResult(
204 - 'SELECT COUNT(DISTINCT mail.id) FROM #__acym_mail AS mail
205 - JOIN #__acym_queue AS queue
206 - ON mail.id = queue.mail_id
207 - WHERE mail.type = '.acym_escapeDB(MailClass::TYPE_AUTOMATION)
208 - );
209 - $followupNumber = acym_loadResult(
210 - 'SELECT COUNT(DISTINCT mail.id)
211 - FROM #__acym_mail AS mail
212 - JOIN #__acym_queue AS queue
213 - ON mail.id = queue.mail_id
214 - WHERE mail.type = '.acym_escapeDB(MailClass::TYPE_FOLLOWUP)
215 - );
216 -
217 - $elementsPerStatus = acym_loadObjectList($queryStatus.' GROUP BY active');
218 - $queuedActiveCampaigns = 0;
219 - $queuedPausedCampaigns = 0;
220 - foreach ($elementsPerStatus as $element) {
221 - if (is_null($element->active)) {
222 - continue;
223 - }
224 -
225 - if (!empty($element->active)) {
226 - $queuedActiveCampaigns = intval($element->number);
227 - } else {
228 - $queuedPausedCampaigns = intval($element->number);
229 - }
230 - }
231 -
232 - $results['status'] = [
233 - 'all' => $queuedActiveCampaigns + $queuedPausedCampaigns + $automationNumber + $followupNumber,
234 - 'sending' => $queuedActiveCampaigns,
235 - 'paused' => $queuedPausedCampaigns,
236 - 'automation' => $automationNumber,
237 - 'followup' => $followupNumber,
238 - ];
239 -
240 - return $results;
241 - }
242 -
243 - /**
244 - * Get campaigns depending on filters (search, status, pagination)
245 - */
246 - public function getMatchingScheduledCampaigns(array $settings): array
247 - {
248 - $mailClass = new MailClass();
249 - $query = 'FROM #__acym_mail AS mail
250 - JOIN #__acym_campaign AS campaign ON mail.id = campaign.mail_id OR mail.parent_id = campaign.mail_id ';
251 -
252 - if (!empty($settings['tag'])) {
253 - $query .= ' JOIN #__acym_tag AS tag ON mail.id = tag.id_element AND tag.type = "mail" AND tag.name = '.acym_escapeDB($settings['tag']);
254 - }
255 -
256 - $filters = [
257 - 'campaign.draft = 0',
258 - 'campaign.sent = 0',
259 - 'campaign.sending_type = '.acym_escapeDB(CampaignClass::SENDING_TYPE_SCHEDULED),
260 - ];
261 -
262 - if (!empty($settings['search'])) {
263 - $filters[] = 'mail.subject LIKE '.acym_escapeDB('%'.$settings['search'].'%').' OR mail.name LIKE '.acym_escapeDB('%'.$settings['search'].'%');
264 - }
265 -
266 - $query .= ' WHERE ('.implode(') AND (', $filters).')';
267 -
268 - $queryCount = 'SELECT COUNT(DISTINCT mail.id) AS total '.$query;
269 - $query = 'SELECT mail.name, mail.subject, mail.id, campaign.sending_date, campaign.sending_params, mail.language, mail.parent_id '.$query.' GROUP BY mail.id ORDER BY campaign.sending_date ASC';
270 -
271 - acym_query('SET SQL_BIG_SELECTS=1;');
272 - $results['elements'] = $mailClass->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['campaignsPerPage']));
273 - $results['total'] = acym_loadObject($queryCount);
274 -
275 - foreach ($results['elements'] as $i => $oneMail) {
276 - $results['elements'][$i]->sending_params = empty($oneMail->sending_params) ? [] : json_decode($oneMail->sending_params, true);
277 - $mailId = empty($oneMail->parent_id) ? $oneMail->id : $oneMail->parent_id;
278 - $results['elements'][$i]->lists = acym_loadObjectList(
279 - 'SELECT l.color, l.name, l.id
280 - FROM #__acym_list AS l
281 - JOIN #__acym_mail_has_list AS ml ON ml.list_id = l.id
282 - WHERE ml.mail_id = '.intval($mailId),
283 - 'id'
284 - );
285 - }
286 -
287 - return $results;
288 - }
289 -
290 - /**
291 - * Get mails depending on filters (search, status, pagination)
292 - */
293 - public function getMatchingResults(array $settings): array
294 - {
295 - $query = 'FROM #__acym_queue AS queue
296 - JOIN #__acym_mail AS mail ON mail.id = queue.mail_id
297 - JOIN #__acym_user AS user ON queue.user_id = user.id ';
298 -
299 - $filters = [];
300 -
301 - if (!empty($settings['tag'])) {
302 - $query .= ' JOIN #__acym_tag AS tag ON queue.mail_id = tag.id_element AND tag.type = "mail" AND tag.name = '.acym_escapeDB($settings['tag']);
303 - }
304 -
305 - if (!empty($settings['search'])) {
306 - $searchColumns = [
307 - 'user.email',
308 - 'user.name',
309 - 'mail.subject',
310 - 'mail.name',
311 - ];
312 -
313 - $filters[] = implode(' LIKE '.acym_escapeDB('%'.$settings['search'].'%').' OR ', $searchColumns).' LIKE '.acym_escapeDB('%'.$settings['search'].'%');
314 - }
315 -
316 - if (!empty($filters)) {
317 - $query .= ' WHERE ('.implode(') AND (', $filters).')';
318 - }
319 -
320 - if (empty($settings['tag'])) {
321 - $queryCount = 'SELECT COUNT(queue.mail_id) AS total '.$query;
322 - } else {
323 - $queryCount = 'SELECT COUNT(DISTINCT queue.mail_id, queue.user_id) AS total '.$query;
324 - $query .= ' GROUP BY queue.mail_id, queue.user_id';
325 - }
326 -
327 - $query = 'SELECT mail.id, queue.sending_date, mail.name, mail.subject, user.email, user.name AS user_name, queue.user_id, queue.try '.$query.' ORDER BY queue.sending_date ASC';
328 -
329 - $mailClass = new MailClass();
330 -
331 - return [
332 - 'elements' => $mailClass->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['elementsPerPage'])),
333 - 'total' => acym_loadObject($queryCount),
334 - ];
335 - }
336 -
337 - public function scheduleReady(): ?int
338 - {
339 - $this->messages = [];
340 -
341 - $mailClass = new MailClass();
342 -
343 - $multilingualQuery = acym_isMultilingual() ? ' OR mail.parent_id = campaign.mail_id ' : '';
344 -
345 - $mailReady = $mailClass->decode(
346 - acym_loadObjectList(
347 - 'SELECT mail.id, campaign.sending_date, mail.name, campaign.mail_id AS parent_id, mail.language, campaign.sending_params
348 - FROM #__acym_campaign AS campaign
349 - JOIN #__acym_mail AS mail
350 - ON campaign.mail_id = mail.id '.$multilingualQuery.'
351 - WHERE campaign.sending_type = '.acym_escapeDB(CampaignClass::SENDING_TYPE_SCHEDULED).'
352 - AND campaign.draft = 0
353 - AND campaign.sending_date <= '.acym_escapeDB(acym_date('now', 'Y-m-d H:i:s', false)).'
354 - AND campaign.sent = 0',
355 - 'id'
356 - )
357 - );
358 -
359 - if (empty($mailReady)) {
360 - return null;
361 - }
362 -
363 - $nbQueue = [];
364 -
365 - foreach ($mailReady as $mailId => $mail) {
366 - // A/B test campaigns are queued later by CampaignClass::send(), so skip queueing here
367 - $sendingParams = $mail->sending_params ?? [];
368 - if (is_string($sendingParams)) {
369 - $sendingParams = json_decode($sendingParams, true) ?? [];
370 - }
371 -
372 - if (!empty($sendingParams['abtest']['repartition'])) {
373 - $nbQueue[$mailId] = 0;
374 - } else {
375 - $nbQueue[$mailId] = $this->queue($mail);
376 - $this->messages[] = acym_translationSprintf('ACYM_ADDED_QUEUE_SCHEDULE', $nbQueue[$mailId], '<b>'.$mail->name.'</b>');
377 - }
378 - }
379 -
380 - $mailIds = array_keys($mailReady);
381 - acym_arrayToInteger($mailIds);
382 - $campaigns = acym_loadObjectList('SELECT id, mail_id FROM #__acym_campaign WHERE mail_id IN ('.implode(',', $mailIds).')');
383 - $campaignClass = new CampaignClass();
384 - foreach ($campaigns as $campaign) {
385 - $result = $campaignClass->send($campaign->id, $nbQueue[$campaign->mail_id]);
386 - if (!empty($result) || !acym_isMultilingual()) {
387 - continue;
388 - }
389 -
390 - $translatedMails = acym_loadResultArray('SELECT id FROM #__acym_mail WHERE id != '.intval($campaign->mail_id).' AND parent_id = '.intval($campaign->mail_id));
391 - if (empty($translatedMails)) {
392 - continue;
393 - }
394 -
395 - foreach ($translatedMails as $translatedMailId) {
396 - if (!empty($nbQueue[$translatedMailId])) {
397 - $campaignClass->send($campaign->id, $nbQueue[$translatedMailId]);
398 - }
399 - }
400 - }
401 -
402 - return count($mailReady);
403 - }
404 -
405 - public function delete(array $elements): int
406 - {
407 - if (empty($elements)) return 0;
408 - acym_arrayToInteger($elements);
409 -
410 - $query = 'DELETE FROM #__acym_queue WHERE mail_id IN ('.implode(',', $elements).')';
411 - $result = acym_query($query);
412 -
413 - acym_query('UPDATE #__acym_campaign SET draft = 1, active = 1 WHERE mail_id IN ('.implode(',', $elements).')');
414 -
415 - if (!$result) {
416 - return 0;
417 - }
418 -
419 - return $result;
420 - }
421 -
422 - public function deleteQueuedByUserIds(array $userIds, ?int $mailId = null): int
423 - {
424 - acym_arrayToInteger($userIds);
425 - if (empty($userIds)) {
426 - return 0;
427 - }
428 -
429 - $query = 'DELETE FROM #__acym_queue WHERE user_id IN ('.implode(',', $userIds).')';
430 - if (!empty($mailId)) {
431 - $query .= ' AND mail_id = '.intval($mailId);
432 - }
433 -
434 - try {
435 - $nbDeleted = acym_query($query);
436 -
437 - if ($nbDeleted === false) {
438 - $this->errors[] = acym_getDBError();
439 -
440 - return 0;
441 - }
442 -
443 - return (int)$nbDeleted;
444 - } catch (\Exception $e) {
445 - $this->errors[] = $e->getMessage();
446 -
447 - return 0;
448 - }
449 - }
450 -
451 - public function getReady(int $startFrom, int $limit, int $mailId = 0): array
452 - {
453 - if (empty($limit)) {
454 - return [];
455 - }
456 -
457 - $query = 'SELECT queue.*, campaign.sending_params AS sending_params FROM #__acym_queue AS queue';
458 - $query .= ' JOIN #__acym_user AS user ON queue.`user_id` = user.`id` ';
459 - $query .= ' JOIN #__acym_mail AS mail ON queue.`mail_id` = mail.`id` ';
460 - $query .= ' LEFT JOIN #__acym_campaign AS campaign ON campaign.`mail_id` = mail.`id` ';
461 - $query .= ' WHERE user.active = 1
462 - AND queue.`sending_date` <= '.acym_escapeDB(acym_date('now', 'Y-m-d H:i:s', false)).'
463 - AND (campaign.mail_id IS NULL
464 - OR (campaign.`active` = 1
465 - AND campaign.`draft` = 0
466 - )
467 - )';
468 -
469 - if ($this->config->get('require_confirmation', 1) == 1) {
470 - $query .= ' AND (user.confirmed = 1 OR mail.type = '.acym_escapeDB(MailClass::TYPE_NOTIFICATION).' OR mail.name LIKE "%confirm%")';
471 - }
472 -
473 - if (!empty($this->emailtypes)) {
474 - foreach ($this->emailtypes as &$oneType) {
475 - $oneType = acym_escapeDB($oneType);
476 - }
477 - $query .= ' AND mail.type IN ('.implode(', ', $this->emailtypes).')';
478 - }
479 -
480 - if (!empty($mailId)) {
481 - $query .= ' AND queue.`mail_id` = '.intval($mailId);
482 - }
483 -
484 - // We don't display this option in the configuration anymore but we use its value if it's set in the database
485 - $sendOrder = $this->config->get('sendorder');
486 - if (empty($sendOrder)) {
487 - $order = 'queue.`user_id` ASC';
488 - } elseif ($sendOrder === 'rand') {
489 - $order = 'RAND()';
490 - } else {
491 - $sendOrder = str_replace('subid', 'user_id', $sendOrder);
492 - $ordering = explode(',', $sendOrder);
493 - $order = 'queue.`'.acym_secureDBColumn(trim($ordering[0])).'` '.acym_secureDBColumn(trim($ordering[1] ?? 'ASC'));
494 - }
495 -
496 - $query .= ' ORDER BY queue.`priority` ASC, queue.`sending_date` ASC, '.$order;
497 - // You can add a "startqueue" parameter to the url so Acy will not load the first e-mails but will start directly with the 300 or 500 or...
498 - $query .= ' LIMIT '.intval($startFrom).','.intval($limit);
499 -
500 - try {
501 - $results = acym_loadObjectList($query);
502 - } catch (\Exception $e) {
503 - $results = null;
504 - }
505 -
506 - if ($results === null) {
507 - // We got an issue here... maybe the table is crashed so we will repair it.
508 - acym_query('REPAIR TABLE #__acym_queue, #__acym_user, #__acym_mail, #__acym_campaign');
509 - }
510 -
511 - if (empty($results)) {
512 - return [];
513 - }
514 -
515 - // This comment doesn't make any sense
516 - //We update the first entry from the queue and change its sending_date with +1 so it does not get sent immediately after in case of we had an issue (a time out execution)...
517 - //That way e-mails which can't be sent will be sent at the end and we will be able to clean the queue and don't care about what's left in the queue any more
518 - //Also it will avoid the same user to receive messages again and again and again in case of there is a problem
519 - $firstElementQueued = reset($results);
520 - acym_query(
521 - 'UPDATE #__acym_queue
522 - SET sending_date = DATE_ADD(sending_date, INTERVAL 1 SECOND)
523 - WHERE mail_id = '.intval($firstElementQueued->mail_id).' AND user_id = '.intval($firstElementQueued->user_id).'
524 - LIMIT 1'
525 - );
526 -
527 - return $results;
528 - }
529 -
530 - public function delayFailed(int $mailId, array $userIds): void
531 - {
532 - acym_arrayToInteger($userIds);
533 - if (empty($mailId) || empty($userIds)) {
534 - return;
535 - }
536 -
537 - acym_query(
538 - 'UPDATE #__acym_queue
539 - SET sending_date = DATE_ADD(sending_date, INTERVAL 1 HOUR), try = try +1
540 - WHERE mail_id = '.intval($mailId).'
541 - AND user_id IN ('.implode(',', $userIds).')'
542 - );
543 - }
544 -
545 - public function delayAll(int $hours): void
546 - {
547 - if ($hours < 1) {
548 - return;
549 - }
550 -
551 - acym_query(
552 - 'UPDATE #__acym_queue
553 - SET sending_date = DATE_ADD(sending_date, INTERVAL '.$hours.' HOUR)
554 - WHERE sending_date < DATE_ADD(NOW(), INTERVAL '.intval($hours).' HOUR)'
555 - );
556 - }
557 -
558 - public function getMailReceivers(object $mail, bool $onlyNew = false): AutomationHelper
559 - {
560 - if (empty($mail->sending_params)) {
561 - $sendingParams = [];
562 - $mail->filters = [];
563 - } else {
564 - $sendingParams = is_array($mail->sending_params) ? $mail->sending_params : json_decode($mail->sending_params, true);
565 -
566 - $campaignClass = new CampaignClass();
567 - $mail->filters = $campaignClass->getFilterCampaign($sendingParams);
568 -
569 - if (!empty($sendingParams['resendTarget']) && 'new' === $sendingParams['resendTarget']) {
570 - $onlyNew = true;
571 - }
572 - }
573 -
574 - $automationHelper = new AutomationHelper();
575 - $automationHelper->join['userlist'] = ' #__acym_user_has_list AS userlist ON user.id = userlist.user_id';
576 - $automationHelper->join['maillist'] = ' #__acym_mail_has_list AS maillist ON userlist.list_id = maillist.list_id';
577 - $automationHelper->where = [
578 - 'userlist.status = 1',
579 - 'maillist.mail_id = '.intval(empty($mail->parent_id) ? $mail->id : $mail->parent_id),
580 - ];
581 -
582 - // Send this version only to the users with the correct language
583 - if (!$onlyNew && acym_isMultilingual()) {
584 - $where = 'user.language = '.acym_escapeDB($mail->language);
585 - if ($mail->id == $mail->parent_id) {
586 - //TODO check if a user with no language will receive every versions or only the main one
587 - $where .= ' OR user.language = "" OR user.language NOT IN (SELECT language FROM #__acym_mail WHERE parent_id = '.intval($mail->id).')';
588 - }
589 - $automationHelper->where[] = $where;
590 - }
591 -
592 - if ($this->config->get('require_confirmation', 1) == 1) {
593 - $automationHelper->where[] = '`user`.`confirmed` = 1';
594 - }
595 -
596 - if ($onlyNew) {
597 - $automationHelper->leftjoin['us'] = '`#__acym_user_stat` AS `us` ON `us`.`user_id` = `user`.`id` AND `us`.`mail_id` IN (SELECT id FROM #__acym_mail WHERE parent_id = '.intval(
598 - $mail->id
599 - ).' OR id = '.intval($mail->id).')';
600 - $automationHelper->where[] = '`us`.`user_id` IS NULL';
601 -
602 - // Do not count the disabled user for the resend counter on summary
603 - $automationHelper->where[] = '`user`.`active` = 1';
604 - }
605 -
606 - $automationHelper->removeFlag(SegmentsController::FLAG_USERS);
607 - $automationHelper->removeFlag(SegmentsController::FLAG_COUNT);
608 -
609 - // Handle potential segment
610 - if (empty($mail->filters)) {
611 - return $automationHelper;
612 - }
613 -
614 - // Mark users matching the segment
615 - foreach ($mail->filters as $orValues) {
616 - if (empty($orValues)) continue;
617 -
618 - $automationHelperSegment = new AutomationHelper();
619 - foreach ($orValues as $and => $andValues) {
620 - $and = intval($and);
621 - foreach ($andValues as $filterName => $options) {
622 - acym_trigger('onAcymProcessFilter_'.$filterName, [&$automationHelperSegment, &$options, &$and]);
623 - }
624 - }
625 - $automationHelperSegment->addFlag(SegmentsController::FLAG_COUNT);
626 - }
627 -
628 - $segmentMatchingCondition = 'LIKE';
629 - if (!empty($sendingParams['segment']['invert']) && $sendingParams['segment']['invert'] === 'exclude') {
630 - $segmentMatchingCondition = 'NOT LIKE';
631 - }
632 - $automationHelper->where[] = 'user.automation '.$segmentMatchingCondition.' "%a'.intval(SegmentsController::FLAG_COUNT).'a%"';
633 -
634 - return $automationHelper;
635 - }
636 -
637 - public function queue(object $mail): int
638 - {
639 - $automationHelper = $this->getMailReceivers($mail);
640 - // Only queue enabled users
641 - $automationHelper->where[] = '`user`.`active` = 1';
642 -
643 - $priority = $this->config->get('priority_newsletter', 3);
644 - $select = [intval($mail->id), 'userlist.user_id', acym_escapeDB($mail->sending_date), intval($priority), '0'];
645 - $inserted = acym_query('INSERT IGNORE INTO #__acym_queue (`mail_id`, `user_id`, `sending_date`, `priority`, `try`) ('.$automationHelper->getQuery($select).')');
646 -
647 - $automationHelper->removeFlag(SegmentsController::FLAG_COUNT);
648 -
649 - return (int)$inserted;
650 - }
651 -
652 - public function addQueue(int $userId, int $mailId, string $sendingDate): int
653 - {
654 - $priority = $this->config->get('priority_newsletter', 3);
655 -
656 - return (int)acym_query(
657 - 'INSERT IGNORE INTO #__acym_queue (`mail_id`, `user_id`, `sending_date`, `priority`, `try`) VALUES ('.intval($mailId).', '.intval($userId).', '.acym_escapeDB(
658 - $sendingDate
659 - ).', '.intval($priority).', 0)'
660 - );
661 - }
662 -
663 - public function unpauseCampaign(int $campaignId, int $active): void
664 - {
665 - if (acym_query('UPDATE #__acym_campaign SET active = '.intval($active).' WHERE id = '.intval($campaignId))) {
666 - acym_enqueueMessage(acym_translation($active ? 'ACYM_UNPAUSE_CAMPAIGN_SUCCESSFUL' : 'ACYM_PAUSE_CAMPAIGN_SUCCESSFUL'), "success");
667 - } else {
668 - acym_enqueueMessage(acym_translation($active ? 'ACYM_UNPAUSE_CAMPAIGN_FAIL' : 'ACYM_PAUSE_CAMPAIGN_FAIL'), "error");
669 - }
670 - }
671 -
672 - public function emptyQueue(): int
673 - {
674 - return (int)acym_query('DELETE FROM `#__acym_queue`');
675 - }
676 -
677 - public function cleanQueue(): int
678 - {
679 - $twoDaysEarlier = acym_date(time() - 172800, 'Y-m-d H:i:s', false);
680 -
681 - $conditionUser = '`user`.`active` = 0';
682 - if ($this->config->get('require_confirmation', 1) == 1) {
683 - $conditionUser .= ' OR `user`.`confirmed` = 0';
684 - }
685 -
686 - $numberOfDaysToWait = $this->config->get('queue_delete_days', 0);
687 - $conditionDateDelete = '';
688 - if (!empty($numberOfDaysToWait)) {
689 - $dateTimeConditionDelete = acym_date(time() - ($numberOfDaysToWait * 86400), 'Y-m-d H:i:s', false);
690 - $conditionDateDelete = ' OR (`queue`.`sending_date` < '.acym_escapeDB($dateTimeConditionDelete).')';
691 - }
692 -
693 - return (int)acym_query(
694 - 'DELETE `queue`.*
695 - FROM `#__acym_queue` AS `queue`
696 - JOIN `#__acym_user` AS `user` ON `queue`.`user_id` = `user`.`id`
697 - WHERE (('.$conditionUser.') AND `queue`.`sending_date` < '.acym_escapeDB($twoDaysEarlier).') '.$conditionDateDelete
698 - );
699 - }
700 -
701 - public function isSendingFinished(int $mailId): bool
702 - {
703 - $mailClass = new MailClass();
704 - $mail = $mailClass->getOneById($mailId);
705 -
706 - if (empty($mail) || $mailClass->isTransactionalMail($mail)) return false;
707 -
708 - $filters = [
709 - '`queue`.`mail_id` = '.intval($mailId),
710 - '`user`.`active` = 1',
711 - ];
712 - if ($this->config->get('require_confirmation')) {
713 - $filters[] = '`user`.`confirmed` = 1';
714 - }
715 -
716 - $res = intval(
717 - acym_loadResult(
718 - 'SELECT COUNT(`queue`.`mail_id`)
719 - FROM #__acym_queue AS `queue`
720 - JOIN #__acym_user AS `user`
721 - ON `queue`.`user_id` = `user`.`id`
722 - WHERE '.implode(' AND ', $filters)
723 - )
724 - );
725 -
726 - return empty($res);
727 - }
728 -
729 - public function getQueueParams(int $mailId, int $userId): array
730 - {
731 - $query = acym_loadObject(
732 - 'SELECT `params` FROM #__acym_queue WHERE `user_id` = '.intval($userId).' AND `mail_id` = '.$mailId
733 - );
734 -
735 - return empty($query) ? [] : json_decode((string)$query->params, true);
736 - }
737 -}