PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
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 +192 -114 10.0.1 → 11.1.0 View file →
@@ -7,28 +7,73 @@
7 7 use AcyMailing\Core\AcymClass;
8 8
9 9 class QueueClass extends AcymClass
10 10 {
11 - public $emailtypes;
11 + public array $emailtypes = [];
12 12
13 - public function getMatchingCampaigns($settings)
13 + /**
14 + * Get campaigns depending on filters (search, status, pagination)
15 + */
16 + public function getMatchingCampaigns(array $settings): array
14 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 +
15 33 $campaignClass = new CampaignClass();
16 34 $mailStatClass = new MailStatClass();
17 35 $mailClass = new MailClass();
18 - $query = 'FROM #__acym_mail AS mail
19 - JOIN #__acym_queue AS queue ON mail.id = queue.mail_id
20 - LEFT JOIN #__acym_campaign AS campaign ON mail.id = campaign.mail_id OR mail.parent_id = campaign.mail_id';
21 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
22 65 $queryStatus = 'SELECT COUNT(DISTINCT mail.id) AS number, campaign.active
23 66 FROM #__acym_mail AS mail
24 - JOIN #__acym_queue AS queue ON queue.mail_id = mail.id
25 67 LEFT JOIN #__acym_campaign AS campaign ON mail.id = campaign.mail_id';
26 68
27 69 if (!empty($settings['tag'])) {
28 - $query .= ' JOIN #__acym_tag AS tag ON (mail.id = tag.id_element OR mail.parent_id = tag.id_element) AND tag.type = "mail" AND tag.name = '.acym_escapeDB(
29 - $settings['tag']
30 - );
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;
31 76 $queryStatus .= ' JOIN #__acym_tag AS tag ON mail.id = tag.id_element AND tag.type = "mail" AND tag.name = '.acym_escapeDB($settings['tag']);
32 77 }
33 78
34 79 $filters = [];
@@ -37,11 +82,9 @@
37 82 if (!empty($settings['search'])) {
38 83 $filters[] = 'mail.subject LIKE '.acym_escapeDB('%'.$settings['search'].'%').' OR mail.name LIKE '.acym_escapeDB('%'.$settings['search'].'%');
39 84 }
40 85
41 - if (!empty($filters)) {
42 - $queryStatus .= ' WHERE ('.implode(') AND (', $filters).')';
43 - }
86 + $queryStatus .= ' WHERE ('.implode(') AND (', $filters).') AND mail.id IN ('.implode(',', $queuedMails).')';
44 87
45 88 if (!empty($settings['status'])) {
46 89 $allowedStatus = [
47 90 'sending' => 'campaign.active = 1',
@@ -50,31 +93,28 @@
50 93 'followup' => 'mail.type = '.acym_escapeDB(MailClass::TYPE_FOLLOWUP),
51 94 ];
52 95
53 96 if (empty($allowedStatus[$settings['status']])) {
54 - die('Unauthorized filter: '.acym_escape($settings['status']));
97 + die('Unauthorized filter: '.esc_html($settings['status']));
55 98 }
56 99
57 100 $filters[] = $allowedStatus[$settings['status']];
58 101 }
59 102
60 - if (!empty($filters)) {
61 - $query .= ' WHERE ('.implode(') AND (', $filters).')';
62 - }
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';
63 106
64 - $queryCount = 'SELECT COUNT(DISTINCT mail.id) '.$query;
65 - $query .= ' GROUP BY mail.id';
66 -
67 - $query = 'SELECT mail.name, mail.subject, mail.type, mail.id, campaign.id AS campaign, IF(campaign.sending_date IS NULL, queue.sending_date, campaign.sending_date) AS sending_date, campaign.sending_type, campaign.active, campaign.sending_params AS sending_params, COUNT(queue.mail_id) AS nbqueued, mail.language, mail.parent_id '.$query.' ORDER BY queue.sending_date ASC';
68 -
69 107 acym_query('SET SQL_BIG_SELECTS=1;');
70 - $results['elements'] = $mailClass->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['campaignsPerPage']));
71 - $results['total'] = acym_loadResult($queryCount);
108 + $results = [
109 + 'elements' => $mailClass->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['campaignsPerPage'])),
110 + 'total' => acym_loadObject($queryCount),
111 + ];
72 112
73 113 $isMultilingual = acym_isMultilingual();
74 114 $campaignRecipientsMultilingual = [];
75 - $automationHelper = new AutomationHelper();
76 115
116 + // Get the recipients
77 117 $specialTypes = [];
78 118 acym_trigger('getCampaignTypes', [&$specialTypes]);
79 119
80 120 foreach ($results['elements'] as $i => $oneMail) {
@@ -111,8 +151,10 @@
111 151 $results['elements'][$i]->recipients = intval($mailStatClass->getTotalSubscribersByMailIdWithChild($mailId));
112 152 }
113 153 } elseif ($isMultilingual) {
114 154 if (empty($campaignRecipientsMultilingual[$oneMail->campaign])) {
155 + $automationHelper = new AutomationHelper();
156 +
115 157 $listIds = array_keys($results['elements'][$i]->lists);
116 158 acym_arrayToInteger($listIds);
117 159
118 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(
@@ -171,17 +213,27 @@
171 213 ON mail.id = queue.mail_id
172 214 WHERE mail.type = '.acym_escapeDB(MailClass::TYPE_FOLLOWUP)
173 215 );
174 216
175 - $elementsPerStatus = acym_loadObjectList($queryStatus.' GROUP BY active', 'active');
176 - foreach ($elementsPerStatus as $i => $element) {
177 - $elementsPerStatus[$i] = empty($element->number) ? 0 : $element->number;
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 + }
178 230 }
179 231
180 232 $results['status'] = [
181 - 'all' => array_sum($elementsPerStatus) + $automationNumber + $followupNumber,
182 - 'sending' => $elementsPerStatus[1] ?? 0,
183 - 'paused' => $elementsPerStatus[0] ?? 0,
233 + 'all' => $queuedActiveCampaigns + $queuedPausedCampaigns + $automationNumber + $followupNumber,
234 + 'sending' => $queuedActiveCampaigns,
235 + 'paused' => $queuedPausedCampaigns,
184 236 'automation' => $automationNumber,
185 237 'followup' => $followupNumber,
186 238 ];
187 239
@@ -187,11 +239,13 @@
187 239
188 240 return $results;
189 241 }
190 242
191 - public function getMatchingScheduledCampaigns($settings)
243 + /**
244 + * Get campaigns depending on filters (search, status, pagination)
245 + */
246 + public function getMatchingScheduledCampaigns(array $settings): array
192 247 {
193 - $campaignClass = new CampaignClass();
194 248 $mailClass = new MailClass();
195 249 $query = 'FROM #__acym_mail AS mail
196 250 JOIN #__acym_campaign AS campaign ON mail.id = campaign.mail_id OR mail.parent_id = campaign.mail_id ';
197 251
@@ -201,9 +255,9 @@
201 255
202 256 $filters = [
203 257 'campaign.draft = 0',
204 258 'campaign.sent = 0',
205 - 'campaign.sending_type = '.acym_escapeDB($campaignClass->getConstScheduled()),
259 + 'campaign.sending_type = '.acym_escapeDB(CampaignClass::SENDING_TYPE_SCHEDULED),
206 260 ];
207 261
208 262 if (!empty($settings['search'])) {
209 263 $filters[] = 'mail.subject LIKE '.acym_escapeDB('%'.$settings['search'].'%').' OR mail.name LIKE '.acym_escapeDB('%'.$settings['search'].'%');
@@ -208,18 +262,16 @@
208 262 if (!empty($settings['search'])) {
209 263 $filters[] = 'mail.subject LIKE '.acym_escapeDB('%'.$settings['search'].'%').' OR mail.name LIKE '.acym_escapeDB('%'.$settings['search'].'%');
210 264 }
211 265
212 - if (!empty($filters)) {
213 - $query .= ' WHERE ('.implode(') AND (', $filters).')';
214 - }
266 + $query .= ' WHERE ('.implode(') AND (', $filters).')';
215 267
216 - $queryCount = 'SELECT COUNT(DISTINCT mail.id) '.$query;
268 + $queryCount = 'SELECT COUNT(DISTINCT mail.id) AS total '.$query;
217 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';
218 270
219 271 acym_query('SET SQL_BIG_SELECTS=1;');
220 272 $results['elements'] = $mailClass->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['campaignsPerPage']));
221 - $results['total'] = acym_loadResult($queryCount);
273 + $results['total'] = acym_loadObject($queryCount);
222 274
223 275 foreach ($results['elements'] as $i => $oneMail) {
224 276 $results['elements'][$i]->sending_params = empty($oneMail->sending_params) ? [] : json_decode($oneMail->sending_params, true);
225 277 $mailId = empty($oneMail->parent_id) ? $oneMail->id : $oneMail->parent_id;
@@ -234,9 +286,12 @@
234 286
235 287 return $results;
236 288 }
237 289
238 - public function getMatchingResults($settings)
290 + /**
291 + * Get mails depending on filters (search, status, pagination)
292 + */
293 + public function getMatchingResults(array $settings): array
239 294 {
240 295 $query = 'FROM #__acym_queue AS queue
241 296 JOIN #__acym_mail AS mail ON mail.id = queue.mail_id
242 297 JOIN #__acym_user AS user ON queue.user_id = user.id ';
@@ -261,27 +316,29 @@
261 316 if (!empty($filters)) {
262 317 $query .= ' WHERE ('.implode(') AND (', $filters).')';
263 318 }
264 319
265 - if (!empty($settings['tag'])) {
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;
266 324 $query .= ' GROUP BY queue.mail_id, queue.user_id';
267 325 }
268 326
269 - $queryCount = 'SELECT COUNT(queue.mail_id) '.$query;
270 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';
271 328
272 329 $mailClass = new MailClass();
273 - $results['elements'] = $mailClass->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['elementsPerPage']));
274 - $results['total'] = acym_loadResult($queryCount);
275 330
276 - return $results;
331 + return [
332 + 'elements' => $mailClass->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['elementsPerPage'])),
333 + 'total' => acym_loadObject($queryCount),
334 + ];
277 335 }
278 336
279 - public function scheduleReady()
337 + public function scheduleReady(): ?int
280 338 {
281 339 $this->messages = [];
282 340
283 - $campaignClass = new CampaignClass();
284 341 $mailClass = new MailClass();
285 342
286 343 $multilingualQuery = acym_isMultilingual() ? ' OR mail.parent_id = campaign.mail_id ' : '';
287 344
@@ -290,9 +347,9 @@
290 347 'SELECT mail.id, campaign.sending_date, mail.name, campaign.mail_id AS parent_id, mail.language, campaign.sending_params
291 348 FROM #__acym_campaign AS campaign
292 349 JOIN #__acym_mail AS mail
293 350 ON campaign.mail_id = mail.id '.$multilingualQuery.'
294 - WHERE campaign.sending_type = '.acym_escapeDB($campaignClass->getConstScheduled()).'
351 + WHERE campaign.sending_type = '.acym_escapeDB(CampaignClass::SENDING_TYPE_SCHEDULED).'
295 352 AND campaign.draft = 0
296 353 AND campaign.sending_date <= '.acym_escapeDB(acym_date('now', 'Y-m-d H:i:s', false)).'
297 354 AND campaign.sent = 0',
298 355 'id'
@@ -299,16 +356,26 @@
299 356 )
300 357 );
301 358
302 359 if (empty($mailReady)) {
303 - return false;
360 + return null;
304 361 }
305 362
306 363 $nbQueue = [];
307 364
308 365 foreach ($mailReady as $mailId => $mail) {
309 - $nbQueue[$mailId] = $this->queue($mail);
310 - $this->messages[] = acym_translationSprintf('ACYM_ADDED_QUEUE_SCHEDULE', $nbQueue[$mailId], '<b>'.$mail->name.'</b>');
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 + }
311 378 }
312 379
313 380 $mailIds = array_keys($mailReady);
314 381 acym_arrayToInteger($mailIds);
@@ -315,14 +382,20 @@
315 382 $campaigns = acym_loadObjectList('SELECT id, mail_id FROM #__acym_campaign WHERE mail_id IN ('.implode(',', $mailIds).')');
316 383 $campaignClass = new CampaignClass();
317 384 foreach ($campaigns as $campaign) {
318 385 $result = $campaignClass->send($campaign->id, $nbQueue[$campaign->mail_id]);
319 - if (empty($result) && acym_isMultilingual()) {
320 - $translatedMails = acym_loadResultArray('SELECT id FROM #__acym_mail WHERE id != '.intval($campaign->mail_id).' AND parent_id = '.intval($campaign->mail_id));
321 - if (!empty($translatedMails)) {
322 - foreach ($translatedMails as $translatedMailId) {
323 - if (!empty($nbQueue[$translatedMailId])) $campaignClass->send($campaign->id, $nbQueue[$translatedMailId]);
324 - }
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]);
325 398 }
326 399 }
327 400 }
328 401
@@ -328,12 +401,11 @@
328 401
329 402 return count($mailReady);
330 403 }
331 404
332 - public function delete($elements)
405 + public function delete(array $elements): int
333 406 {
334 407 if (empty($elements)) return 0;
335 - if (!is_array($elements)) $elements = [$elements];
336 408 acym_arrayToInteger($elements);
337 409
338 410 $query = 'DELETE FROM #__acym_queue WHERE mail_id IN ('.implode(',', $elements).')';
339 411 $result = acym_query($query);
@@ -340,60 +412,48 @@
340 412
341 413 acym_query('UPDATE #__acym_campaign SET draft = 1, active = 1 WHERE mail_id IN ('.implode(',', $elements).')');
342 414
343 415 if (!$result) {
344 - return false;
416 + return 0;
345 417 }
346 418
347 419 return $result;
348 420 }
349 421
350 - public function deleteOne($elements, $mailId = null)
422 + public function deleteQueuedByUserIds(array $userIds, ?int $mailId = null): int
351 423 {
352 - if (!is_array($elements)) {
353 - $elements = [$elements];
424 + acym_arrayToInteger($userIds);
425 + if (empty($userIds)) {
426 + return 0;
354 427 }
355 428
356 - if (empty($elements)) {
357 - return 0;
429 + $query = 'DELETE FROM #__acym_queue WHERE user_id IN ('.implode(',', $userIds).')';
430 + if (!empty($mailId)) {
431 + $query .= ' AND mail_id = '.intval($mailId);
358 432 }
359 433
360 - $nbDeleted = 0;
361 - foreach ($elements as $one) {
362 - if (strpos($one, '_')) {
363 - [$mailId, $userId] = explode('_', $one);
364 - } else {
365 - $userId = $one;
434 + try {
435 + $nbDeleted = acym_query($query);
436 +
437 + if ($nbDeleted === false) {
438 + $this->errors[] = acym_getDBError();
439 +
440 + return 0;
366 441 }
367 442
368 - $query = 'DELETE FROM #__acym_queue WHERE user_id = '.intval($userId);
369 - if (!empty($mailId)) {
370 - $query .= ' AND mail_id = '.intval($mailId);
371 - }
443 + return (int)$nbDeleted;
444 + } catch (\Exception $e) {
445 + $this->errors[] = $e->getMessage();
372 446
373 - try {
374 - $res = acym_query($query);
375 - } catch (\Exception $e) {
376 - $res = false;
377 - }
378 - if ($res === false) {
379 - if (isset($e)) {
380 - $this->errors[] = $e->getMessage();
381 - unset($e);
382 - } else {
383 - $this->errors[] = acym_getDBError();
384 - }
385 - } else {
386 - $nbDeleted += $res;
387 - }
447 + return 0;
388 448 }
389 -
390 - return $res;
391 449 }
392 450
393 - public function getReady($limit, $mailId = 0): array
451 + public function getReady(int $startFrom, int $limit, int $mailId = 0): array
394 452 {
395 - if (empty($limit)) return [];
453 + if (empty($limit)) {
454 + return [];
455 + }
396 456
397 457 $query = 'SELECT queue.*, campaign.sending_params AS sending_params FROM #__acym_queue AS queue';
398 458 $query .= ' JOIN #__acym_user AS user ON queue.`user_id` = user.`id` ';
399 459 $query .= ' JOIN #__acym_mail AS mail ON queue.`mail_id` = mail.`id` ';
@@ -420,8 +480,9 @@
420 480 if (!empty($mailId)) {
421 481 $query .= ' AND queue.`mail_id` = '.intval($mailId);
422 482 }
423 483
484 + // We don't display this option in the configuration anymore but we use its value if it's set in the database
424 485 $sendOrder = $this->config->get('sendorder');
425 486 if (empty($sendOrder)) {
426 487 $order = 'queue.`user_id` ASC';
427 488 } elseif ($sendOrder === 'rand') {
@@ -428,14 +489,14 @@
428 489 $order = 'RAND()';
429 490 } else {
430 491 $sendOrder = str_replace('subid', 'user_id', $sendOrder);
431 492 $ordering = explode(',', $sendOrder);
432 - $order = 'queue.`'.acym_secureDBColumn(trim($ordering[0])).'` '.acym_secureDBColumn(trim($ordering[1]));
493 + $order = 'queue.`'.acym_secureDBColumn(trim($ordering[0])).'` '.acym_secureDBColumn(trim($ordering[1] ?? 'ASC'));
433 494 }
434 495
435 496 $query .= ' ORDER BY queue.`priority` ASC, queue.`sending_date` ASC, '.$order;
436 - $startqueue = acym_getVar('int', 'startqueue', 0);
437 - $query .= ' LIMIT '.intval($startqueue).','.intval($limit);
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);
438 499
439 500 try {
440 501 $results = acym_loadObjectList($query);
441 502 } catch (\Exception $e) {
@@ -442,8 +503,9 @@
442 503 $results = null;
443 504 }
444 505
445 506 if ($results === null) {
507 + // We got an issue here... maybe the table is crashed so we will repair it.
446 508 acym_query('REPAIR TABLE #__acym_queue, #__acym_user, #__acym_mail, #__acym_campaign');
447 509 }
448 510
449 511 if (empty($results)) {
@@ -449,8 +511,12 @@
449 511 if (empty($results)) {
450 512 return [];
451 513 }
452 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
453 519 $firstElementQueued = reset($results);
454 520 acym_query(
455 521 'UPDATE #__acym_queue
456 522 SET sending_date = DATE_ADD(sending_date, INTERVAL 1 SECOND)
@@ -460,16 +526,16 @@
460 526
461 527 return $results;
462 528 }
463 529
464 - public function delayFailed($mailId, $userIds)
530 + public function delayFailed(int $mailId, array $userIds): void
465 531 {
466 532 acym_arrayToInteger($userIds);
467 533 if (empty($mailId) || empty($userIds)) {
468 - return false;
534 + return;
469 535 }
470 536
471 - return acym_query(
537 + acym_query(
472 538 'UPDATE #__acym_queue
473 539 SET sending_date = DATE_ADD(sending_date, INTERVAL 1 HOUR), try = try +1
474 540 WHERE mail_id = '.intval($mailId).'
475 541 AND user_id IN ('.implode(',', $userIds).')'
@@ -475,15 +541,15 @@
475 541 AND user_id IN ('.implode(',', $userIds).')'
476 542 );
477 543 }
478 544
479 - public function delayAll(int $hours)
545 + public function delayAll(int $hours): void
480 546 {
481 547 if ($hours < 1) {
482 - return false;
548 + return;
483 549 }
484 550
485 - return acym_query(
551 + acym_query(
486 552 'UPDATE #__acym_queue
487 553 SET sending_date = DATE_ADD(sending_date, INTERVAL '.$hours.' HOUR)
488 554 WHERE sending_date < DATE_ADD(NOW(), INTERVAL '.intval($hours).' HOUR)'
489 555 );
@@ -488,9 +554,9 @@
488 554 WHERE sending_date < DATE_ADD(NOW(), INTERVAL '.intval($hours).' HOUR)'
489 555 );
490 556 }
491 557
492 - public function getMailReceivers($mail, $onlyNew = false)
558 + public function getMailReceivers(object $mail, bool $onlyNew = false): AutomationHelper
493 559 {
494 560 if (empty($mail->sending_params)) {
495 561 $sendingParams = [];
496 562 $mail->filters = [];
@@ -512,11 +578,13 @@
512 578 'userlist.status = 1',
513 579 'maillist.mail_id = '.intval(empty($mail->parent_id) ? $mail->id : $mail->parent_id),
514 580 ];
515 581
582 + // Send this version only to the users with the correct language
516 583 if (!$onlyNew && acym_isMultilingual()) {
517 584 $where = 'user.language = '.acym_escapeDB($mail->language);
518 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
519 587 $where .= ' OR user.language = "" OR user.language NOT IN (SELECT language FROM #__acym_mail WHERE parent_id = '.intval($mail->id).')';
520 588 }
521 589 $automationHelper->where[] = $where;
522 590 }
@@ -530,8 +598,9 @@
530 598 $mail->id
531 599 ).' OR id = '.intval($mail->id).')';
532 600 $automationHelper->where[] = '`us`.`user_id` IS NULL';
533 601
602 + // Do not count the disabled user for the resend counter on summary
534 603 $automationHelper->where[] = '`user`.`active` = 1';
535 604 }
536 605
537 606 $automationHelper->removeFlag(SegmentsController::FLAG_USERS);
@@ -536,12 +605,14 @@
536 605
537 606 $automationHelper->removeFlag(SegmentsController::FLAG_USERS);
538 607 $automationHelper->removeFlag(SegmentsController::FLAG_COUNT);
539 608
609 + // Handle potential segment
540 610 if (empty($mail->filters)) {
541 611 return $automationHelper;
542 612 }
543 613
614 + // Mark users matching the segment
544 615 foreach ($mail->filters as $orValues) {
545 616 if (empty($orValues)) continue;
546 617
547 618 $automationHelperSegment = new AutomationHelper();
@@ -562,11 +633,12 @@
562 633
563 634 return $automationHelper;
564 635 }
565 636
566 - public function queue($mail)
637 + public function queue(object $mail): int
567 638 {
568 639 $automationHelper = $this->getMailReceivers($mail);
640 + // Only queue enabled users
569 641 $automationHelper->where[] = '`user`.`active` = 1';
570 642
571 643 $priority = $this->config->get('priority_newsletter', 3);
572 644 $select = [intval($mail->id), 'userlist.user_id', acym_escapeDB($mail->sending_date), intval($priority), '0'];
@@ -573,19 +645,23 @@
573 645 $inserted = acym_query('INSERT IGNORE INTO #__acym_queue (`mail_id`, `user_id`, `sending_date`, `priority`, `try`) ('.$automationHelper->getQuery($select).')');
574 646
575 647 $automationHelper->removeFlag(SegmentsController::FLAG_COUNT);
576 648
577 - return $inserted;
649 + return (int)$inserted;
578 650 }
579 651
580 - public function addQueue($userId, $mailId, $sendingDate)
652 + public function addQueue(int $userId, int $mailId, string $sendingDate): int
581 653 {
582 654 $priority = $this->config->get('priority_newsletter', 3);
583 655
584 - return acym_query('INSERT IGNORE INTO #__acym_queue (`mail_id`, `user_id`, `sending_date`, `priority`, `try`) VALUES ('.intval($mailId).', '.intval($userId).', '.acym_escapeDB($sendingDate).', '.intval($priority).', 0)');
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 + );
585 661 }
586 662
587 - public function unpauseCampaign($campaignId, $active)
663 + public function unpauseCampaign(int $campaignId, int $active): void
588 664 {
589 665 if (acym_query('UPDATE #__acym_campaign SET active = '.intval($active).' WHERE id = '.intval($campaignId))) {
590 666 acym_enqueueMessage(acym_translation($active ? 'ACYM_UNPAUSE_CAMPAIGN_SUCCESSFUL' : 'ACYM_PAUSE_CAMPAIGN_SUCCESSFUL'), "success");
591 667 } else {
@@ -592,19 +668,21 @@
592 668 acym_enqueueMessage(acym_translation($active ? 'ACYM_UNPAUSE_CAMPAIGN_FAIL' : 'ACYM_PAUSE_CAMPAIGN_FAIL'), "error");
593 669 }
594 670 }
595 671
596 - public function emptyQueue()
672 + public function emptyQueue(): int
597 673 {
598 - return acym_query('DELETE FROM `#__acym_queue`');
674 + return (int)acym_query('DELETE FROM `#__acym_queue`');
599 675 }
600 676
601 - public function cleanQueue()
677 + public function cleanQueue(): int
602 678 {
603 679 $twoDaysEarlier = acym_date(time() - 172800, 'Y-m-d H:i:s', false);
604 680
605 681 $conditionUser = '`user`.`active` = 0';
606 - if ($this->config->get('require_confirmation', 1) == 1) $conditionUser .= ' OR `user`.`confirmed` = 0';
682 + if ($this->config->get('require_confirmation', 1) == 1) {
683 + $conditionUser .= ' OR `user`.`confirmed` = 0';
684 + }
607 685
608 686 $numberOfDaysToWait = $this->config->get('queue_delete_days', 0);
609 687 $conditionDateDelete = '';
610 688 if (!empty($numberOfDaysToWait)) {
@@ -611,9 +689,9 @@
611 689 $dateTimeConditionDelete = acym_date(time() - ($numberOfDaysToWait * 86400), 'Y-m-d H:i:s', false);
612 690 $conditionDateDelete = ' OR (`queue`.`sending_date` < '.acym_escapeDB($dateTimeConditionDelete).')';
613 691 }
614 692
615 - return acym_query(
693 + return (int)acym_query(
616 694 'DELETE `queue`.*
617 695 FROM `#__acym_queue` AS `queue`
618 696 JOIN `#__acym_user` AS `user` ON `queue`.`user_id` = `user`.`id`
619 697 WHERE (('.$conditionUser.') AND `queue`.`sending_date` < '.acym_escapeDB($twoDaysEarlier).') '.$conditionDateDelete
@@ -619,9 +697,9 @@
619 697 WHERE (('.$conditionUser.') AND `queue`.`sending_date` < '.acym_escapeDB($twoDaysEarlier).') '.$conditionDateDelete
620 698 );
621 699 }
622 700
623 - public function isSendingFinished($mailId): bool
701 + public function isSendingFinished(int $mailId): bool
624 702 {
625 703 $mailClass = new MailClass();
626 704 $mail = $mailClass->getOneById($mailId);
627 705