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/ListClass.php +255 -155 10.0.1 → 11.1.0 View file →
@@ -10,8 +10,9 @@
10 10 {
11 11 const LIST_TYPE_STANDARD = 'standard';
12 12 const LIST_TYPE_FRONT = 'front';
13 13 const LIST_TYPE_FOLLOWUP = 'followup';
14 + const COLOR_PARTS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
14 15
15 16 public function __construct()
16 17 {
17 18 parent::__construct();
@@ -28,16 +29,35 @@
28 29 if ($value == 'lists.list_id') {
29 30 unset($settings['columns'][$key]);
30 31 continue;
31 32 }
32 - $settings['columns'][$key] = $key === 'join' ? $value : 'list.'.$value;
33 + $settings['columns'][$key] = $key === 'join' ? acym_secureDBColumn($value) : 'list.'.acym_secureDBColumn($value);
33 34 }
34 35 $columns = implode(', ', $settings['columns']);
35 36 }
36 37
37 38 $query = 'SELECT '.$columns.' FROM #__acym_list AS list';
38 - $queryCount = 'SELECT COUNT(list.id) FROM #__acym_list AS list';
39 + $queryCount = 'SELECT COUNT(list.id) AS total FROM #__acym_list AS list';
39 40 if (!empty($settings['join'])) $query .= $this->getJoinForQuery($settings['join']);
41 + /*
42 + This query will return for example:
43 +
44 + array(
45 + 6 => 0,
46 + 2 => 1,
47 + 5 => 2,
48 + 12 => 3
49 + )
50 +
51 + It would mean that:
52 +
53 + 6 lists are disabled and invisible 0 + (0*2) = 0
54 + 2 lists are active and invisible 1 + (0*2) = 1
55 + 5 lists are inactive and visible 0 + (1*2) = 2
56 + 12 lists are active and visible 1 + (1*2) = 3
57 +
58 + So there are 2 + 12 active lists and 5 + 12 visible lists, get it?
59 + */
40 60 $queryStatus = 'SELECT COUNT(id) AS number, active + (visible*2) AS score FROM #__acym_list AS list';
41 61 $filters = [];
42 62 $listsId = [];
43 63
@@ -107,9 +127,9 @@
107 127 if (!empty($settings['join'])) {
108 128 $this->setSelectedList($results['elements'], $settings['join']);
109 129 }
110 130 foreach ($results['elements'] as $i => $oneList) {
111 - array_push($listsId, $oneList->id);
131 + $listsId[] = $oneList->id;
112 132 $results['elements'][$i]->sendable_users = 0;
113 133 $results['elements'][$i]->unconfirmed_users = 0;
114 134 $results['elements'][$i]->unsubscribed_users = 0;
115 135 $results['elements'][$i]->inactive_users = 0;
@@ -119,10 +139,10 @@
119 139
120 140 $countUserByList = [];
121 141 $countEvolByList = [];
122 142 if (!empty($listsId) && empty($settings['entitySelect'])) {
123 - $countUserByList = $this->getSubscribersCountPerStatusByListId($listsId);
124 - $countEvolByList = $this->getSubscribersEvolutionByList($listsId);
143 + $countUserByList = $this->getSubscribersCountPerStatusByListIds($listsId);
144 + $countEvolByList = $this->getSubscribersEvolutionByListIds($listsId);
125 145 }
126 146
127 147 foreach ($results['elements'] as $i => $list) {
128 148 $results['elements'][$i]->tags = [];
@@ -137,12 +157,12 @@
137 157 if (isset($countEvolByList[$list->id]->newSub)) $results['elements'][$i]->newSub = $countEvolByList[$list->id]->newSub;
138 158 if (isset($countEvolByList[$list->id]->newUnsub)) $results['elements'][$i]->newUnsub = $countEvolByList[$list->id]->newUnsub;
139 159 }
140 160
141 - $results['total'] = acym_loadResult($queryCount);
161 + $results['total'] = acym_loadObject($queryCount);
142 162
143 163 $listsPerStatus = acym_loadObjectList($queryStatus.' GROUP BY score', 'score');
144 - for ($i = 0 ; $i < 4 ; $i++) {
164 + for ($i = 0; $i < 4; $i++) {
145 165 $listsPerStatus[$i] = empty($listsPerStatus[$i]) ? 0 : $listsPerStatus[$i]->number;
146 166 }
147 167
148 168 $results['status'] = [
@@ -155,9 +175,9 @@
155 175
156 176 return $results;
157 177 }
158 178
159 - public function getOneById($id)
179 + public function getOneById(int $id): ?object
160 180 {
161 181 $list = parent::getOneById($id);
162 182
163 183 if (!empty($list)) {
@@ -166,21 +186,23 @@
166 186
167 187 return $list;
168 188 }
169 189
170 - private function setSelectedList(&$elements, $join)
190 + private function setSelectedList(array $elements, string $join): void
171 191 {
172 - if (strpos($join, 'join_list') !== false) {
173 - $listsIds = explode('-', $join);
174 - $listsIds = $listsIds[1];
175 - $listsIds = explode(',', $listsIds);
176 - foreach ($elements as $key => $element) {
177 - $elements[$key]->list_id = in_array($element->id, $listsIds) ? $element->id : null;
178 - }
192 + if (strpos($join, 'join_list') === false) {
193 + return;
179 194 }
195 +
196 + $listsIds = explode('-', $join);
197 + $listsIds = $listsIds[1];
198 + $listsIds = explode(',', $listsIds);
199 + foreach ($elements as $element) {
200 + $element->list_id = in_array($element->id, $listsIds) ? $element->id : null;
201 + }
180 202 }
181 203
182 - public function getJoinForQuery($joinType)
204 + private function getJoinForQuery(string $joinType): string
183 205 {
184 206 if (strpos($joinType, 'join_mail') !== false) {
185 207 $mailId = explode('-', $joinType);
186 208
@@ -194,9 +216,9 @@
194 216
195 217 return '';
196 218 }
197 219
198 - public function getListsWithIdNameCount($settings)
220 + public function getListsWithIdNameCount(array $settings): array
199 221 {
200 222 $filters = [];
201 223
202 224 if (isset($settings['ids'])) {
@@ -254,24 +276,20 @@
254 276 }
255 277
256 278 $query .= ' GROUP BY list.id ';
257 279
258 - $results['lists'] = acym_loadObjectList($query, '', $settings['offset'], $settings['listsPerPage']);
259 - $results['total'] = acym_loadResult($queryCount);
260 -
261 - return $results;
280 + return [
281 + 'lists' => acym_loadObjectList($query, '', $settings['offset'], $settings['listsPerPage']),
282 + 'total' => (int)acym_loadResult($queryCount),
283 + ];
262 284 }
263 285
264 - public function getOneByName($name)
286 + public function getListsByIds(array $ids): array
265 287 {
266 - return acym_loadObject('SELECT * FROM #__acym_list WHERE `name` = '.acym_escapeDB($name));
267 - }
268 -
269 - public function getListsByIds($ids)
270 - {
271 - if (!is_array($ids)) $ids = [$ids];
272 288 acym_arrayToInteger($ids);
273 - if (empty($ids)) return [];
289 + if (empty($ids)) {
290 + return [];
291 + }
274 292
275 293 $query = 'SELECT * FROM #__acym_list WHERE id IN ('.implode(', ', $ids).')';
276 294
277 295 return acym_loadObjectList($query);
@@ -276,42 +294,14 @@
276 294
277 295 return acym_loadObjectList($query);
278 296 }
279 297
280 - public function getAllListUsers()
298 + public function getSubscribersCount(array $listsIds): int
281 299 {
282 - $query = 'SELECT #__acym_user_has_list.list_id, count(*)
283 - FROM #__acym_list AS list
284 - JOIN #__acym_user_has_list
285 - ON list.id = #__acym_user_has_list.list_id
286 - JOIN #__acym_user
287 - ON #__acym_user.id = #__acym_user_has_list.user_id
288 - GROUP BY list.id';
289 -
290 - return acym_loadObjectList($query);
291 - }
292 -
293 - public function getSubscribersCountByListId($id)
294 - {
295 - $confirmed = $this->config->get('require_confirmation', 1) == 1 ? ' AND users.confirmed = 1 ' : '';
296 -
297 - $query = 'SELECT COUNT(userLists.user_id) AS subscribers
298 - FROM #__acym_user_has_list AS userLists
299 - JOIN #__acym_user AS users ON userLists.user_id = users.id
300 - WHERE userLists.list_id = '.intval($id).'
301 - AND userLists.status = 1
302 - AND users.active = 1 '.$confirmed.'
303 - GROUP BY userLists.list_id';
304 -
305 - $result = acym_loadResult($query);
306 -
307 - return empty($result) ? 0 : $result;
308 - }
309 -
310 - public function getSubscribersCount($listsIds)
311 - {
312 300 acym_arrayToInteger($listsIds);
313 - if (empty($listsIds)) return 0;
301 + if (empty($listsIds)) {
302 + return 0;
303 + }
314 304
315 305 $query = 'SELECT COUNT(DISTINCT user.id)
316 306 FROM #__acym_user AS user
317 307 JOIN #__acym_user_has_list AS userList ON user.id = userList.user_id
@@ -320,30 +310,22 @@
320 310 if ($this->config->get('require_confirmation', 1) == 1) {
321 311 $query .= ' AND user.confirmed = 1';
322 312 }
323 313
324 - return acym_loadResult($query);
314 + return (int)acym_loadResult($query);
325 315 }
326 316
327 - public function getSubscribersIdsById($listId, $returnUnsubscribed = false)
317 + public function getSubscribersForList(array $options = []): array
328 318 {
329 - $query = 'SELECT user_id FROM #__acym_user_has_list WHERE list_id = '.intval($listId);
330 -
331 - if (!$returnUnsubscribed) {
332 - $query .= ' AND status = 1';
333 - }
334 -
335 - return acym_loadResultArray($query);
336 - }
337 -
338 - public function getSubscribersForList(array $options = [])
339 - {
340 319 $listIds = $options['listIds'] ?? [];
341 320 $offset = $options['offset'] ?? 0;
342 321 $limit = $options['limit'] ?? 100;
343 322 $status = $options['status'] ?? null;
344 323 $orderBy = $options['orderBy'] ?? '';
345 - $orderBySort = $options['orderBySort'] ?? '';
324 + $orderBySort = strtolower((string)($options['orderBySort'] ?? ''));
325 + if (!in_array($orderBySort, ['asc', 'desc'], true)) {
326 + $orderBySort = empty($orderBy) ? 'asc' : 'desc';
327 + }
346 328 $subscribedAfter = $options['subscribed_after'] ?? null;
347 329 $unsubscribedAfter = $options['unsubscribed_after'] ?? null;
348 330
349 331 if (empty($listIds)) {
@@ -368,11 +350,14 @@
368 350 $requestSub = 'SELECT user.*, user_list.status, user_list.subscription_date, user_list.unsubscribe_date FROM #__acym_user AS user';
369 351 $requestSub .= ' LEFT JOIN #__acym_user_has_list AS user_list ON user.id = user_list.user_id';
370 352 $requestSub .= ' WHERE user.active = 1 AND user_list.list_id IN ('.implode(', ', $listIds).')'.$statusCondition;
371 353
372 - if (!empty($orderBy)) {
373 - if (empty($orderBySort)) $orderBySort = 'desc';
374 - $requestSub .= ' ORDER BY '.acym_secureDBColumn($orderBy).' '.acym_secureDBColumn($orderBySort);
354 + $orderByColumn = empty($orderBy) ? 'user.id' : acym_secureDBColumn($orderBy);
355 + $requestSub .= ' ORDER BY '.$orderByColumn.' '.$orderBySort;
356 +
357 + // Any other column can hold duplicates, we need a unique one to break the ties
358 + if (!in_array($orderByColumn, ['id', 'user.id'], true)) {
359 + $requestSub .= ', user.id ASC';
375 360 }
376 361
377 362 return acym_loadObjectList(
378 363 $requestSub,
@@ -381,16 +366,17 @@
381 366 $limit
382 367 );
383 368 }
384 369
385 - public function delete($elements, $force = false)
370 + public function delete(array $elements, bool $force = false): int
386 371 {
387 - if (!is_array($elements)) $elements = [$elements];
388 372 if (!$force) {
389 373 $this->onlyManageableLists($elements);
390 374 }
391 375
392 - if (empty($elements)) return 0;
376 + if (empty($elements)) {
377 + return 0;
378 + }
393 379
394 380 foreach ($elements as $id) {
395 381 acym_query('DELETE FROM #__acym_mail_has_list WHERE list_id = '.intval($id));
396 382 acym_query('DELETE FROM #__acym_user_has_list WHERE list_id = '.intval($id));
@@ -399,16 +385,18 @@
399 385
400 386 return parent::delete($elements);
401 387 }
402 388
403 - public function synchDeleteCmsList($userId)
389 + public function synchDeleteCmsList(int $userId): void
404 390 {
405 391 $query = 'SELECT * FROM #__acym_list WHERE type = "'.self::LIST_TYPE_FRONT.'" AND cms_user_id = '.intval($userId);
406 392 $listFrontManagement = acym_loadObject($query);
407 - if (!empty($listFrontManagement)) $this->delete([$listFrontManagement->id]);
393 + if (!empty($listFrontManagement)) {
394 + $this->delete([$listFrontManagement->id]);
395 + }
408 396 }
409 397
410 - public function save($list)
398 + public function save(object $list): ?int
411 399 {
412 400 if (isset($list->tags)) {
413 401 $tags = $list->tags;
414 402 unset($list->tags);
@@ -434,9 +422,9 @@
434 422
435 423 foreach ($list as $oneAttribute => $value) {
436 424 if (empty($value)) continue;
437 425
438 - $list->$oneAttribute = strip_tags($value);
426 + $list->$oneAttribute = acym_stripTags($value);
439 427 }
440 428
441 429 if (empty($list->description)) {
442 430 $list->description = '';
@@ -453,9 +441,13 @@
453 441 }
454 442
455 443 $listID = parent::save($list);
456 444
457 - if (!empty($listID) && isset($tags)) {
445 + if (empty($listID)) {
446 + return null;
447 + }
448 +
449 + if (isset($tags)) {
458 450 $tagClass = new TagClass();
459 451 $tagClass->setTags(TagClass::TYPE_LIST, intval($listID), $tags);
460 452 }
461 453
@@ -491,9 +483,9 @@
491 483
492 484 return $listsToReturn;
493 485 }
494 486
495 - public function getAllForSelect($emptyFirst = true, $userFrontID = 0, $needTranslation = false, $needFrontLabel = false)
487 + public function getAllForSelect(bool $emptyFirst = true, int $userFrontID = 0, bool $needTranslation = false, bool $needFrontLabel = false): array
496 488 {
497 489 $groupCondition = '';
498 490 if (!empty($userFrontID)) {
499 491 $userGroups = acym_getGroupsByUser($userFrontID);
@@ -507,9 +499,11 @@
507 499 }
508 500
509 501 $return = [];
510 502
511 - if ($emptyFirst) $return[''] = acym_translation('ACYM_SELECT_A_LIST');
503 + if ($emptyFirst) {
504 + $return[''] = acym_translation('ACYM_SELECT_A_LIST');
505 + }
512 506
513 507 foreach ($lists as $key => $list) {
514 508 $return[$key] = $needFrontLabel && !empty($list->display_name) ? $list->display_name : $list->name;
515 509 }
@@ -516,9 +510,9 @@
516 510
517 511 return $return;
518 512 }
519 513
520 - public function getAllWithoutManagement($needTranslation = false)
514 + public function getAllWithoutManagement(bool $needTranslation = false): array
521 515 {
522 516 $lists = acym_loadObjectList('SELECT * FROM #__acym_list WHERE `type` = '.acym_escapeDB(self::LIST_TYPE_STANDARD), 'id');
523 517
524 518 if (acym_isMultilingual() && $needTranslation) {
@@ -527,9 +521,9 @@
527 521
528 522 return $lists;
529 523 }
530 524
531 - public function getTranslatedNameDescription($lists)
525 + public function getTranslatedNameDescription(array $lists): array
532 526 {
533 527 $currentLanguageTag = acym_getLanguageTag();
534 528 foreach ($lists as $id => $list) {
535 529 if (empty($list->translation)) continue;
@@ -536,17 +530,17 @@
536 530
537 531 $list->translation = json_decode($list->translation, true);
538 532 if (!empty($list->translation[$currentLanguageTag])) {
539 533 if (!empty($list->translation[$currentLanguageTag]['name'])) {
540 - $lists[$id]->name = $list->translation[$currentLanguageTag]['name'];
534 + $list->name = $list->translation[$currentLanguageTag]['name'];
541 535 }
542 536
543 537 if (!empty($list->translation[$currentLanguageTag]['display_name'])) {
544 - $lists[$id]->display_name = $list->translation[$currentLanguageTag]['display_name'];
538 + $list->display_name = $list->translation[$currentLanguageTag]['display_name'];
545 539 }
546 540
547 541 if (!empty($list->translation[$currentLanguageTag]['description'])) {
548 - $lists[$id]->description = $list->translation[$currentLanguageTag]['description'];
542 + $list->description = $list->translation[$currentLanguageTag]['description'];
549 543 }
550 544 }
551 545 }
552 546
@@ -552,9 +546,12 @@
552 546
553 547 return $lists;
554 548 }
555 549
556 - public function sendWelcome(int $userID, array $listIDs, bool $forceFront = false)
550 + /**
551 + * Sends the welcome emails attached to the specified lists
552 + */
553 + public function sendWelcome(int $userID, array $listIDs, bool $forceFront = false): void
557 554 {
558 555 if (!$forceFront && acym_isAdmin()) {
559 556 return;
560 557 }
@@ -571,13 +568,14 @@
571 568 }
572 569
573 570 $alreadySent = [];
574 571 $mailerHelper = new MailerHelper();
575 - $mailerHelper->report = $this->config->get('welcome_message', 1);
572 + $mailerHelper->report = (bool)$this->config->get('welcome_message', 1);
576 573 foreach ($messages as $oneMessage) {
577 574 $mailid = $oneMessage->welcome_id;
578 575 if (empty($mailid)) continue;
579 576
577 + //We don't send twice the same message
580 578 if (isset($alreadySent[$mailid])) {
581 579 continue;
582 580 }
583 581
@@ -586,9 +584,12 @@
586 584 $alreadySent[$mailid] = true;
587 585 }
588 586 }
589 587
590 - public function sendUnsubscribe($userID, $listIDs)
588 + /**
589 + * Sends the unsubscribe emails attached to the specified lists
590 + */
591 + public function sendUnsubscribe(int $userID, array $listIDs): void
591 592 {
592 593 if (acym_isAdmin()) {
593 594 return;
594 595 }
@@ -605,13 +606,14 @@
605 606 }
606 607
607 608 $alreadySent = [];
608 609 $mailerHelper = new MailerHelper();
609 - $mailerHelper->report = $this->config->get('unsub_message', 1);
610 + $mailerHelper->report = (bool)$this->config->get('unsub_message', 1);
610 611 foreach ($messages as $oneMessage) {
611 612 if (!empty($oneMessage->unsubscribe_id)) {
612 613 $mailid = $oneMessage->unsubscribe_id;
613 614
615 + //We don't send twice the same message
614 616 if (isset($alreadySent[$mailid])) {
615 617 continue;
616 618 }
617 619
@@ -634,10 +636,9 @@
634 636 $this->save($defaultList);
635 637 }
636 638 }
637 639
638 -
639 - public function getTotalSubCount($ids)
640 + public function getTotalSubCount(array $ids): int
640 641 {
641 642 if (empty($ids)) {
642 643 return 0;
643 644 }
@@ -659,24 +660,32 @@
659 660
660 661 return intval(acym_loadResult($query));
661 662 }
662 663
663 - public function getMailsByListId($listId)
664 + /**
665 + * Get all mails attached to a list
666 + */
667 + public function getMailsByListId(int $listId): array
664 668 {
665 - $query = 'SELECT mail_id FROM #__acym_mail_has_list WHERE list_id = '.intval($listId);
669 + $mailIds = acym_loadResultArray('SELECT mail_id FROM #__acym_mail_has_list WHERE list_id = '.intval($listId));
666 670
667 - return acym_loadResultArray($query);
671 + return empty($mailIds) ? [] : $mailIds;
668 672 }
669 673
670 - public function getSubscribersCountPerStatusByListId($listIds = [])
674 + public function getSubscribersCountPerStatusByListIds(array $listIds = []): array
671 675 {
672 676 $condList = '';
673 677 if (!empty($listIds)) {
674 - if (!is_array($listIds)) $listIds = [$listIds];
675 678 acym_arrayToInteger($listIds);
676 679 $condList = 'AND userList.list_id IN ('.implode(',', $listIds).')';
677 680 }
678 681
682 + /*
683 + * score:
684 + * An unconfirmed and active user will have a score of 0 + 1*2 = 2
685 + * A confirmed and active user will have a score of 1 + 1*2 = 3
686 + * A confirmed and inactive user will have a score of 1 + 0*2 = 1
687 + */
679 688 $query = 'SELECT userList.list_id, COUNT(userList.user_id) AS users, acyuser.confirmed + acyuser.active*2 AS score
680 689 FROM #__acym_user_has_list AS userList
681 690 JOIN #__acym_user AS acyuser
682 691 ON acyuser.id = userList.user_id
@@ -691,8 +700,9 @@
691 700 if (!isset($listsUserStats[$oneResult->list_id])) {
692 701 $listsUserStats[$oneResult->list_id] = $this->initList($oneResult->list_id);
693 702 }
694 703
704 + // Joomla 4 casts the result into an int
695 705 $oneResult->score = (string)$oneResult->score;
696 706
697 707 if (in_array($oneResult->score, ['0', '1'])) {
698 708 $listsUserStats[$oneResult->list_id]->inactive_users += $oneResult->users;
@@ -723,13 +733,12 @@
723 733
724 734 return $listsUserStats;
725 735 }
726 736
727 - public function getSubscribersEvolutionByList($listIds)
737 + public function getSubscribersEvolutionByListIds(array $listIds): array
728 738 {
729 739 $condList = '';
730 740 if (!empty($listIds)) {
731 - if (!is_array($listIds)) $listIds = [$listIds];
732 741 acym_arrayToInteger($listIds);
733 742 $condList = ' AND list_id IN ('.implode(',', $listIds).')';
734 743 }
735 744 $dateNow = acym_loadResult('SELECT DATE_SUB(NOW(), INTERVAL 1 MONTH)');
@@ -743,9 +752,11 @@
743 752 $queryEvolUnsub .= ' GROUP BY list_id';
744 753 $newUnsubscribers = acym_loadObjectList($queryEvolUnsub, 'list_id');
745 754
746 755 foreach ($newUnsubscribers as $listId => $oneUnsub) {
747 - if (empty($evolSubscibers[$listId])) $evolSubscibers[$listId] = new \stdClass();
756 + if (empty($evolSubscibers[$listId])) {
757 + $evolSubscibers[$listId] = new \stdClass();
758 + }
748 759 $evolSubscibers[$listId]->newUnsub = $oneUnsub->newUnsub;
749 760 }
750 761
751 762 return $evolSubscibers;
@@ -750,18 +761,19 @@
750 761
751 762 return $evolSubscibers;
752 763 }
753 764
754 - public function getYearSubEvolutionPerList($listId)
765 + public function getYearSubEvolutionPerList(int $listId): array
755 766 {
756 - $listId = intval($listId);
757 - $month = date('n') + 1;
758 - $year = date('Y') - 1;
767 + // Get next month from 1 year ago
768 + $month = gmdate('n') + 1;
769 + $year = gmdate('Y') - 1;
759 770 $initDate = $year.'-'.$month.'-01';
760 771 if ($month == 13) {
761 - $initDate = date('Y').'-01-01';
772 + $initDate = gmdate('Y').'-01-01';
762 773 }
763 774
775 + // Get new subscribers per month
764 776 $queryEvolSub = 'SELECT MONTH(subscription_date) as monthSub, DATE_FORMAT(subscription_date,"%Y_%m") AS unit, COUNT(user_id) AS nbUser';
765 777 $queryEvolSub .= ' FROM `#__acym_user_has_list`';
766 778 $queryEvolSub .= ' WHERE subscription_date >= "'.$initDate.'" AND list_id = '.$listId;
767 779 $queryEvolSub .= ' GROUP BY unit';
@@ -766,8 +778,9 @@
766 778 $queryEvolSub .= ' WHERE subscription_date >= "'.$initDate.'" AND list_id = '.$listId;
767 779 $queryEvolSub .= ' GROUP BY unit';
768 780 $evolSubscibers = acym_loadObjectList($queryEvolSub, 'unit');
769 781
782 + // Get unsubscribers per month
770 783 $queryEvolUnsub = 'SELECT MONTH(unsubscribe_date) as monthUnsub, DATE_FORMAT(unsubscribe_date,"%Y_%m") AS unit, COUNT(user_id) AS nbUser';
771 784 $queryEvolUnsub .= ' FROM `#__acym_user_has_list`';
772 785 $queryEvolUnsub .= ' WHERE unsubscribe_date >= "'.$initDate.'" AND list_id = '.$listId;
773 786 $queryEvolUnsub .= ' GROUP BY unit';
@@ -778,9 +791,9 @@
778 791 'unsubscribers' => $evolUnsubscibers,
779 792 ];
780 793 }
781 794
782 - private function initList($listId)
795 + private function initList(int $listId): object
783 796 {
784 797 $list = new \stdClass();
785 798 $list->list_id = $listId;
786 799 $list->sendable_users = 0;
@@ -790,12 +803,14 @@
790 803
791 804 return $list;
792 805 }
793 806
794 - public function getManageableLists()
807 + public function getManageableLists(): array
795 808 {
796 809 $idCurrentUser = acym_currentUserId();
797 - if (empty($idCurrentUser)) return [];
810 + if (empty($idCurrentUser)) {
811 + return [];
812 + }
798 813
799 814 $userGroups = acym_getGroupsByUser($idCurrentUser);
800 815
801 816 return acym_loadResultArray(
@@ -805,19 +820,21 @@
805 820 OR (access LIKE "%,'.implode(',%" OR access LIKE "%,', $userGroups).',%")'
806 821 );
807 822 }
808 823
809 - public function onlyManageableLists(&$elements)
824 + public function onlyManageableLists(&$elements): void
810 825 {
811 - if (acym_isAdmin()) return;
826 + if (acym_isAdmin()) {
827 + return;
828 + }
812 829
813 830 $manageableLists = $this->getManageableLists();
814 831 $elements = array_intersect($elements, $manageableLists);
815 832 }
816 833
817 - public function hasUserAccess($listId): bool
834 + public function hasUserAccess(int $listId): bool
818 835 {
819 - if (acym_isAdmin()) {
836 + if (acym_isAdmin() && acym_isAllowed('lists')) {
820 837 return true;
821 838 }
822 839
823 840 return in_array($listId, $this->getManageableLists());
@@ -822,16 +839,20 @@
822 839
823 840 return in_array($listId, $this->getManageableLists());
824 841 }
825 842
826 - public function getfrontManagementList()
843 + public function getfrontManagementList(): int
827 844 {
828 845 $idCurrentUser = acym_currentUserId();
829 - if (empty($idCurrentUser)) return 0;
846 + if (empty($idCurrentUser)) {
847 + return 0;
848 + }
830 849
831 850 $frontListId = acym_loadResult('SELECT id FROM #__acym_list WHERE type = '.acym_escapeDB(self::LIST_TYPE_FRONT).' AND cms_user_id = '.intval($idCurrentUser));
832 851
833 - if (!empty($frontListId)) return $frontListId;
852 + if (!empty($frontListId)) {
853 + return $frontListId;
854 + }
834 855
835 856 $frontList = new \stdClass();
836 857 $frontList->name = 'frontlist_'.$idCurrentUser;
837 858 $frontList->active = 1;
@@ -838,60 +859,78 @@
838 859 $frontList->visible = 0;
839 860 $frontList->cms_user_id = $idCurrentUser;
840 861 $frontList->type = self::LIST_TYPE_FRONT;
841 862
842 - return $this->save($frontList);
863 + return (int)$this->save($frontList);
843 864 }
844 865
845 - public function setWelcomeUnsubEmail($listIds, $mailId, $type)
866 + public function setWelcomeUnsubEmail(array $listIds, int $mailId, string $type): bool
846 867 {
847 868 if (!in_array($type, [MailClass::TYPE_WELCOME, MailClass::TYPE_UNSUBSCRIBE]) || empty($mailId)) {
848 869 return false;
849 870 }
850 871
851 - $column = acym_escape($type).'_id';
872 + $column = esc_attr($type).'_id';
852 873 $columnsList = acym_getColumns('list');
853 - if (!in_array($column, $columnsList)) return false;
874 + if (!in_array($column, $columnsList)) {
875 + return false;
876 + }
854 877
855 - if (!is_array($listIds)) {
856 - if (!empty($listIds)) $listIds = [$listIds];
878 + acym_arrayToInteger($listIds);
879 + $listIds = array_filter($listIds);
880 +
881 + if (!$this->removeWelcomeUnsubByMailId($mailId, $listIds, $column)) {
882 + return false;
857 883 }
858 884
859 - if (!$this->removeWelcomeUnsubByMailId($mailId, $listIds, $column)) return false;
860 -
861 885 foreach ($listIds as $listId) {
862 -
863 886 $list = $this->getOneById($listId);
864 - if (empty($list)) return false;
887 + if (empty($list)) {
888 + continue;
889 + }
865 890
866 891 $list->{$column} = $mailId;
867 892
868 - if (!$this->save($list)) return false;
893 + $savedListId = $this->save($list);
894 + if (empty($savedListId)) {
895 + return false;
896 + }
869 897 }
870 898
871 899 return true;
872 900 }
873 901
874 - private function removeWelcomeUnsubByMailId($mailId, $listIds, $column)
902 + private function removeWelcomeUnsubByMailId(int $mailId, array $listIds, string $column): bool
875 903 {
876 - if (empty($mailId)) return false;
904 + if (empty($mailId)) {
905 + return false;
906 + }
877 907
878 - $where = $column.' = '.intval($mailId);
879 - if (!empty($listIds)) $where .= ' AND id NOT IN ('.implode(',', $listIds).')';
908 + $query = 'SELECT * FROM #__acym_list WHERE '.acym_secureDBColumn($column).' = '.$mailId;
880 909
881 - $lists = acym_loadObjectList('SELECT * FROM #__acym_list WHERE '.$where);
882 - if (empty($lists)) return true;
910 + if (!empty($listIds)) {
911 + acym_arrayToInteger($listIds);
912 + $query .= ' AND `id` NOT IN ('.implode(',', $listIds).')';
913 + }
883 914
915 + $lists = acym_loadObjectList($query);
916 + if (empty($lists)) {
917 + return true;
918 + }
919 +
884 920 foreach ($lists as $list) {
885 921 $list->{$column} = null;
886 922
887 - if (!$this->save($list)) return false;
923 + $savedListId = $this->save($list);
924 + if (empty($savedListId)) {
925 + return false;
926 + }
888 927 }
889 928
890 929 return true;
891 930 }
892 931
893 - public function getListIdsByWelcomeUnsub($mailId, $welcome = true)
932 + public function getListIdsByWelcomeUnsub(int $mailId, bool $welcome = true): array
894 933 {
895 934 $type = $welcome ? 'welcome_id' : 'unsubscribe_id';
896 935
897 936 $return = acym_loadResultArray('SELECT id FROM #__acym_list WHERE '.$type.' = '.intval($mailId));
@@ -898,21 +937,10 @@
898 937
899 938 return empty($return) ? [] : $return;
900 939 }
901 940
902 - public function getAll($key = null, $needTranslation = false)
941 + public function getUsersForSummaryModal(int $id, int $offset, int $limit, string $search): array
903 942 {
904 - $lists = parent::getAll($key);
905 -
906 - if ($needTranslation && acym_isMultilingual()) {
907 - $lists = $this->getTranslatedNameDescription($lists);
908 - }
909 -
910 - return $lists;
911 - }
912 -
913 - public function getUsersForSummaryModal($id, $offset, $limit, $search)
914 - {
915 943 $whereQuery = ' AND user_list.status = 1 AND user.active = 1';
916 944
917 945 if (!empty($search)) {
918 946 $search = acym_escapeDB('%'.$search.'%');
@@ -931,9 +959,9 @@
931 959
932 960 return acym_loadObjectList($query, 'id');
933 961 }
934 962
935 - public function getXLists(array $options = [])
963 + public function getXLists(array $options = []): array
936 964 {
937 965 $limit = $options['limit'] ?? 10;
938 966 $offset = $options['offset'] ?? 0;
939 967 $filters = $options['filters'] ?? ['type' => self::LIST_TYPE_STANDARD];
@@ -961,6 +989,78 @@
961 989 $query .= ' WHERE '.implode(' AND ', $conditions);
962 990 }
963 991
964 992 return acym_loadObjectList($query, $this->pkey, $offset, $limit);
993 + }
994 +
995 + public function getOneList(): bool
996 + {
997 + $firstList = acym_loadObject('SELECT * FROM #__acym_list WHERE `id` != 1');
998 +
999 + return !empty($firstList);
1000 + }
1001 +
1002 + public function getMostUsedLists(): array
1003 + {
1004 + return acym_loadObjectList(
1005 + 'SELECT list_id
1006 + FROM #__acym_mail_has_list
1007 + GROUP BY list_id
1008 + ORDER BY COUNT(*) DESC
1009 + LIMIT 5'
1010 + );
1011 + }
1012 +
1013 + public function getListsSubscribersAndUnsubscribeUsersFromUserHasList(): array
1014 + {
1015 + $query = 'SELECT list_id,
1016 + SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS subscribers,
1017 + SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS unsubscribed_users
1018 + FROM `#__acym_user_has_list`
1019 + GROUP BY list_id';
1020 +
1021 + return acym_loadObjectList($query);
1022 + }
1023 +
1024 + public function updateListsSubscribersAndUnsubscribeUsers(int $listId, int $subscribers, int $unsubscribeUsers, int $new_sub, int $new_unsub): void
1025 + {
1026 + acym_query(
1027 + 'UPDATE `#__acym_list`
1028 + SET `subscribers` = '.$subscribers.', `unsubscribed_users` = '.$unsubscribeUsers.', `new_sub` = '.$new_sub.', `new_unsub` = '.$new_unsub.'
1029 + WHERE id = '.$listId
1030 + );
1031 + }
1032 +
1033 + public function getMostUsedListsByIdsWithSubscribersData(array $ids = []): array
1034 + {
1035 + if (empty($ids)) {
1036 + return [];
1037 + }
1038 + acym_arrayToInteger($ids);
1039 + $query = 'SELECT name, subscribers, unsubscribed_users, new_sub, new_unsub FROM `#__acym_list` WHERE id IN ('.implode(', ', $ids).')';
1040 +
1041 + return acym_loadObjectList($query);
1042 + }
1043 +
1044 + public function getUserListEntries(array $userIds, array $listIds): array
1045 + {
1046 + if (empty($userIds) || empty($listIds)) {
1047 + return [];
1048 + }
1049 +
1050 + $userIdsStr = implode(',', array_map('intval', $userIds));
1051 + $listIdsStr = implode(',', array_map('intval', $listIds));
1052 +
1053 + $query = 'SELECT * FROM `#__acym_user_has_list`
1054 + WHERE user_id IN ('.$userIdsStr.') AND list_id IN ('.$listIdsStr.')';
1055 +
1056 + $results = acym_loadObjectList($query);
1057 +
1058 + $entries = [];
1059 + foreach ($results as $row) {
1060 + $key = $row->user_id.'_'.$row->list_id;
1061 + $entries[$key] = $row;
1062 + }
1063 +
1064 + return $entries;
965 1065 }
966 1066 }