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