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/CampaignClass.php +297 -172 10.0.1 → 11.1.0 View file →
@@ -1,10 +1,12 @@
1 1 <?php
2 2
3 3 namespace AcyMailing\Classes;
4 4
5 +use AcyMailing\Controllers\CampaignsController;
5 6 use AcyMailing\Controllers\SegmentsController;
6 7 use AcyMailing\Helpers\AutomationHelper;
8 +use AcyMailing\Helpers\MailerHelper;
7 9 use AcyMailing\Helpers\PaginationHelper;
8 10 use AcyMailing\Core\AcymClass;
9 11
10 12 class CampaignClass extends AcymClass
@@ -18,10 +20,8 @@
18 20 self::SENDING_TYPE_AUTO,
19 21 ];
20 22 const AB_TEST_VERSIONS = ['B'];
21 23
22 - private array $jsonColumns = ['sending_params'];
23 -
24 24 public function __construct()
25 25 {
26 26 parent::__construct();
27 27
@@ -26,27 +26,26 @@
26 26 parent::__construct();
27 27
28 28 $this->table = 'campaign';
29 29 $this->pkey = 'id';
30 + $this->jsonColumns = ['sending_params'];
31 + $this->intColumns = [
32 + 'id',
33 + 'mail_id',
34 + 'parent_id',
35 + 'draft',
36 + 'active',
37 + 'sent',
38 + 'visible',
39 + 'subscribers',
40 + 'open_unique',
41 + 'tracking_sale',
42 + 'tracking',
43 + ];
30 44 }
31 45
32 - public function getConstNow()
46 + public function decode($campaign, bool $decodeMail = true)
33 47 {
34 - return self::SENDING_TYPE_NOW;
35 - }
36 -
37 - public function getConstScheduled()
38 - {
39 - return self::SENDING_TYPE_SCHEDULED;
40 - }
41 -
42 - public function getConstAuto()
43 - {
44 - return self::SENDING_TYPE_AUTO;
45 - }
46 -
47 - public function decode($campaign, $decodeMail = true)
48 - {
49 48 if (empty($campaign)) return $campaign;
50 49
51 50 if (is_array($campaign)) {
52 51 foreach ($campaign as $i => $oneCampaign) {
@@ -51,16 +50,12 @@
51 50 if (is_array($campaign)) {
52 51 foreach ($campaign as $i => $oneCampaign) {
53 52 $campaign[$i] = $this->decode($oneCampaign, false);
54 53 }
54 + } else {
55 + $this->fixTypes($campaign);
55 56 }
56 57
57 - foreach ($this->jsonColumns as $oneColumn) {
58 - if (!isset($campaign->$oneColumn)) continue;
59 -
60 - $campaign->$oneColumn = empty($campaign->$oneColumn) ? [] : json_decode($campaign->$oneColumn, true);
61 - }
62 -
63 58 if ($decodeMail) {
64 59 $mailClass = new MailClass();
65 60 $campaign = $mailClass->decode($campaign);
66 61 }
@@ -67,9 +62,9 @@
67 62
68 63 return $campaign;
69 64 }
70 65
71 - public function getAll($key = null)
66 + public function getAll(?string $key = null): array
72 67 {
73 68 $allCampaigns = parent::getAll($key);
74 69
75 70 return $this->decode($allCampaigns);
@@ -80,17 +75,16 @@
80 75 $tagClass = new TagClass();
81 76 $mailClass = new MailClass();
82 77
83 78 $query = 'SELECT campaign.*, mail.name, SUM(mail_stat.sent) AS subscribers, mail_stat.open_unique, mail_stat.tracking_sale, mail_stat.currency FROM #__acym_campaign AS campaign';
84 - $queryCount = 'SELECT campaign.* FROM #__acym_campaign AS campaign';
79 + $queryCount = 'FROM #__acym_campaign AS campaign';
85 80
86 -
87 81 $filters = [];
88 82 $task = acym_getVar('string', 'task');
89 83 if ($task === 'campaigns') {
90 - $filters[] = 'mail.type = \'standard\'';
84 + $filters[] = 'mail.type = '.acym_escapeDB(MailClass::TYPE_STANDARD);
91 85 } elseif ($task === 'mailbox_action') {
92 - $filters[] = 'mail.type = \'mailbox_action\'';
86 + $filters[] = 'mail.type = '.acym_escapeDB(MailClass::TYPE_MAILBOX_ACTION);
93 87 }
94 88 $mailIds = [];
95 89
96 90 $query .= ' JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id';
@@ -102,8 +96,9 @@
102 96 if ($this->config->get('front_campaigns_filter', 'own') === 'allowed') {
103 97 $listClass = new ListClass();
104 98 $allowedLists = $listClass->getManageableLists();
105 99 if (!empty($allowedLists)) {
100 + acym_arrayToInteger($allowedLists);
106 101 $query .= ' LEFT JOIN #__acym_mail_has_list AS mailList ON campaign.mail_id = mailList.mail_id AND mailList.list_id IN ('.implode(',', $allowedLists).')';
107 102 $queryCount .= ' LEFT JOIN #__acym_mail_has_list AS mailList ON campaign.mail_id = mailList.mail_id AND mailList.list_id IN ('.implode(',', $allowedLists).')';
108 103 $condition .= ' OR mailList.list_id IS NOT NULL';
109 104 }
@@ -116,9 +111,9 @@
116 111 $tagJoin = ' JOIN #__acym_tag AS tag ON campaign.mail_id = tag.id_element';
117 112 $query .= $tagJoin;
118 113 $queryCount .= $tagJoin;
119 114 $filters[] = 'tag.name = '.acym_escapeDB($settings['tag']);
120 - $filters[] = 'tag.type = "mail"';
115 + $filters[] = 'tag.type = '.acym_escapeDB(TagClass::TYPE_MAIL);
121 116 }
122 117
123 118 if (!empty($settings['search'])) {
124 119 $filters[] = 'mail.name LIKE '.acym_escapeDB('%'.acym_utf8Encode($settings['search']).'%');
@@ -158,11 +153,12 @@
158 153 }
159 154
160 155 $query .= ' GROUP BY campaign.id';
161 156
162 - if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) {
157 + if (!empty($settings['ordering'])) {
163 158 $table = in_array($settings['ordering'], ['name', 'creation_date']) ? 'mail' : 'campaign';
164 - $query .= ' ORDER BY '.$table.'.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn(strtoupper($settings['ordering_sort_order']));
159 + $order = isset($settings['ordering_sort_order']) && strtolower($settings['ordering_sort_order']) === 'asc' ? 'ASC' : 'DESC';
160 + $query .= ' ORDER BY '.$table.'.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn($order);
165 161 }
166 162
167 163 if (empty($settings['offset']) || $settings['offset'] < 0) {
168 164 $settings['offset'] = 0;
@@ -213,14 +209,38 @@
213 209 $this->getStatsCampaign($results['elements'][$i], $urlClickClass, $isAbTest);
214 210 }
215 211 }
216 212
217 - $results['total'] = acym_loadObjectList($queryCount);
213 + if (!empty($settings['advanced_total'])) {
214 + if ($settings['campaign_type'] === 'campaigns') {
215 + $queryCount .= (empty($filters) ? ' WHERE ' : ' AND ').'campaign.parent_id IS NULL';
218 216
217 + $results['total'] = acym_loadObject('SELECT COUNT(campaign.id) AS total, SUM(campaign.sent) AS sent, SUM(campaign.draft) AS draft '.$queryCount);
218 + $results['total']->all = $results['total']->total;
219 + $results['total']->scheduled = acym_loadResult(
220 + 'SELECT COUNT(campaign.id) '.$queryCount.' AND campaign.`sending_type` = '.acym_escapeDB(self::SENDING_TYPE_SCHEDULED)
221 + );
222 + } else {
223 + $results['total'] = acym_loadObject('SELECT COUNT(campaign.id) AS total '.$queryCount);
224 + $results['total']->all = 0;
225 + if (!empty($results['total']->total)) {
226 + $results['total']->all = $results['total']->total;
227 + }
228 +
229 + $results['total']->generated = $this->getNbGeneratedCampaigns();
230 + }
231 +
232 + if (CampaignsController::TASK_TYPE_CAMPAIGN_AUTO === $settings['campaign_type'] && 'generated' === $settings['status']) {
233 + $results['total']->all = $this->getCountCampaignType(self::SENDING_TYPE_AUTO);
234 + }
235 + } else {
236 + $results['total'] = acym_loadObject('SELECT COUNT(campaign.id) AS total '.$queryCount);
237 + }
238 +
219 239 return $results;
220 240 }
221 241
222 - private function prepareStatsCampaign(&$element)
242 + private function prepareStatsCampaign(object $element): void
223 243 {
224 244 $query = 'SELECT SUM(mailstat.sent) AS subscribers, SUM(mailstat.open_unique) AS open_unique, SUM(mailstat.tracking_sale) AS tracking_sale
225 245 FROM #__acym_mail_stat AS mailstat
226 246 LEFT JOIN #__acym_mail AS mail ON mail.id = mailstat.mail_id WHERE mail.parent_id = '.intval($element->mail_id);
@@ -229,20 +249,29 @@
229 249 $element->open_unique += $stats->open_unique;
230 250 $element->tracking_sale += $stats->tracking_sale;
231 251 }
232 252
233 - public function getStatsCampaign(&$element, $urlClickClass, $isAbTest = false)
253 + public function getStatsCampaign(object $element, UrlClickClass $urlClickClass, bool $isAbTest = false): void
234 254 {
235 255 $element->open = 0;
256 + $element->click = 0;
257 +
236 258 if (!empty($element->subscribers)) {
237 - $element->open = number_format($element->open_unique / $element->subscribers * 100, 2);
259 + // In anonymous mode opens/clicks are counted globally (totals, not unique subscribers), so a percentage of recipients is meaningless: expose the average number of opens/clicks per email sent instead (e.g. 3.25), rendered as "3.25×" in the view
260 + $anonymousStats = !empty($this->config->get('anonymous_stats', 0));
261 + $clicksNb = $urlClickClass->getNumberUsersClicked([$element->mail_id], $isAbTest);
238 262
239 - $clicksNb = $urlClickClass->getNumberUsersClicked($element->mail_id, $isAbTest);
240 - $element->click = number_format($clicksNb / $element->subscribers * 100, 2);
263 + if ($anonymousStats) {
264 + $element->open = number_format($element->open_unique / $element->subscribers, 2);
265 + $element->click = number_format($clicksNb / $element->subscribers, 2);
266 + } else {
267 + $element->open = number_format($element->open_unique / $element->subscribers * 100, 2);
268 + $element->click = number_format($clicksNb / $element->subscribers * 100, 2);
269 + }
241 270 }
242 271 }
243 272
244 - public function getTrackingSales(&$element)
273 + public function getTrackingSales(object $element): void
245 274 {
246 275 $element->sale = 0;
247 276 $element->currency = '';
248 277
@@ -259,32 +288,48 @@
259 288 }
260 289 $this->formatSaleTracking($element, $trackingSales);
261 290 }
262 291
263 - private function getStatsCampaignAuto(&$element, $urlClickClass)
292 + private function getStatsCampaignAuto(object $element, UrlClickClass $urlClickClass): void
264 293 {
265 294 $generatedMailsStats = acym_loadObjectList(
266 - 'SELECT mail_stat.* FROM #__acym_mail AS mail JOIN #__acym_mail_stat AS mail_stat ON mail.id = mail_stat.mail_id WHERE mail.id IN (SELECT mail_id FROM #__acym_campaign WHERE parent_id = '.intval(
267 - $element->id
268 - ).')'
295 + 'SELECT mail_stat.*
296 + FROM #__acym_mail AS mail
297 + JOIN #__acym_mail_stat AS mail_stat
298 + ON mail.id = mail_stat.mail_id
299 + WHERE mail.id IN (SELECT mail_id FROM #__acym_campaign WHERE parent_id = '.intval($element->id).')'
269 300 );
301 +
270 302 $element->open = 0;
271 303 $element->click = 0;
272 304 $element->subscribers = 0;
273 - if (empty($generatedMailsStats)) return;
305 + if (empty($generatedMailsStats)) {
306 + return;
307 + }
274 308
275 309 foreach ($generatedMailsStats as $key => $mailsStat) {
276 310 $element->open += $mailsStat->open_unique;
277 - $element->click += $urlClickClass->getNumberUsersClicked($element->id);
311 + $element->click += $urlClickClass->getNumberUsersClicked([$element->id]);
278 312 $element->subscribers += $mailsStat->sent;
279 313 }
280 314
281 315 if (!empty($element->subscribers)) {
282 - $element->open = number_format($element->open / $element->subscribers * 100, 2);
283 - $element->click = number_format($element->click / $element->subscribers * 100, 2);
316 + // In anonymous mode opens/clicks are counted globally (totals, not unique subscribers), so expose the average number of opens/clicks per email sent (e.g. 3.25) instead of a percentage, rendered as "3.25×" in the view
317 + $anonymousStats = !empty($this->config->get('anonymous_stats', 0));
318 +
319 + if ($anonymousStats) {
320 + $element->open = number_format($element->open / $element->subscribers, 2);
321 + $element->click = number_format($element->click / $element->subscribers, 2);
322 + } else {
323 + $element->open = number_format($element->open / $element->subscribers * 100, 2);
324 + $element->click = number_format($element->click / $element->subscribers * 100, 2);
325 + }
284 326 }
285 327
286 - if (!acym_isTrackingSalesActive()) return;
328 + //Tracking sales
329 + if (!acym_isTrackingSalesActive()) {
330 + return;
331 + }
287 332
288 333 $trackingSales = acym_loadObject(
289 334 'SELECT SUM(mail_stat.tracking_sale) AS sale, mail_stat.currency
290 335 FROM #__acym_mail_stat AS mail_stat
@@ -292,9 +337,9 @@
292 337 );
293 338 $this->formatSaleTracking($element, $trackingSales);
294 339 }
295 340
296 - private function formatSaleTracking(&$element, $trackingSales)
341 + private function formatSaleTracking(object $element, object $trackingSales): void
297 342 {
298 343 $element->sale = $trackingSales->sale;
299 344 if (empty($element->currency)) $element->currency = '';
300 345 acym_trigger('getCurrency', [&$element->currency]);
@@ -299,43 +344,44 @@
299 344 if (empty($element->currency)) $element->currency = '';
300 345 acym_trigger('getCurrency', [&$element->currency]);
301 346 }
302 347
303 - public function getOneById($id)
348 + public function getOneById(int $id): ?object
304 349 {
305 - return $this->decode(acym_loadObject('SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.id = '.intval($id)));
350 + $campaign = parent::getOneById($id);
351 +
352 + return empty($campaign) ? null : $this->decode($campaign);
306 353 }
307 354
308 - public function getOneByIdWithMail($id)
355 + public function getOneByMailId(int $mailId): ?object
309 356 {
310 - $query = 'SELECT campaign.*, mail.name, mail.subject, mail.body, mail.from_name, mail.from_email, mail.reply_to_name, mail.reply_to_email, mail.bcc, mail.links_language, mail.tracking, mail.translation, mail.bounce_email
311 - FROM #__acym_campaign AS campaign
312 - JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id
313 - WHERE campaign.id = '.intval($id);
357 + $campaign = acym_loadObject(
358 + 'SELECT *
359 + FROM #__acym_campaign
360 + WHERE `mail_id` = '.intval($mailId)
361 + );
314 362
315 - return $this->decode(acym_loadObject($query));
363 + return empty($campaign) ? null : $campaign;
316 364 }
317 365
318 - public function get($identifier, $column = 'id')
366 + public function getOneByIdWithMail(int $id): ?object
319 367 {
320 - return $this->decode(acym_loadObject('SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.'.acym_secureDBColumn($column).' = '.acym_escapeDB($identifier)));
321 - }
368 + $campaign = acym_loadObject(
369 + 'SELECT campaign.*, mail.name, mail.subject, mail.body, mail.from_name, mail.from_email, mail.reply_to_name, mail.reply_to_email, mail.bcc, mail.links_language, mail.tracking, mail.translation, mail.bounce_email
370 + FROM #__acym_campaign AS campaign
371 + JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id
372 + WHERE campaign.id = '.intval($id)
373 + );
322 374
323 - public function getAllCampaignsNameMailId()
324 - {
325 - $query = 'SELECT m.id, m.name
326 - FROM #__acym_campaign AS c
327 - LEFT JOIN #__acym_mail AS m ON c.mail_id = m.id';
328 -
329 - return $this->decode(acym_loadObjectList($query));
375 + return empty($campaign) ? null : $this->decode($campaign);
330 376 }
331 377
332 - public function getOneCampaignByMailId($mailId)
378 + public function getOneCampaignByMailId(int $mailId)
333 379 {
334 380 return $this->decode(acym_loadObject('SELECT * FROM #__acym_campaign WHERE mail_id = '.intval($mailId)));
335 381 }
336 382
337 - public function getAutoCampaignFromGeneratedMailId($mailId)
383 + public function getAutoCampaignFromGeneratedMailId(int $mailId)
338 384 {
339 385 $queryCampaign = 'SELECT * FROM #__acym_campaign WHERE id = (SELECT parent_id FROM #__acym_campaign WHERE mail_id = '.intval($mailId).')';
340 386
341 387 return $this->decode(acym_loadObject($queryCampaign));
@@ -340,9 +386,9 @@
340 386
341 387 return $this->decode(acym_loadObject($queryCampaign));
342 388 }
343 389
344 - public function manageListsToCampaign($listsIds, $mailId, $unselectedListIds = [])
390 + public function manageListsToCampaign($listsIds, int $mailId, array $unselectedListIds = []): bool
345 391 {
346 392 if (!empty($unselectedListIds)) {
347 393 acym_arrayToInteger($unselectedListIds);
348 394 acym_query('DELETE FROM #__acym_mail_has_list WHERE mail_id = '.intval($mailId).' AND list_id IN ('.implode(', ', $unselectedListIds).')');
@@ -350,11 +396,22 @@
350 396
351 397 acym_arrayToInteger($listsIds);
352 398 if (empty($listsIds)) return false;
353 399
400 + $listsIds = array_unique($listsIds);
401 +
402 + $existingListsIds = acym_loadResultArray('SELECT `id` FROM #__acym_list WHERE `id` IN ('.implode(',', $listsIds).')');
403 + acym_arrayToInteger($existingListsIds);
404 +
405 + $unknownListsIds = array_diff($listsIds, $existingListsIds);
406 + if (!empty($unknownListsIds)) {
407 + $this->errors[] = acym_translationSprintf('ACYM_LIST_NOT_FOUND', implode(', ', $unknownListsIds));
408 + }
409 +
410 + if (empty($existingListsIds)) return false;
411 +
354 412 $values = [];
355 - $listsIds = array_unique($listsIds);
356 - foreach ($listsIds as $listId) {
413 + foreach ($existingListsIds as $listId) {
357 414 $values[] = '('.intval($mailId).', '.intval($listId).')';
358 415 }
359 416
360 417 if (!empty($values)) {
@@ -363,11 +420,11 @@
363 420
364 421 return true;
365 422 }
366 423
367 - public function save($campaignToSave)
424 + public function save(object $element): ?int
368 425 {
369 - $campaign = clone $campaignToSave;
426 + $campaign = clone $element;
370 427 if (isset($campaign->tags)) {
371 428 $tags = $campaign->tags;
372 429 unset($campaign->tags);
373 430 }
@@ -376,9 +433,9 @@
376 433 if (in_array($oneAttribute, $this->jsonColumns)) {
377 434 $campaign->$oneAttribute = json_encode(empty($value) ? [] : $value);
378 435 } else {
379 436 if (empty($value)) continue;
380 - $campaign->$oneAttribute = strip_tags($value);
437 + $campaign->$oneAttribute = acym_stripTags($value);
381 438 }
382 439 }
383 440
384 441 $campaignID = parent::save($campaign);
@@ -390,9 +447,9 @@
390 447
391 448 return $campaignID;
392 449 }
393 450
394 - public function onlyManageableCampaigns(&$elements)
451 + public function onlyManageableCampaigns(array &$elements): void
395 452 {
396 453 if (acym_isAdmin()) return;
397 454
398 455 $idCurrentUser = acym_currentUserId();
@@ -413,13 +470,13 @@
413 470 if (empty($userId)) {
414 471 return false;
415 472 }
416 473
417 - if (acym_isAdmin()) {
474 + if (acym_isAdmin() && acym_isAllowed('campaigns')) {
418 475 return true;
419 476 }
420 477
421 - $query = 'SELECT COUNT(*) FROM #__acym_campaign AS campaign
478 + $query = 'SELECT COUNT(*) FROM #__acym_campaign AS campaign
422 479 JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id ';
423 480
424 481 $condition = 'mail.creator_id = '.intval($userId);
425 482 if ($this->config->get('front_campaigns_filter', 'own') === 'allowed') {
@@ -435,11 +492,14 @@
435 492
436 493 return acym_loadResult($query) > 0;
437 494 }
438 495
439 - public function delete($elements)
496 + /**
497 + * Delete a campaign. Needs to delete the tag associated with the campaign and the mail attached to the campaign.
498 + * Deleting a mail of a campaign needs to clean the association table mail_has_list and its tags
499 + */
500 + public function delete(array $elements): int
440 501 {
441 - if (!is_array($elements)) $elements = [$elements];
442 502 acym_arrayToInteger($elements);
443 503 $this->onlyManageableCampaigns($elements);
444 504
445 505 if (empty($elements)) return 0;
@@ -455,9 +515,9 @@
455 515
456 516 return parent::delete($elements);
457 517 }
458 518
459 - public function countUsersCampaign($campaignID, $onlyActive = false): int
519 + public function countUsersCampaign(int $campaignID, bool $onlyActive = false): int
460 520 {
461 521 $campaign = $this->getOneById($campaignID);
462 522 if (empty($campaign)) {
463 523 return 0;
@@ -516,29 +576,32 @@
516 576 return $numberOfRecipients;
517 577 }
518 578 }
519 579
520 - public function getFilterCampaign($sendingParams)
580 + public function getFilterCampaign($sendingParams): array
521 581 {
522 - $filters = [];
582 + if (empty($sendingParams['segment'])) {
583 + return [];
584 + }
523 585
524 - if (!empty($sendingParams['segment'])) {
525 - if (!empty($sendingParams['segment']['filters'])) {
526 - $filters = $sendingParams['segment']['filters'];
527 - } elseif (!empty($sendingParams['segment']['segment_id'])) {
528 - $segmentClass = new SegmentClass();
529 - $segment = $segmentClass->getOneById($sendingParams['segment']['segment_id']);
530 - if (!empty($segment)) {
531 - $filters = $segment->filters;
532 - }
586 + if (!empty($sendingParams['segment']['filters'])) {
587 + return $sendingParams['segment']['filters'];
588 + }
589 +
590 + if (!empty($sendingParams['segment']['segment_id'])) {
591 + $segmentClass = new SegmentClass();
592 + $segment = $segmentClass->getOneById($sendingParams['segment']['segment_id']);
593 + if (!empty($segment)) {
594 + return $segment->filters;
533 595 }
534 596 }
535 597
536 - return $filters;
598 + return [];
537 599 }
538 600
539 - public function send($campaignID, $result = 0, $abTestFinal = false)
601 + public function send(int $campaignID, int $result = 0, bool $abTestFinal = false)
540 602 {
603 + // Make sure the email we're trying to send exists
541 604 $campaign = $this->getOneById($campaignID);
542 605
543 606 if (empty($campaign->mail_id)) {
544 607 $this->errors[] = acym_translation('ACYM_EMAIL_NOT_FOUND');
@@ -552,17 +615,20 @@
552 615 if (empty($filters)) {
553 616 $filters = [0 => []];
554 617 acym_trigger('onAcymSendCampaignSpecial', [$campaign, &$filters[0], &$pluginIsExisting]);
555 618 } else {
619 + // Adds the special campaigns conditions to the "OR" blocs of the segment
556 620 foreach ($filters as $key => $filter) {
557 621 acym_trigger('onAcymSendCampaignSpecial', [$campaign, &$filters[$key], &$pluginIsExisting]);
558 622 }
559 623 }
560 624
625 + // This is a special campaign type, but the required plugin is not installed
561 626 if (!$pluginIsExisting) {
562 627 return false;
563 628 }
564 629
630 + // Make sure some receivers have been selected
565 631 $lists = acym_loadResultArray('SELECT list_id FROM #__acym_mail_has_list WHERE mail_id = '.intval($campaign->mail_id));
566 632 if (empty($lists)) {
567 633 $this->errors[] = acym_translation('ACYM_NO_LIST_SELECTED');
568 634
@@ -619,8 +685,9 @@
619 685 } else {
620 686 $select = [intval($campaign->mail_id), 'ul.`user_id`', acym_escapeDB($date)];
621 687 }
622 688
689 + // Resending a campaign only to users who didn't receive it
623 690 if (!empty($campaign->sending_params['resendTarget']) && 'new' === $campaign->sending_params['resendTarget']) {
624 691 if (acym_isMultilingual()) {
625 692 $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(
626 693 $campaign->mail_id
@@ -642,10 +709,11 @@
642 709 $numberUsersInsertedByMailId[intval($campaign->mail_id)] = acym_query(
643 710 'INSERT IGNORE INTO `#__acym_queue` (`mail_id`, `user_id`, `sending_date`) '.$automationHelper->getQuery($select1)
644 711 );
645 712
713 + // If we have an odd number of users to send, we send one more to the first mail
646 714 $numberOfUsersToSend2 = $numberOfUsersToSend1 * 2 > $numberOfUsersToSend ? $numberOfUsersToSend1 - 1 : $numberOfUsersToSend1;
647 - $automationHelper->limit = $numberOfUsersToSend.', '.$numberOfUsersToSend2;
715 + $automationHelper->limit = $numberOfUsersToSend1.', '.$numberOfUsersToSend2;
648 716 $select2 = [intval($campaign->sending_params['abtest']['B']), 'ul.`user_id`', acym_escapeDB($date)];
649 717 $numberUsersInsertedByMailId[intval($campaign->sending_params['abtest']['B'])] = acym_query(
650 718 'INSERT IGNORE INTO `#__acym_queue` (`mail_id`, `user_id`, `sending_date`) '.$automationHelper->getQuery($select2)
651 719 );
@@ -678,13 +746,12 @@
678 746 }
679 747
680 748 $mailStatClass = new MailStatClass();
681 749 foreach ($numberUsersInsertedByMailId as $mailId => $numberOfUsersInserted) {
682 - $newMailStat = [
683 - 'mail_id' => intval($mailId),
684 - 'total_subscribers' => intval($numberOfUsersInserted),
685 - 'send_date' => $date,
686 - ];
750 + $newMailStat = new \stdClass();
751 + $newMailStat->mail_id = intval($mailId);
752 + $newMailStat->total_subscribers = intval($numberOfUsersInserted);
753 + $newMailStat->send_date = $date;
687 754
688 755 $mailStatClass->save($newMailStat);
689 756 }
690 757
@@ -698,22 +765,29 @@
698 765
699 766 return $result;
700 767 }
701 768
702 - public function getCampaignForDashboard()
769 + public function getCampaignForDashboard(): array
703 770 {
704 - $query = 'SELECT campaign.*, mail.name as name FROM #__acym_campaign as campaign LEFT JOIN #__acym_mail as mail ON campaign.mail_id = mail.id WHERE `active` = 1 AND `sending_type` = '.acym_escapeDB(
705 - self::SENDING_TYPE_SCHEDULED
706 - ).' AND `sent` = 0 LIMIT 3';
771 + $campaigns = acym_loadObjectList(
772 + 'SELECT campaign.*, mail.name AS name
773 + FROM #__acym_campaign AS campaign
774 + LEFT JOIN #__acym_mail AS mail
775 + ON campaign.mail_id = mail.id
776 + WHERE `active` = 1
777 + AND `sent` = 0
778 + AND `sending_type` = '.acym_escapeDB(self::SENDING_TYPE_SCHEDULED).'
779 + LIMIT 3'
780 + );
707 781
708 - return $this->decode(acym_loadObjectList($query));
782 + return $this->decode($campaigns);
709 783 }
710 784
711 - public function getOpenRateCampaigns($mailIds)
785 + public function getOpenRateCampaigns(array $mailIds)
712 786 {
713 - if (!is_array($mailIds)) $mailIds = [$mailIds];
714 787 acym_arrayToInteger($mailIds);
715 788
789 + //TODO move these methods in mail stat class
716 790 $query = 'SELECT SUM(sent) AS sent, SUM(open_unique) AS open_unique FROM #__acym_mail_stat
717 791 WHERE mail_id IN ('.implode(',', $mailIds).')';
718 792
719 793 return acym_loadObject($query);
@@ -732,13 +806,10 @@
732 806
733 807 return acym_loadObject($query);
734 808 }
735 809
736 -
737 - public function getBounceRateCampaigns($mailIds)
810 + public function getBounceRateCampaigns(array $mailIds)
738 811 {
739 - if (!is_array($mailIds)) $mailIds = [$mailIds];
740 -
741 812 acym_arrayToInteger($mailIds);
742 813
743 814 $query = 'SELECT SUM(sent) AS sent, SUM(bounce_unique) AS bounce_unique FROM #__acym_mail_stat
744 815 WHERE mail_id IN ('.implode(',', $mailIds).')';
@@ -745,9 +816,9 @@
745 816
746 817 return acym_loadObject($query);
747 818 }
748 819
749 - public function getOpenByMonth($mailIds = [], $start = '', $end = '')
820 + public function getOpenByMonth(array $mailIds = [], string $start = '', string $end = ''): array
750 821 {
751 822 if (!is_array($mailIds)) $mailIds = [$mailIds];
752 823 acym_arrayToInteger($mailIds);
753 824
@@ -760,22 +831,10 @@
760 831
761 832 return acym_loadObjectList($query);
762 833 }
763 834
764 - public function getOpenByWeek($mail_id = '', $start = '', $end = '')
835 + public function getOpenByDay(array $mailIds = [], string $start = '', string $end = ''): array
765 836 {
766 - $query = 'SELECT COUNT(user_id) as open, DATE_FORMAT(open_date, \'%Y-%m-%d\') as open_date FROM #__acym_user_stat WHERE open > 0';
767 - $query .= empty($mail_id) ? '' : ' AND `mail_id`='.intval($mail_id);
768 - $query .= ' AND `open_date` > "0000-00-00"';
769 - $query .= empty($start) ? '' : ' AND `open_date` >= '.acym_escapeDB($start);
770 - $query .= empty($end) ? '' : ' AND `open_date` <= '.acym_escapeDB($end);
771 - $query .= ' GROUP BY WEEK(open_date), YEAR(open_date) ORDER BY open_date';
772 -
773 - return acym_loadObjectList($query);
774 - }
775 -
776 - public function getOpenByDay($mailIds = [], $start = '', $end = '')
777 - {
778 837 if (!is_array($mailIds)) $mailIds = [$mailIds];
779 838 acym_arrayToInteger($mailIds);
780 839
781 840 $query = 'SELECT COUNT(user_id) as open, DATE_FORMAT(open_date, \'%Y-%m-%d\') as open_date FROM #__acym_user_stat WHERE open > 0';
@@ -787,9 +846,9 @@
787 846
788 847 return acym_loadObjectList($query);
789 848 }
790 849
791 - public function getOpenByHour($mailIds = [], $start = '', $end = '')
850 + public function getOpenByHour(array $mailIds = [], string $start = '', string $end = ''): array
792 851 {
793 852 if (!is_array($mailIds)) $mailIds = [$mailIds];
794 853 acym_arrayToInteger($mailIds);
795 854
@@ -802,11 +861,10 @@
802 861
803 862 return acym_loadObjectList($query);
804 863 }
805 864
806 - public function getDevicesWithCountByMailId($mailIds = [])
865 + public function getDevicesWithCountByMailId(array $mailIds = []): array
807 866 {
808 - if (!is_array($mailIds)) $mailIds = [$mailIds];
809 867 acym_arrayToInteger($mailIds);
810 868
811 869 $query = 'SELECT device, COUNT(*) as number FROM #__acym_user_stat WHERE `open` > 0';
812 870 if (!empty($mailIds)) $query .= ' AND mail_id IN ('.implode(',', $mailIds).')';
@@ -814,32 +872,39 @@
814 872
815 873 return acym_loadObjectList($query);
816 874 }
817 875
818 - public function getLastNewsletters(&$params): array
876 + public function getLastNewsletters(array &$params): array
819 877 {
878 + // Init select elements
820 879 $querySelect = 'SELECT mail.*, campaign.sending_date ';
821 880 $queryCountSelect = 'SELECT COUNT(*) FROM (SELECT DISTINCT mail.id ';
822 881
882 + // Form the query
823 883 $query = 'FROM #__acym_campaign AS campaign
824 884 JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id ';
825 885
886 + // We may need some joins depending on the selected options
826 887 if (isset($params['userId']) || isset($params['lists'])) {
827 888 $query .= 'JOIN #__acym_mail_has_list AS maillist ON mail.id = maillist.mail_id ';
828 889 if (isset($params['userId'])) $query .= 'JOIN #__acym_user_has_list AS userlist ON maillist.list_id = userlist.list_id ';
829 890 }
830 891
892 + // Make sure we display only active campaigns
831 893 $where = 'WHERE campaign.active = 1 AND campaign.sent = 1 AND mail.type = '.acym_escapeDB(MailClass::TYPE_STANDARD).' AND campaign.visible = 1 ';
832 894
895 + // If we want an archive of some specific lists
833 896 if (isset($params['lists'])) {
834 897 acym_arrayToInteger($params['lists']);
835 898 $where .= 'AND maillist.list_id IN ('.implode(', ', $params['lists']).') ';
836 899 }
837 900
901 + // If we want an archive for a specific user
838 902 if (isset($params['userId']) && !empty($params['displayUserListOnly'])) {
839 903 $where .= 'AND userlist.user_id = '.intval($params['userId']).' ';
840 904 }
841 905
906 + // If the user search for a newsletter
842 907 if (isset($params['search'])) {
843 908 $search = acym_escapeDB('%'.acym_utf8Encode($params['search']).'%');
844 909 $where .= 'AND (mail.subject LIKE '.$search.' OR mail.body LIKE '.$search.')';
845 910 }
@@ -845,13 +910,15 @@
845 910 }
846 911
847 912 $query .= $where;
848 913 $return = [];
849 - $return['count'] = acym_loadResult($queryCountSelect.$query.') AS r ');
914 + $return['count'] = (int)acym_loadResult($queryCountSelect.$query.') AS r ');
850 915
916 + // Make sure we display campaigns only once
851 917 $endQuerySelect = 'GROUP BY mail.id ';
852 918 $endQuerySelect .= 'ORDER BY campaign.sending_date DESC';
853 919
920 + // Init the pagination
854 921 $page = $params['page'] ?? 0;
855 922 $numberPerPage = $params['numberPerPage'] ?? 0;
856 923 $lastNewsletters = $params['limit'] ?? 0;
857 924
@@ -907,16 +974,17 @@
907 974
908 975 return $return;
909 976 }
910 977
911 - public function getListsByMailId($mailId)
978 + public function getListsByMailId(int $mailId): array
912 979 {
913 - $query = 'SELECT list_id FROM #__acym_mail_has_list WHERE mail_id = '.intval($mailId);
980 + $listIds = acym_loadResultArray('SELECT list_id FROM #__acym_mail_has_list WHERE mail_id = '.intval($mailId));
981 + acym_arrayToInteger($listIds);
914 982
915 - return acym_loadResultArray($query);
983 + return $listIds;
916 984 }
917 985
918 - public function triggerAutoCampaign()
986 + public function triggerAutoCampaign(): void
919 987 {
920 988 $activeAutoCampaigns = acym_loadObjectList(
921 989 'SELECT campaign.*, mail.name
922 990 FROM #__acym_campaign AS campaign
@@ -924,16 +992,30 @@
924 992 WHERE `active` = 1 AND `sending_type` = '.acym_escapeDB(self::SENDING_TYPE_AUTO)
925 993 );
926 994 $activeAutoCampaigns = $this->decode($activeAutoCampaigns);
927 995
928 - if (empty($activeAutoCampaigns)) return;
996 + if (empty($activeAutoCampaigns)) {
997 + return;
998 + }
929 999
930 1000 $mailClass = new MailClass();
1001 + $mailerHelper = new MailerHelper();
1002 + $mailerHelper->autoAddUser = true;
1003 + $adminNotificationEmail = $mailClass->getOneByName('acy_notification_auto_campaign_admin');
931 1004 $time = time();
932 1005
933 1006 foreach ($activeAutoCampaigns as $campaign) {
934 - if (!empty($campaign->sending_params['start_date']) && (int)acym_getTime(acym_date($campaign->sending_params['start_date'], 'Y-m-d H:i')) > $time) continue;
1007 + // Check the start date
1008 + $nextTrigger = $campaign->next_trigger;
1009 + if (empty($nextTrigger) && !empty($campaign->sending_params['start_date'])) {
1010 + $nextTrigger = $campaign->sending_params['start_date'];
1011 + }
935 1012
1013 + if (!empty($nextTrigger) && acym_getTime(acym_date($nextTrigger, 'Y-m-d H:i')) > $time) {
1014 + continue;
1015 + }
1016 +
1017 + //check if we trigger the campaign
936 1018 $step = new \stdClass();
937 1019 $step->triggers = $campaign->sending_params;
938 1020 $step->last_execution = $campaign->last_generated;
939 1021 $step->next_execution = $campaign->next_trigger;
@@ -946,8 +1028,9 @@
946 1028 $this->save($campaign);
947 1029 continue;
948 1030 }
949 1031
1032 + //update the campaign
950 1033 $campaignMail = $mailClass->getOneById($campaign->mail_id);
951 1034
952 1035 $lastGenerated = $campaign->last_generated;
953 1036 $shouldGenerate = $this->updateAutoCampaign($campaign, $campaignMail, $time);
@@ -952,24 +1035,44 @@
952 1035 $lastGenerated = $campaign->last_generated;
953 1036 $shouldGenerate = $this->updateAutoCampaign($campaign, $campaignMail, $time);
954 1037 $this->save($campaign);
955 1038
956 - if (!$shouldGenerate) continue;
1039 + if (!$shouldGenerate) {
1040 + continue;
1041 + }
957 1042
1043 + //We generate the new campaign
958 1044 $generatedCampaign = $this->generateCampaign($campaign, $campaignMail, $lastGenerated, $mailClass);
1045 + if (empty($generatedCampaign)) {
1046 + $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_FAILED_GENERATING', $campaign->name);
1047 + continue;
1048 + }
959 1049
1050 + $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_GENERATED', $campaign->name, $campaign->sending_params['number_generated']);
1051 +
1052 + // We send it directly if no confirmation is needed
960 1053 if (empty($campaign->sending_params['need_confirm_to_send'])) {
961 1054 $this->send($generatedCampaign->id);
1055 + } elseif (!empty($campaign->sending_params['admin_notification_emails']) && !empty($adminNotificationEmail)) {
1056 + $mailerHelper->addParam('campaign_name', $campaign->name);
1057 + $campaignLink = '<a href="'.acym_backendLink('campaigns&task=summaryGenerated&campaignId='.$generatedCampaign->id).'">'.$campaign->name.'</a>';
1058 + $mailerHelper->addParam('campaign_link', $campaignLink);
1059 +
1060 + foreach ($campaign->sending_params['admin_notification_emails'] as $email) {
1061 + $mailerHelper->sendOne($adminNotificationEmail->id, $email);
1062 + }
962 1063 }
963 1064 }
964 1065 }
965 1066
966 - private function shouldGenerateCampaign($campaign, $campaignMail): bool
1067 + private function shouldGenerateCampaign(object $campaign, object $campaignMail): bool
967 1068 {
1069 + // The generateByCategory function is the only one that can stop a campaign generation, with min number of items
968 1070 $results = acym_trigger('generateByCategory', [&$campaignMail], null, function ($plugin) {
969 1071 $plugin->generateCampaignResult->status = true;
970 1072 });
971 1073
1074 + // If one of the return statuses is "false", we won't generate the campaign
972 1075 foreach ($results as $oneResult) {
973 1076 if (isset($oneResult->status) && !$oneResult->status) {
974 1077 $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_NOT_GENERATED', $campaign->name, $oneResult->message);
975 1078
@@ -979,9 +1082,9 @@
979 1082
980 1083 return true;
981 1084 }
982 1085
983 - private function updateAutoCampaign(&$campaign, $campaignMail, $time): bool
1086 + private function updateAutoCampaign(object $campaign, object $campaignMail, int $time): bool
984 1087 {
985 1088 if (!$this->shouldGenerateCampaign($campaign, $campaignMail)) {
986 1089 return false;
987 1090 }
@@ -992,16 +1095,18 @@
992 1095 $campaign->sending_params['number_generated']++;
993 1096 }
994 1097 $campaign->last_generated = $time;
995 1098
996 - $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_GENERATED', $campaign->name, $campaign->sending_params['number_generated']);
997 -
998 1099 return true;
999 1100 }
1000 1101
1001 - private function generateCampaign($campaign, $campaignMail, $lastGenerated, $mailClass)
1102 + private function generateCampaign(object $campaign, object $campaignMail, ?int $lastGenerated, MailClass $mailClass): ?object
1002 1103 {
1003 1104 $newMail = $this->generateMailAutoCampaign($campaignMail, $campaign->sending_params['number_generated'], $mailClass);
1105 + if (empty($newMail)) {
1106 + return null;
1107 + }
1108 +
1004 1109 $newCampaign = new \stdClass();
1005 1110 $newCampaign->mail_id = $newMail->id;
1006 1111 $newCampaign->parent_id = $campaign->id;
1007 1112 $newCampaign->active = 1;
@@ -1013,8 +1118,9 @@
1013 1118 $newCampaign->sending_params = empty($campaign->sending_params['segment']) ? '' : ['segment' => $campaign->sending_params['segment']];
1014 1119
1015 1120 $newCampaign->id = $this->save($newCampaign);
1016 1121
1122 + // Replace content in the generated mail. MUST be done after campaign has been saved
1017 1123 acym_trigger('replaceContent', [&$newMail, false]);
1018 1124 $mailClass->save($newMail);
1019 1125
1020 1126 return $newCampaign;
@@ -1019,9 +1125,9 @@
1019 1125
1020 1126 return $newCampaign;
1021 1127 }
1022 1128
1023 - private function generateMailAutoCampaign($newMail, $generatedMailNumber, $mailClass)
1129 + private function generateMailAutoCampaign(object $newMail, int $generatedMailNumber, MailClass $mailClass): ?object
1024 1130 {
1025 1131 $mailId = $newMail->id;
1026 1132 unset($newMail->id);
1027 1133 $newMail->creation_date = acym_date('now', 'Y-m-d H:i:s', false);
@@ -1027,8 +1133,12 @@
1027 1133 $newMail->creation_date = acym_date('now', 'Y-m-d H:i:s', false);
1028 1134 $newMail->name .= ' #'.$generatedMailNumber;
1029 1135
1030 1136 $newMail->id = $mailClass->save($newMail);
1137 + if (empty($newMail->id)) {
1138 + return null;
1139 + }
1140 +
1031 1141 $this->setListToGeneratedCampaign($mailId, $newMail->id, $mailClass);
1032 1142
1033 1143 if (acym_isMultilingual()) {
1034 1144 $this->generateMailAutoCampaignMultilingual($mailId, $generatedMailNumber, $newMail->id);
@@ -1036,9 +1146,9 @@
1036 1146
1037 1147 return $newMail;
1038 1148 }
1039 1149
1040 - private function generateMailAutoCampaignMultilingual($mailId, $generatedMailNumber, $newParentId)
1150 + private function generateMailAutoCampaignMultilingual(int $mailId, int $generatedMailNumber, int $newParentId): void
1041 1151 {
1042 1152 $mailClass = new MailClass();
1043 1153 $mails = $mailClass->getTranslationsById($mailId, true);
1044 1154
@@ -1050,9 +1160,9 @@
1050 1160 $mailClass->save($mail);
1051 1161 }
1052 1162 }
1053 1163
1054 - private function setListToGeneratedCampaign($parentMailId, $newMailId, $mailClass)
1164 + private function setListToGeneratedCampaign(int $parentMailId, int $newMailId, MailClass $mailClass): void
1055 1165 {
1056 1166 $lists = $mailClass->getAllListsByMailId($parentMailId);
1057 1167 $listIds = array_keys($lists);
1058 1168
@@ -1058,27 +1168,32 @@
1058 1168
1059 1169 $this->manageListsToCampaign($listIds, $newMailId);
1060 1170 }
1061 1171
1062 - public function getLastGenerated($mailId)
1172 + public function getLastGenerated(int $mailId): int
1063 1173 {
1064 - return acym_loadResult(
1174 + $lastGenerated = acym_loadResult(
1065 1175 'SELECT `last_generated`
1066 1176 FROM #__acym_campaign
1067 1177 WHERE `mail_id` = '.intval($mailId)
1068 1178 );
1179 +
1180 + return empty($lastGenerated) ? 0 : $lastGenerated;
1069 1181 }
1070 1182
1071 - public function getAllCampaignsGenerated()
1183 + private function getNbGeneratedCampaigns(): int
1072 1184 {
1073 - $query = 'SELECT id FROM #__acym_campaign WHERE parent_id IS NOT NULL AND sending_type = '.acym_escapeDB(self::SENDING_TYPE_NOW);
1074 -
1075 - return acym_loadObjectList($query);
1185 + return (int)acym_loadResult(
1186 + 'SELECT COUNT(*)
1187 + FROM #__acym_campaign
1188 + WHERE `parent_id` IS NOT NULL
1189 + AND `sending_type` = '.acym_escapeDB(self::SENDING_TYPE_NOW)
1190 + );
1076 1191 }
1077 1192
1078 - public function getAllCampaignsGeneratedWaiting()
1193 + public function getAllCampaignsGeneratedWaiting(): array
1079 1194 {
1080 - return acym_loadObjectList(
1195 + $campaignIds = acym_loadObjectList(
1081 1196 'SELECT id
1082 1197 FROM #__acym_campaign
1083 1198 WHERE parent_id IS NOT NULL
1084 1199 AND sending_type = '.acym_escapeDB(self::SENDING_TYPE_NOW).'
@@ -1085,11 +1200,14 @@
1085 1200 AND draft = 1
1086 1201 AND active = 1
1087 1202 AND sent = 0'
1088 1203 );
1204 + acym_arrayToInteger($campaignIds);
1205 +
1206 + return $campaignIds;
1089 1207 }
1090 1208
1091 - public function getCampaignsByTypes($campaignTypes, $onlyActives = false)
1209 + public function getCampaignsByTypes(array $campaignTypes, bool $onlyActives = false): array
1092 1210 {
1093 1211 if (empty($campaignTypes)) return [];
1094 1212 $campaignTypes = array_map('acym_escapeDB', $campaignTypes);
1095 1213 $query = 'SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.sending_type IN ('.implode(',', $campaignTypes).')';
@@ -1097,16 +1215,16 @@
1097 1215
1098 1216 return $this->decode(acym_loadObjectList($query), false);
1099 1217 }
1100 1218
1101 - public function getCountCampaignType($type)
1219 + public function getCountCampaignType(string $type): int
1102 1220 {
1103 1221 if (empty($type)) return 0;
1104 1222
1105 - return acym_loadResult('SELECT COUNT(*) FROM #__acym_campaign WHERE sending_type = '.acym_escapeDB($type));
1223 + return (int)acym_loadResult('SELECT COUNT(*) FROM #__acym_campaign WHERE sending_type = '.acym_escapeDB($type));
1106 1224 }
1107 1225
1108 - public function getAllAbTestCampaignsToFinishSending()
1226 + public function getAllAbTestCampaignsToFinishSending(): array
1109 1227 {
1110 1228 $query = 'SELECT * FROM #__acym_campaign WHERE sending_params LIKE \'%"abtest":%\' AND draft = 0 AND active = 1 AND sent = 1';
1111 1229
1112 1230 return $this->decode(acym_loadObjectList($query));
@@ -1111,9 +1229,9 @@
1111 1229
1112 1230 return $this->decode(acym_loadObjectList($query));
1113 1231 }
1114 1232
1115 - public function finishAbTestCampaign($campaign)
1233 + public function finishAbTestCampaign(object $campaign): bool
1116 1234 {
1117 1235 $abTestParams = empty($campaign->sending_params['abtest']) ? [] : $campaign->sending_params['abtest'];
1118 1236
1119 1237 if (empty($abTestParams['B']) || empty($abTestParams['repartition']) || !empty($abTestParams['abtest_finished']) || empty($abTestParams['after']['action'])) {
@@ -1164,9 +1282,9 @@
1164 1282 $mail->id = 0;
1165 1283 $mail->parent_id = $campaign->mail_id;
1166 1284 $mail->name .= ' - '.acym_translation('ACYM_ABTEST_WINNER');
1167 1285 $newMailId = $mailClass->save($mail);
1168 - if (!$newMailId) {
1286 + if (empty($newMailId)) {
1169 1287 return false;
1170 1288 }
1171 1289
1172 1290 $campaign->sending_params['abtest']['abtest_finished'] = 1;
@@ -1177,24 +1295,24 @@
1177 1295
1178 1296 return true;
1179 1297 }
1180 1298
1181 - public function isAbTestMail($mailId)
1299 + public function isAbTestMail(int $mailId): bool
1182 1300 {
1183 - $query = 'SELECT * FROM #__acym_campaign WHERE mail_id = '.intval($mailId).' AND sending_params LIKE \'%"abtest":%\'';
1301 + $mailClass = new MailClass();
1302 + $mainMailId = $mailClass->getMainMailId($mailId);
1184 1303
1185 - if (!empty(acym_loadObject($query))) {
1186 - return true;
1187 - }
1304 + $campaign = acym_loadObject(
1305 + 'SELECT *
1306 + FROM #__acym_campaign
1307 + WHERE mail_id = '.intval($mainMailId).'
1308 + AND sending_params LIKE \'%"abtest":%\''
1309 + );
1188 1310
1189 - $query = 'SELECT * FROM #__acym_campaign AS campaign JOIN #__acym_mail AS mail ON campaign.mail_id = mail.parent_id AND mail.id = '.intval(
1190 - $mailId
1191 - ).' WHERE sending_params LIKE \'%"abtest":%\'';
1192 -
1193 - return !empty(acym_loadObject($query));
1311 + return !empty($campaign);
1194 1312 }
1195 1313
1196 - public function resetAbTestVersion($campaignId): void
1314 + public function resetAbTestVersion(int $campaignId): void
1197 1315 {
1198 1316 if (empty($campaignId)) {
1199 1317 return;
1200 1318 }
@@ -1211,9 +1329,9 @@
1211 1329
1212 1330 foreach (self::AB_TEST_VERSIONS as $version) {
1213 1331 if (!empty($campaign->sending_params['abtest'][$version])) {
1214 1332 $mailClass = new MailClass();
1215 - $mailClass->delete($campaign->sending_params['abtest'][$version]);
1333 + $mailClass->delete([$campaign->sending_params['abtest'][$version]]);
1216 1334 unset($campaign->sending_params['abtest'][$version]);
1217 1335 }
1218 1336 }
1219 1337
@@ -1219,9 +1337,9 @@
1219 1337
1220 1338 $this->save($campaign);
1221 1339 }
1222 1340
1223 - public function getXCampaigns(array $options)
1341 + public function getXCampaigns(array $options): array
1224 1342 {
1225 1343 $limit = $options['limit'] ?? 10;
1226 1344 $offset = $options['offset'] ?? 0;
1227 1345 $filters = $options['filters'] ?? [];
@@ -1256,6 +1374,13 @@
1256 1374 $query .= ' WHERE '.implode(' AND ', $conditions);
1257 1375 }
1258 1376
1259 1377 return $this->decode(acym_loadObjectList($query, $this->pkey, $offset, $limit));
1378 + }
1379 +
1380 + public function getOneCampaign(): bool
1381 + {
1382 + $firstCampaign = acym_loadObject('SELECT * FROM #__acym_campaign');
1383 +
1384 + return !empty($firstCampaign);
1260 1385 }
1261 1386 }