PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.10.2
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.10.2
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / back / Classes / ListClass.php

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

1,018 lines 34.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace AcyMailing\Classes;
4
5 use AcyMailing\Helpers\MailerHelper;
6 use AcyMailing\Helpers\PaginationHelper;
7 use AcyMailing\Core\AcymClass;
8
9 class ListClass extends AcymClass
10 {
11 const LIST_TYPE_STANDARD = 'standard';
12 const LIST_TYPE_FRONT = 'front';
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'];
15
16 public function __construct()
17 {
18 parent::__construct();
19
20 $this->table = 'list';
21 $this->pkey = 'id';
22 }
23
24 public function getMatchingElements(array $settings = []): array
25 {
26 $columns = 'list.*';
27 if (!empty($settings['columns'])) {
28 foreach ($settings['columns'] as $key => $value) {
29 if ($value == 'lists.list_id') {
30 unset($settings['columns'][$key]);
31 continue;
32 }
33 $settings['columns'][$key] = $key === 'join' ? $value : 'list.'.$value;
34 }
35 $columns = implode(', ', $settings['columns']);
36 }
37
38 $query = 'SELECT '.$columns.' FROM #__acym_list AS list';
39 $queryCount = 'SELECT COUNT(list.id) AS total FROM #__acym_list AS list';
40 if (!empty($settings['join'])) $query .= $this->getJoinForQuery($settings['join']);
41 $queryStatus = 'SELECT COUNT(id) AS number, active + (visible*2) AS score FROM #__acym_list AS list';
42 $filters = [];
43 $listsId = [];
44
45 if (!empty($settings['tag'])) {
46 $tagJoin = ' JOIN #__acym_tag AS tag ON list.id = tag.id_element';
47 $query .= $tagJoin;
48 $queryCount .= $tagJoin;
49 $queryStatus .= $tagJoin;
50 $filters[] = 'tag.name = '.acym_escapeDB($settings['tag']);
51 $filters[] = 'tag.type = "list"';
52 }
53
54 if (!empty($settings['search'])) {
55 $filters[] = 'list.name LIKE '.acym_escapeDB('%'.$settings['search'].'%');
56 }
57
58 if (!empty($settings['creator_id']) && !acym_isAdmin()) {
59 $userGroups = acym_getGroupsByUser($settings['creator_id']);
60 $groupCondition = '(list.access LIKE "%,'.implode(',%" OR list.access LIKE "%,', $userGroups).',%")';
61
62 $filters[] = 'list.cms_user_id = '.intval($settings['creator_id']).' OR '.$groupCondition.'';
63 }
64
65 $filters[] = 'list.type = '.acym_escapeDB(self::LIST_TYPE_STANDARD);
66
67 if (!empty($filters)) {
68 $queryStatus .= ' WHERE ('.implode(') AND (', $filters).')';
69 }
70
71 if (!empty($settings['status'])) {
72 $allowedStatus = [
73 'active' => 'active = 1',
74 'inactive' => 'active = 0',
75 'visible' => 'visible = 1',
76 'invisible' => 'visible = 0',
77 ];
78 if (empty($allowedStatus[$settings['status']])) {
79 die('Injection denied');
80 }
81 $filters[] = 'list.'.$allowedStatus[$settings['status']];
82 }
83
84 if (!empty($settings['where'])) {
85 $filters[] = $settings['where'];
86 }
87
88
89 if (!empty($filters)) {
90 $query .= ' WHERE ('.implode(') AND (', $filters).')';
91 $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
92 }
93
94 if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) {
95 $query .= ' ORDER BY list.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn(strtoupper($settings['ordering_sort_order']));
96 }
97
98 if (empty($settings['offset']) || $settings['offset'] < 0) {
99 $settings['offset'] = 0;
100 }
101
102 if (empty($settings['elementsPerPage']) || $settings['elementsPerPage'] < 1) {
103 $pagination = new PaginationHelper();
104 $settings['elementsPerPage'] = $pagination->getListLimit();
105 }
106
107 $results['elements'] = acym_loadObjectList($query, '', $settings['offset'], $settings['elementsPerPage']);
108 if (!empty($settings['join'])) {
109 $this->setSelectedList($results['elements'], $settings['join']);
110 }
111 foreach ($results['elements'] as $i => $oneList) {
112 $listsId[] = $oneList->id;
113 $results['elements'][$i]->sendable_users = 0;
114 $results['elements'][$i]->unconfirmed_users = 0;
115 $results['elements'][$i]->unsubscribed_users = 0;
116 $results['elements'][$i]->inactive_users = 0;
117 $results['elements'][$i]->newSub = 0;
118 $results['elements'][$i]->newUnsub = 0;
119 }
120
121 $countUserByList = [];
122 $countEvolByList = [];
123 if (!empty($listsId) && empty($settings['entitySelect'])) {
124 $countUserByList = $this->getSubscribersCountPerStatusByListIds($listsId);
125 $countEvolByList = $this->getSubscribersEvolutionByListIds($listsId);
126 }
127
128 foreach ($results['elements'] as $i => $list) {
129 $results['elements'][$i]->tags = [];
130 foreach ($countUserByList as $userList) {
131 if ($list->id == $userList->list_id) {
132 $results['elements'][$i]->sendable_users = $userList->sendable_users;
133 $results['elements'][$i]->unconfirmed_users = $userList->unconfirmed_users;
134 $results['elements'][$i]->unsubscribed_users = $userList->unsubscribed_users;
135 $results['elements'][$i]->inactive_users = $userList->inactive_users;
136 }
137 }
138 if (isset($countEvolByList[$list->id]->newSub)) $results['elements'][$i]->newSub = $countEvolByList[$list->id]->newSub;
139 if (isset($countEvolByList[$list->id]->newUnsub)) $results['elements'][$i]->newUnsub = $countEvolByList[$list->id]->newUnsub;
140 }
141
142 $results['total'] = acym_loadObject($queryCount);
143
144 $listsPerStatus = acym_loadObjectList($queryStatus.' GROUP BY score', 'score');
145 for ($i = 0; $i < 4; $i++) {
146 $listsPerStatus[$i] = empty($listsPerStatus[$i]) ? 0 : $listsPerStatus[$i]->number;
147 }
148
149 $results['status'] = [
150 'all' => array_sum($listsPerStatus),
151 'active' => $listsPerStatus[1] + $listsPerStatus[3],
152 'inactive' => $listsPerStatus[0] + $listsPerStatus[2],
153 'visible' => $listsPerStatus[2] + $listsPerStatus[3],
154 'invisible' => $listsPerStatus[0] + $listsPerStatus[1],
155 ];
156
157 return $results;
158 }
159
160 public function getOneById(int $id): ?object
161 {
162 $list = parent::getOneById($id);
163
164 if (!empty($list)) {
165 $list->translation = empty($list->translation) ? [] : json_decode($list->translation, true);
166 }
167
168 return $list;
169 }
170
171 private function setSelectedList(array $elements, string $join): void
172 {
173 if (strpos($join, 'join_list') === false) {
174 return;
175 }
176
177 $listsIds = explode('-', $join);
178 $listsIds = $listsIds[1];
179 $listsIds = explode(',', $listsIds);
180 foreach ($elements as $element) {
181 $element->list_id = in_array($element->id, $listsIds) ? $element->id : null;
182 }
183 }
184
185 private function getJoinForQuery(string $joinType): string
186 {
187 if (strpos($joinType, 'join_mail') !== false) {
188 $mailId = explode('-', $joinType);
189
190 return ' LEFT JOIN #__acym_mail_has_list as maillist ON list.id = maillist.list_id AND maillist.mail_id = '.intval($mailId[1]);
191 }
192 if (strpos($joinType, 'join_user') !== false) {
193 $userId = explode('-', $joinType);
194
195 return ' LEFT JOIN #__acym_user_has_list as userlist ON list.id = userlist.list_id AND userlist.status = 1 AND userlist.user_id = '.intval($userId[1]);
196 }
197
198 return '';
199 }
200
201 public function getListsWithIdNameCount(array $settings): array
202 {
203 $filters = [];
204
205 if (isset($settings['ids'])) {
206 if (empty($settings['ids'])) {
207 return ['lists' => [], 'total' => 0];
208 } else {
209 acym_arrayToInteger($settings['ids']);
210 $filters[] = 'list.id IN ('.implode(',', $settings['ids']).')';
211 }
212 }
213
214 $query = 'SELECT list.id, list.name, list.color, list.active, COUNT(user.id) AS subscribers
215 FROM #__acym_list AS list
216 LEFT JOIN #__acym_user_has_list AS userList
217 ON list.id = userList.list_id
218 AND userList.status = 1
219 LEFT JOIN #__acym_user AS user
220 ON user.id = userList.user_id
221 AND user.active = 1 ';
222
223 if (intval($this->config->get('require_confirmation', 1)) === 1) {
224 $query .= ' AND user.confirmed = 1 ';
225 }
226
227 $queryCount = 'SELECT COUNT(list.id) FROM #__acym_list AS list';
228
229 if (!acym_isAdmin()) {
230 $currentUserId = acym_currentUserId();
231 if (empty($currentUserId)) {
232 return [
233 'lists' => [],
234 'total' => 0,
235 ];
236 }
237
238 $userGroups = acym_getGroupsByUser($currentUserId);
239 $groupCondition = '(list.access LIKE "%,'.implode(',%" OR list.access LIKE "%,', $userGroups).',%")';
240
241 $filters[] = 'list.cms_user_id = '.intval($currentUserId).' OR '.$groupCondition;
242 }
243
244 if (!empty($settings['search'])) {
245 $filters[] = 'list.name LIKE '.acym_escapeDB('%'.$settings['search'].'%');
246 }
247
248 if (!empty($settings['already'])) {
249 acym_arrayToInteger($settings['already']);
250 $filters[] = 'list.id NOT IN('.implode(',', $settings['already']).')';
251 }
252 $filters[] = 'list.type = '.acym_escapeDB(self::LIST_TYPE_STANDARD);
253
254 if (!empty($filters)) {
255 $query .= ' WHERE ('.implode(') AND (', $filters).')';
256 $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
257 }
258
259 $query .= ' GROUP BY list.id ';
260
261 return [
262 'lists' => acym_loadObjectList($query, '', $settings['offset'], $settings['listsPerPage']),
263 'total' => (int)acym_loadResult($queryCount),
264 ];
265 }
266
267 public function getListsByIds(array $ids): array
268 {
269 acym_arrayToInteger($ids);
270 if (empty($ids)) {
271 return [];
272 }
273
274 $query = 'SELECT * FROM #__acym_list WHERE id IN ('.implode(', ', $ids).')';
275
276 return acym_loadObjectList($query);
277 }
278
279 public function getSubscribersCount(array $listsIds): int
280 {
281 acym_arrayToInteger($listsIds);
282 if (empty($listsIds)) {
283 return 0;
284 }
285
286 $query = 'SELECT COUNT(DISTINCT user.id)
287 FROM #__acym_user AS user
288 JOIN #__acym_user_has_list AS userList ON user.id = userList.user_id
289 WHERE userList.list_id IN ('.implode(",", $listsIds).') AND userList.status = 1 AND user.active = 1';
290
291 if ($this->config->get('require_confirmation', 1) == 1) {
292 $query .= ' AND user.confirmed = 1';
293 }
294
295 return (int)acym_loadResult($query);
296 }
297
298 public function getSubscribersForList(array $options = []): array
299 {
300 $listIds = $options['listIds'] ?? [];
301 $offset = $options['offset'] ?? 0;
302 $limit = $options['limit'] ?? 100;
303 $status = $options['status'] ?? null;
304 $orderBy = $options['orderBy'] ?? '';
305 $orderBySort = $options['orderBySort'] ?? '';
306 $subscribedAfter = $options['subscribed_after'] ?? null;
307 $unsubscribedAfter = $options['unsubscribed_after'] ?? null;
308
309 if (empty($listIds)) {
310 return [];
311 }
312
313 acym_arrayToInteger($listIds);
314
315 $statusCondition = '';
316 if (!is_null($status)) {
317 $statusCondition .= ' AND user_list.status = '.intval($status);
318 }
319
320 if (!empty($subscribedAfter)) {
321 $statusCondition .= ' AND user_list.subscription_date > '.acym_escapeDB($subscribedAfter);
322 }
323
324 if (!empty($unsubscribedAfter)) {
325 $statusCondition .= ' AND user_list.unsubscribe_date > '.acym_escapeDB($unsubscribedAfter);
326 }
327
328 $requestSub = 'SELECT user.*, user_list.status, user_list.subscription_date, user_list.unsubscribe_date FROM #__acym_user AS user';
329 $requestSub .= ' LEFT JOIN #__acym_user_has_list AS user_list ON user.id = user_list.user_id';
330 $requestSub .= ' WHERE user.active = 1 AND user_list.list_id IN ('.implode(', ', $listIds).')'.$statusCondition;
331
332 if (!empty($orderBy)) {
333 if (empty($orderBySort)) $orderBySort = 'desc';
334 $requestSub .= ' ORDER BY '.acym_secureDBColumn($orderBy).' '.acym_secureDBColumn($orderBySort);
335 }
336
337 return acym_loadObjectList(
338 $requestSub,
339 '',
340 $offset,
341 $limit
342 );
343 }
344
345 public function delete(array $elements, bool $force = false): int
346 {
347 if (!$force) {
348 $this->onlyManageableLists($elements);
349 }
350
351 if (empty($elements)) {
352 return 0;
353 }
354
355 foreach ($elements as $id) {
356 acym_query('DELETE FROM #__acym_mail_has_list WHERE list_id = '.intval($id));
357 acym_query('DELETE FROM #__acym_user_has_list WHERE list_id = '.intval($id));
358 acym_query('DELETE FROM #__acym_tag WHERE `id_element` = '.intval($id).' AND `type` = "list"');
359 }
360
361 return parent::delete($elements);
362 }
363
364 public function synchDeleteCmsList(int $userId): void
365 {
366 $query = 'SELECT * FROM #__acym_list WHERE type = "'.self::LIST_TYPE_FRONT.'" AND cms_user_id = '.intval($userId);
367 $listFrontManagement = acym_loadObject($query);
368 if (!empty($listFrontManagement)) {
369 $this->delete([$listFrontManagement->id]);
370 }
371 }
372
373 public function save(object $list): ?int
374 {
375 if (isset($list->tags)) {
376 $tags = $list->tags;
377 unset($list->tags);
378 }
379
380 $oldList = null;
381
382 if (empty($list->id)) {
383 if (empty($list->cms_user_id)) {
384 $list->cms_user_id = acym_currentUserId();
385 }
386
387 $list->creation_date = acym_date('now', 'Y-m-d H:i:s', false);
388 } else {
389 $oldList = $this->getOneById($list->id);
390 }
391
392 if (!empty($list->translation)) {
393 if (is_array($list->translation)) $list->translation = json_encode($list->translation);
394 } else {
395 $list->translation = '';
396 }
397
398 foreach ($list as $oneAttribute => $value) {
399 if (empty($value)) continue;
400
401 $list->$oneAttribute = strip_tags($value);
402 }
403
404 if (empty($list->description)) {
405 $list->description = '';
406 }
407
408 if (!isset($list->access) && empty($list->id)) {
409 $list->access = '';
410 }
411
412 if (empty($list->id)) {
413 acym_trigger('onAcymBeforeListCreate', [&$list]);
414 } else {
415 acym_trigger('onAcymBeforeListModify', [&$list]);
416 }
417
418 $listID = parent::save($list);
419
420 if (empty($listID)) {
421 return null;
422 }
423
424 if (isset($tags)) {
425 $tagClass = new TagClass();
426 $tagClass->setTags(TagClass::TYPE_LIST, intval($listID), $tags);
427 }
428
429 $list->id = $listID;
430
431 if (is_null($oldList)) {
432 acym_trigger('onAcymAfterListCreate', [&$list]);
433 } else {
434 acym_trigger('onAcymAfterListModify', [&$list, &$oldList]);
435 }
436
437 return $listID;
438 }
439
440 public function getAllWithIdName(): array
441 {
442 $endQuery = '';
443 if (!acym_isAdmin()) {
444 $creatorId = acym_currentUserId();
445
446 $userGroups = acym_getGroupsByUser($creatorId);
447 $groupCondition = '(access LIKE "%,'.implode(',%" OR access LIKE "%,', $userGroups).',%")';
448
449 $endQuery = ' AND (cms_user_id = '.intval($creatorId).' OR '.$groupCondition.')';
450 }
451 $lists = acym_loadObjectList('SELECT id, name FROM #__acym_list WHERE type = '.acym_escapeDB(self::LIST_TYPE_STANDARD).$endQuery, 'id');
452
453 $listsToReturn = [];
454
455 foreach ($lists as $key => $list) {
456 $listsToReturn[$key] = $list->name;
457 }
458
459 return $listsToReturn;
460 }
461
462 public function getAllForSelect(bool $emptyFirst = true, int $userFrontID = 0, bool $needTranslation = false, bool $needFrontLabel = false): array
463 {
464 $groupCondition = '';
465 if (!empty($userFrontID)) {
466 $userGroups = acym_getGroupsByUser($userFrontID);
467 $groupCondition = ' AND (cms_user_id = '.intval($userFrontID).' OR (access LIKE "%,'.implode(',%" OR access LIKE "%,', $userGroups).',%"))';
468 }
469
470 $lists = acym_loadObjectList('SELECT * FROM #__acym_list WHERE type = '.acym_escapeDB(self::LIST_TYPE_STANDARD).$groupCondition, 'id');
471
472 if (acym_isMultilingual() && $needTranslation) {
473 $lists = $this->getTranslatedNameDescription($lists);
474 }
475
476 $return = [];
477
478 if ($emptyFirst) {
479 $return[''] = acym_translation('ACYM_SELECT_A_LIST');
480 }
481
482 foreach ($lists as $key => $list) {
483 $return[$key] = $needFrontLabel && !empty($list->display_name) ? $list->display_name : $list->name;
484 }
485
486 return $return;
487 }
488
489 public function getAllWithoutManagement(bool $needTranslation = false): array
490 {
491 $lists = acym_loadObjectList('SELECT * FROM #__acym_list WHERE `type` = '.acym_escapeDB(self::LIST_TYPE_STANDARD), 'id');
492
493 if (acym_isMultilingual() && $needTranslation) {
494 $lists = $this->getTranslatedNameDescription($lists);
495 }
496
497 return $lists;
498 }
499
500 public function getTranslatedNameDescription(array $lists): array
501 {
502 $currentLanguageTag = acym_getLanguageTag();
503 foreach ($lists as $id => $list) {
504 if (empty($list->translation)) continue;
505
506 $list->translation = json_decode($list->translation, true);
507 if (!empty($list->translation[$currentLanguageTag])) {
508 if (!empty($list->translation[$currentLanguageTag]['name'])) {
509 $list->name = $list->translation[$currentLanguageTag]['name'];
510 }
511
512 if (!empty($list->translation[$currentLanguageTag]['display_name'])) {
513 $list->display_name = $list->translation[$currentLanguageTag]['display_name'];
514 }
515
516 if (!empty($list->translation[$currentLanguageTag]['description'])) {
517 $list->description = $list->translation[$currentLanguageTag]['description'];
518 }
519 }
520 }
521
522 return $lists;
523 }
524
525 public function sendWelcome(int $userID, array $listIDs, bool $forceFront = false): void
526 {
527 if (!$forceFront && acym_isAdmin()) {
528 return;
529 }
530
531 acym_arrayToInteger($listIDs);
532 if (empty($listIDs)) {
533 return;
534 }
535
536 $messages = acym_loadObjectList('SELECT `welcome_id` FROM #__acym_list WHERE `id` IN ('.implode(',', $listIDs).') AND `active` = 1');
537
538 if (empty($messages)) {
539 return;
540 }
541
542 $alreadySent = [];
543 $mailerHelper = new MailerHelper();
544 $mailerHelper->report = (bool)$this->config->get('welcome_message', 1);
545 foreach ($messages as $oneMessage) {
546 $mailid = $oneMessage->welcome_id;
547 if (empty($mailid)) continue;
548
549 if (isset($alreadySent[$mailid])) {
550 continue;
551 }
552
553 $mailerHelper->trackEmail = true;
554 $mailerHelper->sendOne($mailid, $userID);
555 $alreadySent[$mailid] = true;
556 }
557 }
558
559 public function sendUnsubscribe(int $userID, array $listIDs): void
560 {
561 if (acym_isAdmin()) {
562 return;
563 }
564
565 acym_arrayToInteger($listIDs);
566 if (empty($listIDs)) {
567 return;
568 }
569
570 $messages = acym_loadObjectList('SELECT `unsubscribe_id` FROM #__acym_list WHERE `id` IN ('.implode(',', $listIDs).') AND `active` = 1');
571
572 if (empty($messages)) {
573 return;
574 }
575
576 $alreadySent = [];
577 $mailerHelper = new MailerHelper();
578 $mailerHelper->report = (bool)$this->config->get('unsub_message', 1);
579 foreach ($messages as $oneMessage) {
580 if (!empty($oneMessage->unsubscribe_id)) {
581 $mailid = $oneMessage->unsubscribe_id;
582
583 if (isset($alreadySent[$mailid])) {
584 continue;
585 }
586
587 $mailerHelper->trackEmail = true;
588 $mailerHelper->sendOne($mailid, $userID);
589 $alreadySent[$mailid] = true;
590 }
591 }
592 }
593
594 public function addDefaultList()
595 {
596 $listId = acym_loadResult('SELECT `id` FROM #__acym_list LIMIT 1');
597 if (empty($listId)) {
598 $defaultList = new \stdClass();
599 $defaultList->name = 'Newsletters';
600 $defaultList->color = '#3366ff';
601 $defaultList->description = '';
602
603 $this->save($defaultList);
604 }
605 }
606
607 public function getTotalSubCount(array $ids): int
608 {
609 if (empty($ids)) {
610 return 0;
611 }
612
613 acym_arrayToInteger($ids);
614 $this->onlyManageableLists($ids);
615 $query = 'SELECT COUNT(DISTINCT hasList.user_id)
616 FROM #__acym_user_has_list AS hasList
617 JOIN #__acym_user AS user
618 ON hasList.user_id = user.id
619 WHERE hasList.status = 1
620 AND user.active = 1
621 AND hasList.list_id IN ('.implode(',', $ids).')';
622
623
624 if ($this->config->get('require_confirmation', 1) == 1) {
625 $query .= ' AND user.confirmed = 1 ';
626 }
627
628 return intval(acym_loadResult($query));
629 }
630
631 public function getMailsByListId(int $listId): array
632 {
633 $mailIds = acym_loadResultArray('SELECT mail_id FROM #__acym_mail_has_list WHERE list_id = '.intval($listId));
634
635 return empty($mailIds) ? [] : $mailIds;
636 }
637
638 public function getSubscribersCountPerStatusByListIds(array $listIds = []): array
639 {
640 $condList = '';
641 if (!empty($listIds)) {
642 acym_arrayToInteger($listIds);
643 $condList = 'AND userList.list_id IN ('.implode(',', $listIds).')';
644 }
645
646 $query = 'SELECT userList.list_id, COUNT(userList.user_id) AS users, acyuser.confirmed + acyuser.active*2 AS score
647 FROM #__acym_user_has_list AS userList
648 JOIN #__acym_user AS acyuser
649 ON acyuser.id = userList.user_id
650 WHERE userList.status = 1
651 '.$condList.'
652 GROUP BY score, userList.list_id';
653 $results = acym_loadObjectList($query);
654
655 $confirmationRequired = $this->config->get('require_confirmation', 1);
656 $listsUserStats = [];
657 foreach ($results as $oneResult) {
658 if (!isset($listsUserStats[$oneResult->list_id])) {
659 $listsUserStats[$oneResult->list_id] = $this->initList($oneResult->list_id);
660 }
661
662 $oneResult->score = (string)$oneResult->score;
663
664 if (in_array($oneResult->score, ['0', '1'])) {
665 $listsUserStats[$oneResult->list_id]->inactive_users += $oneResult->users;
666 }
667
668 if (in_array($oneResult->score, ['0', '2'])) {
669 $listsUserStats[$oneResult->list_id]->unconfirmed_users += $oneResult->users;
670 }
671
672 if ($oneResult->score === '3' || ($confirmationRequired != 1 && $oneResult->score == '2')) {
673 $listsUserStats[$oneResult->list_id]->sendable_users += $oneResult->users;
674 }
675 }
676
677 $query = 'SELECT userList.list_id, COUNT(userList.user_id) AS users
678 FROM #__acym_user_has_list AS userList
679 WHERE userList.status = 0
680 '.$condList.'
681 GROUP BY userList.list_id';
682 $unsubscribed = acym_loadObjectList($query);
683
684 foreach ($unsubscribed as $oneList) {
685 if (!isset($listsUserStats[$oneList->list_id])) {
686 $listsUserStats[$oneList->list_id] = $this->initList($oneList->list_id);
687 }
688 $listsUserStats[$oneList->list_id]->unsubscribed_users = $oneList->users;
689 }
690
691 return $listsUserStats;
692 }
693
694 public function getSubscribersEvolutionByListIds(array $listIds): array
695 {
696 $condList = '';
697 if (!empty($listIds)) {
698 acym_arrayToInteger($listIds);
699 $condList = ' AND list_id IN ('.implode(',', $listIds).')';
700 }
701 $dateNow = acym_loadResult('SELECT DATE_SUB(NOW(), INTERVAL 1 MONTH)');
702 $queryEvolSub = 'SELECT list_id, COUNT(*) AS newSub FROM #__acym_user_has_list';
703 $queryEvolSub .= ' WHERE subscription_date > '.acym_escapeDB($dateNow).' '.$condList;
704 $queryEvolSub .= ' GROUP BY list_id';
705 $evolSubscibers = acym_loadObjectList($queryEvolSub, 'list_id');
706
707 $queryEvolUnsub = 'SELECT list_id, COUNT(*) AS newUnsub FROM #__acym_user_has_list';
708 $queryEvolUnsub .= ' WHERE unsubscribe_date > '.acym_escapeDB($dateNow).' '.$condList;
709 $queryEvolUnsub .= ' GROUP BY list_id';
710 $newUnsubscribers = acym_loadObjectList($queryEvolUnsub, 'list_id');
711
712 foreach ($newUnsubscribers as $listId => $oneUnsub) {
713 if (empty($evolSubscibers[$listId])) {
714 $evolSubscibers[$listId] = new \stdClass();
715 }
716 $evolSubscibers[$listId]->newUnsub = $oneUnsub->newUnsub;
717 }
718
719 return $evolSubscibers;
720 }
721
722 public function getYearSubEvolutionPerList(int $listId): array
723 {
724 $month = date('n') + 1;
725 $year = date('Y') - 1;
726 $initDate = $year.'-'.$month.'-01';
727 if ($month == 13) {
728 $initDate = date('Y').'-01-01';
729 }
730
731 $queryEvolSub = 'SELECT MONTH(subscription_date) as monthSub, DATE_FORMAT(subscription_date,"%Y_%m") AS unit, COUNT(user_id) AS nbUser';
732 $queryEvolSub .= ' FROM `#__acym_user_has_list`';
733 $queryEvolSub .= ' WHERE subscription_date >= "'.$initDate.'" AND list_id = '.$listId;
734 $queryEvolSub .= ' GROUP BY unit';
735 $evolSubscibers = acym_loadObjectList($queryEvolSub, 'unit');
736
737 $queryEvolUnsub = 'SELECT MONTH(unsubscribe_date) as monthUnsub, DATE_FORMAT(unsubscribe_date,"%Y_%m") AS unit, COUNT(user_id) AS nbUser';
738 $queryEvolUnsub .= ' FROM `#__acym_user_has_list`';
739 $queryEvolUnsub .= ' WHERE unsubscribe_date >= "'.$initDate.'" AND list_id = '.$listId;
740 $queryEvolUnsub .= ' GROUP BY unit';
741 $evolUnsubscibers = acym_loadObjectList($queryEvolUnsub, 'unit');
742
743 return [
744 'subscribers' => $evolSubscibers,
745 'unsubscribers' => $evolUnsubscibers,
746 ];
747 }
748
749 private function initList(int $listId): object
750 {
751 $list = new \stdClass();
752 $list->list_id = $listId;
753 $list->sendable_users = 0;
754 $list->unconfirmed_users = 0;
755 $list->inactive_users = 0;
756 $list->unsubscribed_users = 0;
757
758 return $list;
759 }
760
761 public function getManageableLists(): array
762 {
763 $idCurrentUser = acym_currentUserId();
764 if (empty($idCurrentUser)) {
765 return [];
766 }
767
768 $userGroups = acym_getGroupsByUser($idCurrentUser);
769
770 return acym_loadResultArray(
771 'SELECT id
772 FROM #__acym_list
773 WHERE cms_user_id = '.intval($idCurrentUser).'
774 OR (access LIKE "%,'.implode(',%" OR access LIKE "%,', $userGroups).',%")'
775 );
776 }
777
778 public function onlyManageableLists(&$elements): void
779 {
780 if (acym_isAdmin()) {
781 return;
782 }
783
784 $manageableLists = $this->getManageableLists();
785 $elements = array_intersect($elements, $manageableLists);
786 }
787
788 public function hasUserAccess(int $listId): bool
789 {
790 if (acym_isAdmin()) {
791 return true;
792 }
793
794 return in_array($listId, $this->getManageableLists());
795 }
796
797 public function getfrontManagementList(): int
798 {
799 $idCurrentUser = acym_currentUserId();
800 if (empty($idCurrentUser)) {
801 return 0;
802 }
803
804 $frontListId = acym_loadResult('SELECT id FROM #__acym_list WHERE type = '.acym_escapeDB(self::LIST_TYPE_FRONT).' AND cms_user_id = '.intval($idCurrentUser));
805
806 if (!empty($frontListId)) {
807 return $frontListId;
808 }
809
810 $frontList = new \stdClass();
811 $frontList->name = 'frontlist_'.$idCurrentUser;
812 $frontList->active = 1;
813 $frontList->visible = 0;
814 $frontList->cms_user_id = $idCurrentUser;
815 $frontList->type = self::LIST_TYPE_FRONT;
816
817 return (int)$this->save($frontList);
818 }
819
820 public function setWelcomeUnsubEmail(array $listIds, int $mailId, string $type): bool
821 {
822 if (!in_array($type, [MailClass::TYPE_WELCOME, MailClass::TYPE_UNSUBSCRIBE]) || empty($mailId)) {
823 return false;
824 }
825
826 $column = acym_escape($type).'_id';
827 $columnsList = acym_getColumns('list');
828 if (!in_array($column, $columnsList)) {
829 return false;
830 }
831
832 if (!$this->removeWelcomeUnsubByMailId($mailId, $listIds, $column)) {
833 return false;
834 }
835
836 foreach ($listIds as $listId) {
837 $list = $this->getOneById($listId);
838 if (empty($list)) {
839 return false;
840 }
841
842 $list->{$column} = $mailId;
843
844 $savedListId = $this->save($list);
845 if (empty($savedListId)) {
846 return false;
847 }
848 }
849
850 return true;
851 }
852
853 private function removeWelcomeUnsubByMailId(int $mailId, array $listIds, string $column): bool
854 {
855 if (empty($mailId)) {
856 return false;
857 }
858
859 $query = 'SELECT * FROM #__acym_list WHERE '.acym_secureDBColumn($column).' = '.$mailId;
860
861 if (!empty($listIds)) {
862 acym_arrayToInteger($listIds);
863 $query .= ' AND `id` NOT IN ('.implode(',', $listIds).')';
864 }
865
866 $lists = acym_loadObjectList($query);
867 if (empty($lists)) {
868 return true;
869 }
870
871 foreach ($lists as $list) {
872 $list->{$column} = null;
873
874 $savedListId = $this->save($list);
875 if (empty($savedListId)) {
876 return false;
877 }
878 }
879
880 return true;
881 }
882
883 public function getListIdsByWelcomeUnsub(int $mailId, bool $welcome = true): array
884 {
885 $type = $welcome ? 'welcome_id' : 'unsubscribe_id';
886
887 $return = acym_loadResultArray('SELECT id FROM #__acym_list WHERE '.$type.' = '.intval($mailId));
888
889 return empty($return) ? [] : $return;
890 }
891
892 public function getUsersForSummaryModal(int $id, int $offset, int $limit, string $search): array
893 {
894 $whereQuery = ' AND user_list.status = 1 AND user.active = 1';
895
896 if (!empty($search)) {
897 $search = acym_escapeDB('%'.$search.'%');
898 $whereQuery .= ' AND (user.email LIKE '.$search.' OR user.name LIKE '.$search.' OR user.id LIKE '.$search.') ';
899 }
900
901 if ($this->config->get('require_confirmation', '1') === '1') {
902 $whereQuery .= ' AND user.confirmed = 1';
903 }
904
905 $query = 'SELECT user.email, user.name, user.id
906 FROM #__acym_user as user
907 JOIN #__acym_user_has_list as user_list ON user.id = user_list.user_id
908 WHERE user_list.list_id = '.intval($id).$whereQuery.' LIMIT '.intval($offset).', '.intval($limit);
909
910
911 return acym_loadObjectList($query, 'id');
912 }
913
914 public function getXLists(array $options = []): array
915 {
916 $limit = $options['limit'] ?? 10;
917 $offset = $options['offset'] ?? 0;
918 $filters = $options['filters'] ?? ['type' => self::LIST_TYPE_STANDARD];
919
920 $conditions = [];
921 foreach ($filters as $column => $filter) {
922 switch ($column) {
923 case 'id':
924 case 'active':
925 case 'visible':
926 case 'clean':
927 case 'welcome_id':
928 case 'unsubscribe_id':
929 case 'cms_user_id':
930 case 'tracking':
931 $conditions[] = acym_secureDBColumn($column).' = '.intval($filter);
932 break;
933 default:
934 $conditions[] = acym_secureDBColumn($column).' LIKE '.acym_escapeDB('%'.$filter.'%');
935 }
936 }
937
938 $query = 'SELECT * FROM #__acym_list';
939 if (!empty($conditions)) {
940 $query .= ' WHERE '.implode(' AND ', $conditions);
941 }
942
943 return acym_loadObjectList($query, $this->pkey, $offset, $limit);
944 }
945
946 public function getOneList(): bool
947 {
948 $firstList = acym_loadObject('SELECT * FROM #__acym_list WHERE `id` != 1');
949
950 return !empty($firstList);
951 }
952
953 public function getMostUsedLists(): array
954 {
955 return acym_loadObjectList(
956 'SELECT list_id
957 FROM #__acym_mail_has_list
958 GROUP BY list_id
959 ORDER BY COUNT(*) DESC
960 LIMIT 5'
961 );
962 }
963
964 public function getListsSubscribersAndUnsubscribeUsersFromUserHasList(): array
965 {
966 $query = 'SELECT list_id,
967 SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS subscribers,
968 SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS unsubscribed_users
969 FROM `#__acym_user_has_list`
970 GROUP BY list_id';
971
972 return acym_loadObjectList($query);
973 }
974
975 public function updateListsSubscribersAndUnsubscribeUsers(int $listId, int $subscribers, int $unsubscribeUsers, int $new_sub, int $new_unsub): void
976 {
977 acym_query(
978 'UPDATE `#__acym_list`
979 SET `subscribers` = '.$subscribers.', `unsubscribed_users` = '.$unsubscribeUsers.', `new_sub` = '.$new_sub.', `new_unsub` = '.$new_unsub.'
980 WHERE id = '.$listId
981 );
982 }
983
984 public function getMostUsedListsByIdsWithSubscribersData(array $ids = []): array
985 {
986 if (empty($ids)) {
987 return [];
988 }
989 acym_arrayToInteger($ids);
990 $query = 'SELECT name, subscribers, unsubscribed_users, new_sub, new_unsub FROM `#__acym_list` WHERE id IN ('.implode(', ', $ids).')';
991
992 return acym_loadObjectList($query);
993 }
994
995 public function getUserListEntries(array $userIds, array $listIds): array
996 {
997 if (empty($userIds) || empty($listIds)) {
998 return [];
999 }
1000
1001 $userIdsStr = implode(',', array_map('intval', $userIds));
1002 $listIdsStr = implode(',', array_map('intval', $listIds));
1003
1004 $query = 'SELECT * FROM `#__acym_user_has_list`
1005 WHERE user_id IN ('.$userIdsStr.') AND list_id IN ('.$listIdsStr.')';
1006
1007 $results = acym_loadObjectList($query);
1008
1009 $entries = [];
1010 foreach ($results as $row) {
1011 $key = $row->user_id.'_'.$row->list_id;
1012 $entries[$key] = $row;
1013 }
1014
1015 return $entries;
1016 }
1017 }
1018