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/CampaignClass.php +0 -1300 10.2.2 → 11.1.1 View file →
@@ -1,1300 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Classes;
4 -
5 -use AcyMailing\Controllers\CampaignsController;
6 -use AcyMailing\Controllers\SegmentsController;
7 -use AcyMailing\Helpers\AutomationHelper;
8 -use AcyMailing\Helpers\MailerHelper;
9 -use AcyMailing\Helpers\PaginationHelper;
10 -use AcyMailing\Core\AcymClass;
11 -
12 -class CampaignClass extends AcymClass
13 -{
14 - const SENDING_TYPE_NOW = 'now';
15 - const SENDING_TYPE_SCHEDULED = 'scheduled';
16 - const SENDING_TYPE_AUTO = 'auto';
17 - const SENDING_TYPES = [
18 - self::SENDING_TYPE_NOW,
19 - self::SENDING_TYPE_SCHEDULED,
20 - self::SENDING_TYPE_AUTO,
21 - ];
22 - const AB_TEST_VERSIONS = ['B'];
23 -
24 - private array $jsonColumns = ['sending_params'];
25 -
26 - public function __construct()
27 - {
28 - parent::__construct();
29 -
30 - $this->table = 'campaign';
31 - $this->pkey = 'id';
32 - }
33 -
34 - public function decode($campaign, $decodeMail = true)
35 - {
36 - if (empty($campaign)) return $campaign;
37 -
38 - if (is_array($campaign)) {
39 - foreach ($campaign as $i => $oneCampaign) {
40 - $campaign[$i] = $this->decode($oneCampaign, false);
41 - }
42 - }
43 -
44 - foreach ($this->jsonColumns as $oneColumn) {
45 - if (!isset($campaign->$oneColumn)) continue;
46 -
47 - $campaign->$oneColumn = empty($campaign->$oneColumn) ? [] : json_decode($campaign->$oneColumn, true);
48 - }
49 -
50 - if ($decodeMail) {
51 - $mailClass = new MailClass();
52 - $campaign = $mailClass->decode($campaign);
53 - }
54 -
55 - return $campaign;
56 - }
57 -
58 - public function getAll(?string $key = null): array
59 - {
60 - $allCampaigns = parent::getAll($key);
61 -
62 - return $this->decode($allCampaigns);
63 - }
64 -
65 - public function getMatchingElements(array $settings = []): array
66 - {
67 - $tagClass = new TagClass();
68 - $mailClass = new MailClass();
69 -
70 - $query = 'SELECT campaign.*, mail.name, SUM(mail_stat.sent) AS subscribers, mail_stat.open_unique, mail_stat.tracking_sale, mail_stat.currency FROM #__acym_campaign AS campaign';
71 - $queryCount = 'FROM #__acym_campaign AS campaign';
72 -
73 - $filters = [];
74 - $task = acym_getVar('string', 'task');
75 - if ($task === 'campaigns') {
76 - $filters[] = 'mail.type = '.acym_escapeDB(MailClass::TYPE_STANDARD);
77 - } elseif ($task === 'mailbox_action') {
78 - $filters[] = 'mail.type = '.acym_escapeDB(MailClass::TYPE_MAILBOX_ACTION);
79 - }
80 - $mailIds = [];
81 -
82 - $query .= ' JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id';
83 - $queryCount .= ' JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id';
84 - $query .= ' LEFT JOIN #__acym_mail_stat AS mail_stat ON campaign.mail_id = mail_stat.mail_id';
85 -
86 - if (!acym_isAdmin()) {
87 - $condition = 'mail.creator_id = '.intval(acym_currentUserId());
88 - if ($this->config->get('front_campaigns_filter', 'own') === 'allowed') {
89 - $listClass = new ListClass();
90 - $allowedLists = $listClass->getManageableLists();
91 - if (!empty($allowedLists)) {
92 - $query .= ' LEFT JOIN #__acym_mail_has_list AS mailList ON campaign.mail_id = mailList.mail_id AND mailList.list_id IN ('.implode(',', $allowedLists).')';
93 - $queryCount .= ' LEFT JOIN #__acym_mail_has_list AS mailList ON campaign.mail_id = mailList.mail_id AND mailList.list_id IN ('.implode(',', $allowedLists).')';
94 - $condition .= ' OR mailList.list_id IS NOT NULL';
95 - }
96 - }
97 - $filters[] = $condition;
98 - $filters[] = 'campaign.sending_params NOT LIKE "%abtest%"';
99 - }
100 -
101 - if (!empty($settings['tag'])) {
102 - $tagJoin = ' JOIN #__acym_tag AS tag ON campaign.mail_id = tag.id_element';
103 - $query .= $tagJoin;
104 - $queryCount .= $tagJoin;
105 - $filters[] = 'tag.name = '.acym_escapeDB($settings['tag']);
106 - $filters[] = 'tag.type = '.acym_escapeDB(TagClass::TYPE_MAIL);
107 - }
108 -
109 - if (!empty($settings['search'])) {
110 - $filters[] = 'mail.name LIKE '.acym_escapeDB('%'.acym_utf8Encode($settings['search']).'%');
111 - }
112 -
113 - if ($settings['status'] !== 'generated') {
114 - $operator = $settings['element_tab'] === 'campaigns_auto' ? '=' : '!=';
115 - if ($settings['element_tab'] === 'campaigns_auto') {
116 - $filters[] = 'campaign.sending_type '.$operator.' '.acym_escapeDB(self::SENDING_TYPE_AUTO);
117 - } elseif ($settings['element_tab'] === 'campaigns') {
118 - $filters[] = 'campaign.sending_type IN ('.acym_escapeDB(self::SENDING_TYPE_NOW).', '.acym_escapeDB(self::SENDING_TYPE_SCHEDULED).')';
119 - } elseif (!empty($settings['element_tab'])) {
120 - acym_trigger('onAcymCampaignAddFiltersSpecificListing', [&$filters, $settings['element_tab']]);
121 - }
122 - }
123 -
124 - if (!empty($filters)) {
125 - $query .= ' WHERE ('.implode(') AND (', $filters).')';
126 - $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
127 - }
128 -
129 - $statusRequests = [
130 - 'all' => '(campaign.parent_id IS NULL OR campaign.parent_id = 0)',
131 - 'scheduled' => 'campaign.sending_type = '.acym_escapeDB(self::SENDING_TYPE_SCHEDULED).' AND (campaign.parent_id IS NULL OR campaign.parent_id = 0)',
132 - 'sent' => 'campaign.sent = 1 AND (campaign.parent_id IS NULL OR campaign.parent_id = 0)',
133 - 'draft' => 'campaign.draft = 1 AND (campaign.parent_id IS NULL OR campaign.parent_id = 0)',
134 - ];
135 -
136 - if ($settings['element_tab'] == 'campaigns_auto') {
137 - $statusRequests['generated'] = 'campaign.sending_type = '.acym_escapeDB(self::SENDING_TYPE_NOW).' AND campaign.parent_id > 0';
138 - }
139 -
140 - if (empty($settings['status'])) $settings['status'] = 'all';
141 - if (!empty($statusRequests[$settings['status']])) {
142 - $query .= empty($filters) ? ' WHERE ' : ' AND ';
143 - $query .= $statusRequests[$settings['status']];
144 - }
145 -
146 - $query .= ' GROUP BY campaign.id';
147 -
148 - if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) {
149 - $table = in_array($settings['ordering'], ['name', 'creation_date']) ? 'mail' : 'campaign';
150 - $query .= ' ORDER BY '.$table.'.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn(strtoupper($settings['ordering_sort_order']));
151 - }
152 -
153 - if (empty($settings['offset']) || $settings['offset'] < 0) {
154 - $settings['offset'] = 0;
155 - }
156 -
157 - if (empty($settings['elementsPerPage']) || $settings['elementsPerPage'] < 1) {
158 - $pagination = new PaginationHelper();
159 - $settings['elementsPerPage'] = $pagination->getListLimit();
160 - }
161 -
162 - $results['elements'] = $this->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['elementsPerPage']));
163 -
164 - foreach ($results['elements'] as $oneCampaign) {
165 - $mailIds[] = $oneCampaign->mail_id;
166 - $oneCampaign->tags = '';
167 - }
168 -
169 - $tags = $tagClass->getAllTagsByTypeAndElementIds(TagClass::TYPE_MAIL, $mailIds);
170 - $lists = $mailClass->getAllListsByMailIds($mailIds);
171 -
172 - $isMultilingual = acym_isMultilingual();
173 -
174 - $urlClickClass = new UrlClickClass();
175 - foreach ($results['elements'] as $i => $oneCampaign) {
176 - $results['elements'][$i]->tags = [];
177 - $results['elements'][$i]->lists = [];
178 - $results['elements'][$i]->automation_id = null;
179 -
180 - foreach ($tags as $tag) {
181 - if ($oneCampaign->id == $tag->id_element) {
182 - $results['elements'][$i]->tags[] = $tag;
183 - }
184 - }
185 -
186 - foreach ($lists as $list) {
187 - if ($oneCampaign->mail_id == $list->mail_id) {
188 - array_push($results['elements'][$i]->lists, $list);
189 - }
190 - }
191 -
192 - if ($settings['element_tab'] === 'campaigns_auto' && $settings['status'] !== 'generated') {
193 - $this->getStatsCampaignAuto($results['elements'][$i], $urlClickClass);
194 - } else {
195 - $isAbTest = isset($results['elements'][$i]->sending_params['abtest']);
196 - if ($isMultilingual || $isAbTest) {
197 - $this->prepareStatsCampaign($results['elements'][$i]);
198 - }
199 - $this->getStatsCampaign($results['elements'][$i], $urlClickClass, $isAbTest);
200 - }
201 - }
202 -
203 - if (!empty($settings['advanced_total'])) {
204 - if ($settings['campaign_type'] === 'campaigns') {
205 - $queryCount .= (empty($filters) ? ' WHERE ' : ' AND ').'campaign.parent_id IS NULL';
206 -
207 - $results['total'] = acym_loadObject('SELECT COUNT(campaign.id) AS total, SUM(campaign.sent) AS sent, SUM(campaign.draft) AS draft '.$queryCount);
208 - $results['total']->all = $results['total']->total;
209 - $results['total']->scheduled = acym_loadResult(
210 - 'SELECT COUNT(campaign.id) '.$queryCount.' AND campaign.`sending_type` = '.acym_escapeDB(self::SENDING_TYPE_SCHEDULED)
211 - );
212 - } else {
213 - $results['total'] = acym_loadObject('SELECT COUNT(campaign.id) AS total '.$queryCount);
214 - $results['total']->all = 0;
215 - if (!empty($results['total']->total)) {
216 - $results['total']->all = $results['total']->total;
217 - }
218 -
219 - $results['total']->generated = $this->getNbGeneratedCampaigns();
220 - }
221 -
222 - if (CampaignsController::TASK_TYPE_CAMPAIGN_AUTO === $settings['campaign_type'] && 'generated' === $settings['status']) {
223 - $results['total']->all = $this->getCountCampaignType(self::SENDING_TYPE_AUTO);
224 - }
225 - } else {
226 - $results['total'] = acym_loadObject('SELECT COUNT(campaign.id) AS total '.$queryCount);
227 - }
228 -
229 - return $results;
230 - }
231 -
232 - private function prepareStatsCampaign(&$element)
233 - {
234 - $query = 'SELECT SUM(mailstat.sent) AS subscribers, SUM(mailstat.open_unique) AS open_unique, SUM(mailstat.tracking_sale) AS tracking_sale
235 - FROM #__acym_mail_stat AS mailstat
236 - LEFT JOIN #__acym_mail AS mail ON mail.id = mailstat.mail_id WHERE mail.parent_id = '.intval($element->mail_id);
237 - $stats = acym_loadObject($query);
238 - $element->subscribers += $stats->subscribers;
239 - $element->open_unique += $stats->open_unique;
240 - $element->tracking_sale += $stats->tracking_sale;
241 - }
242 -
243 - public function getStatsCampaign(&$element, $urlClickClass, $isAbTest = false)
244 - {
245 - $element->open = 0;
246 - $element->click = 0;
247 -
248 - if (!empty($element->subscribers)) {
249 - $element->open = number_format($element->open_unique / $element->subscribers * 100, 2);
250 -
251 - $clicksNb = $urlClickClass->getNumberUsersClicked($element->mail_id, $isAbTest);
252 - $element->click = number_format($clicksNb / $element->subscribers * 100, 2);
253 - }
254 - }
255 -
256 - public function getTrackingSales(&$element)
257 - {
258 - $element->sale = 0;
259 - $element->currency = '';
260 -
261 - if (acym_isMultilingual()) {
262 - $trackingSales = acym_loadObject(
263 - 'SELECT SUM(tracking_sale) as sale, currency FROM #__acym_user_stat WHERE mail_id IN (SELECT id FROM #__acym_mail WHERE id = '.intval(
264 - $element->mail_id
265 - ).' OR parent_id = '.intval($element->mail_id).') AND currency IS NOT NULL'
266 - );
267 - } else {
268 - $trackingSales = acym_loadObject(
269 - 'SELECT SUM(tracking_sale) as sale, currency FROM #__acym_user_stat WHERE mail_id = '.intval($element->mail_id).' AND currency IS NOT NULL'
270 - );
271 - }
272 - $this->formatSaleTracking($element, $trackingSales);
273 - }
274 -
275 - private function getStatsCampaignAuto(&$element, $urlClickClass)
276 - {
277 - $generatedMailsStats = acym_loadObjectList(
278 - 'SELECT mail_stat.* FROM #__acym_mail AS mail JOIN #__acym_mail_stat AS mail_stat ON mail.id = mail_stat.mail_id WHERE mail.id IN (SELECT mail_id FROM #__acym_campaign WHERE parent_id = '.intval(
279 - $element->id
280 - ).')'
281 - );
282 - $element->open = 0;
283 - $element->click = 0;
284 - $element->subscribers = 0;
285 - if (empty($generatedMailsStats)) return;
286 -
287 - foreach ($generatedMailsStats as $key => $mailsStat) {
288 - $element->open += $mailsStat->open_unique;
289 - $element->click += $urlClickClass->getNumberUsersClicked($element->id);
290 - $element->subscribers += $mailsStat->sent;
291 - }
292 -
293 - if (!empty($element->subscribers)) {
294 - $element->open = number_format($element->open / $element->subscribers * 100, 2);
295 - $element->click = number_format($element->click / $element->subscribers * 100, 2);
296 - }
297 -
298 - if (!acym_isTrackingSalesActive()) return;
299 -
300 - $trackingSales = acym_loadObject(
301 - 'SELECT SUM(mail_stat.tracking_sale) AS sale, mail_stat.currency
302 - FROM #__acym_mail_stat AS mail_stat
303 - WHERE mail_id IN (SELECT mail_id FROM #__acym_campaign WHERE parent_id = '.intval($element->id).') AND currency IS NOT NULL'
304 - );
305 - $this->formatSaleTracking($element, $trackingSales);
306 - }
307 -
308 - private function formatSaleTracking(&$element, $trackingSales)
309 - {
310 - $element->sale = $trackingSales->sale;
311 - if (empty($element->currency)) $element->currency = '';
312 - acym_trigger('getCurrency', [&$element->currency]);
313 - }
314 -
315 - public function getOneById($id)
316 - {
317 - return $this->decode(acym_loadObject('SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.id = '.intval($id)));
318 - }
319 -
320 - public function getOneByIdWithMail($id)
321 - {
322 - $query = 'SELECT campaign.*, mail.name, mail.subject, mail.body, mail.from_name, mail.from_email, mail.reply_to_name, mail.reply_to_email, mail.bcc, mail.links_language, mail.tracking, mail.translation, mail.bounce_email
323 - FROM #__acym_campaign AS campaign
324 - JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id
325 - WHERE campaign.id = '.intval($id);
326 -
327 - return $this->decode(acym_loadObject($query));
328 - }
329 -
330 - public function get($identifier, $column = 'id')
331 - {
332 - return $this->decode(acym_loadObject('SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.'.acym_secureDBColumn($column).' = '.acym_escapeDB($identifier)));
333 - }
334 -
335 - public function getAllCampaignsNameMailId()
336 - {
337 - $query = 'SELECT m.id, m.name
338 - FROM #__acym_campaign AS c
339 - LEFT JOIN #__acym_mail AS m ON c.mail_id = m.id';
340 -
341 - return $this->decode(acym_loadObjectList($query));
342 - }
343 -
344 - public function getOneCampaignByMailId($mailId)
345 - {
346 - return $this->decode(acym_loadObject('SELECT * FROM #__acym_campaign WHERE mail_id = '.intval($mailId)));
347 - }
348 -
349 - public function getAutoCampaignFromGeneratedMailId($mailId)
350 - {
351 - $queryCampaign = 'SELECT * FROM #__acym_campaign WHERE id = (SELECT parent_id FROM #__acym_campaign WHERE mail_id = '.intval($mailId).')';
352 -
353 - return $this->decode(acym_loadObject($queryCampaign));
354 - }
355 -
356 - public function manageListsToCampaign($listsIds, $mailId, $unselectedListIds = [])
357 - {
358 - if (!empty($unselectedListIds)) {
359 - acym_arrayToInteger($unselectedListIds);
360 - acym_query('DELETE FROM #__acym_mail_has_list WHERE mail_id = '.intval($mailId).' AND list_id IN ('.implode(', ', $unselectedListIds).')');
361 - }
362 -
363 - acym_arrayToInteger($listsIds);
364 - if (empty($listsIds)) return false;
365 -
366 - $values = [];
367 - $listsIds = array_unique($listsIds);
368 - foreach ($listsIds as $listId) {
369 - $values[] = '('.intval($mailId).', '.intval($listId).')';
370 - }
371 -
372 - if (!empty($values)) {
373 - acym_query('INSERT IGNORE INTO #__acym_mail_has_list (`mail_id`, `list_id`) VALUES '.implode(',', $values));
374 - }
375 -
376 - return true;
377 - }
378 -
379 - public function save($campaignToSave)
380 - {
381 - $campaign = clone $campaignToSave;
382 - if (isset($campaign->tags)) {
383 - $tags = $campaign->tags;
384 - unset($campaign->tags);
385 - }
386 -
387 - foreach ($campaign as $oneAttribute => $value) {
388 - if (in_array($oneAttribute, $this->jsonColumns)) {
389 - $campaign->$oneAttribute = json_encode(empty($value) ? [] : $value);
390 - } else {
391 - if (empty($value)) continue;
392 - $campaign->$oneAttribute = strip_tags($value);
393 - }
394 - }
395 -
396 - $campaignID = parent::save($campaign);
397 -
398 - if (!empty($campaignID) && isset($tags)) {
399 - $tagClass = new TagClass();
400 - $tagClass->setTags(TagClass::TYPE_MAIL, intval($campaign->mail_id), $tags);
401 - }
402 -
403 - return $campaignID;
404 - }
405 -
406 - public function onlyManageableCampaigns(&$elements)
407 - {
408 - if (acym_isAdmin()) return;
409 -
410 - $idCurrentUser = acym_currentUserId();
411 - if (empty($idCurrentUser)) return;
412 -
413 - $manageable = acym_loadResultArray(
414 - 'SELECT campaign.id
415 - FROM #__acym_campaign AS campaign
416 - JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id
417 - WHERE mail.creator_id = '.intval($idCurrentUser)
418 - );
419 - $elements = array_intersect($elements, $manageable);
420 - }
421 -
422 - public function hasUserAccess(int $campaignId): bool
423 - {
424 - $userId = acym_currentUserId();
425 - if (empty($userId)) {
426 - return false;
427 - }
428 -
429 - if (acym_isAdmin()) {
430 - return true;
431 - }
432 -
433 - $query = 'SELECT COUNT(*) FROM #__acym_campaign AS campaign
434 - JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id ';
435 -
436 - $condition = 'mail.creator_id = '.intval($userId);
437 - if ($this->config->get('front_campaigns_filter', 'own') === 'allowed') {
438 - $listClass = new ListClass();
439 - $allowedLists = $listClass->getManageableLists();
440 - if (!empty($allowedLists)) {
441 - $query .= ' LEFT JOIN #__acym_mail_has_list AS mailList ON campaign.mail_id = mailList.mail_id AND mailList.list_id IN ('.implode(',', $allowedLists).')';
442 - $condition .= ' OR mailList.list_id IS NOT NULL';
443 - }
444 - }
445 -
446 - $query .= 'WHERE campaign.id = '.intval($campaignId).' AND ('.$condition.')';
447 -
448 - return acym_loadResult($query) > 0;
449 - }
450 -
451 - public function delete($elements)
452 - {
453 - if (!is_array($elements)) $elements = [$elements];
454 - acym_arrayToInteger($elements);
455 - $this->onlyManageableCampaigns($elements);
456 -
457 - if (empty($elements)) return 0;
458 -
459 - $mailsToDelete = [];
460 - foreach ($elements as $id) {
461 - $mailsToDelete[] = acym_loadResult('SELECT mail_id FROM #__acym_campaign WHERE id = '.intval($id));
462 - acym_query('UPDATE #__acym_campaign SET mail_id = NULL WHERE id = '.intval($id));
463 - }
464 -
465 - $mailClass = new MailClass();
466 - $mailClass->delete($mailsToDelete);
467 -
468 - return parent::delete($elements);
469 - }
470 -
471 - public function countUsersCampaign($campaignID, $onlyActive = false): int
472 - {
473 - $campaign = $this->getOneById($campaignID);
474 - if (empty($campaign)) {
475 - return 0;
476 - }
477 -
478 - $mailClass = new MailClass();
479 - $lists = $mailClass->getAllListsByMailId($campaign->mail_id);
480 - $listsIds = array_column($lists, 'id');
481 -
482 - if (empty($listsIds)) {
483 - return 0;
484 - }
485 -
486 - $automationHelperBase = new AutomationHelper();
487 - $automationHelperBase->removeFlag(SegmentsController::FLAG_COUNT);
488 -
489 - $exclude = !empty($campaign->sending_params['segment']['invert']) && $campaign->sending_params['segment']['invert'] === 'exclude';
490 -
491 - $automationHelpers = [];
492 - $filters = $this->getFilterCampaign($campaign->sending_params);
493 - foreach ($filters as $or => $orValues) {
494 - if (empty($orValues)) continue;
495 -
496 - $automationHelpers[$or] = new AutomationHelper();
497 - foreach ($orValues as $and => $andValues) {
498 - $and = intval($and);
499 - foreach ($andValues as $filterName => $options) {
500 - acym_trigger('onAcymProcessFilter_'.$filterName, [&$automationHelpers[$or], &$options, &$and]);
501 - }
502 - }
503 -
504 - $automationHelpers[$or]->excludeSelected = $exclude;
505 - $automationHelpers[$or]->addFlag(SegmentsController::FLAG_COUNT);
506 - }
507 -
508 - $join = ' #__acym_user_has_list AS user_list ON user_list.user_id = user.id ';
509 - $join .= 'AND user_list.list_id IN ('.implode(',', $listsIds).') ';
510 - $join .= 'AND user_list.status = 1 ';
511 - if ($this->config->get('require_confirmation', 1) == 1) {
512 - $join .= 'AND user.confirmed = 1 ';
513 - }
514 - if ($onlyActive) {
515 - $join .= 'AND user.active = 1 ';
516 - }
517 -
518 - if (empty($automationHelpers)) {
519 - $automationHelperBase->join['user_list'] = $join;
520 -
521 - return acym_loadResult($automationHelperBase->getQuery(['COUNT(DISTINCT user.id)']));
522 - } else {
523 - $automationHelperBase = array_pop($automationHelpers);
524 - $automationHelperBase->join['user_list'] = $join;
525 - $numberOfRecipients = acym_loadResult($automationHelperBase->getQuery(['COUNT(DISTINCT user.id)']));
526 - $automationHelperBase->removeFlag(SegmentsController::FLAG_COUNT);
527 -
528 - return $numberOfRecipients;
529 - }
530 - }
531 -
532 - public function getFilterCampaign($sendingParams)
533 - {
534 - $filters = [];
535 -
536 - if (!empty($sendingParams['segment'])) {
537 - if (!empty($sendingParams['segment']['filters'])) {
538 - $filters = $sendingParams['segment']['filters'];
539 - } elseif (!empty($sendingParams['segment']['segment_id'])) {
540 - $segmentClass = new SegmentClass();
541 - $segment = $segmentClass->getOneById($sendingParams['segment']['segment_id']);
542 - if (!empty($segment)) {
543 - $filters = $segment->filters;
544 - }
545 - }
546 - }
547 -
548 - return $filters;
549 - }
550 -
551 - public function send($campaignID, $result = 0, $abTestFinal = false)
552 - {
553 - $campaign = $this->getOneById($campaignID);
554 -
555 - if (empty($campaign->mail_id)) {
556 - $this->errors[] = acym_translation('ACYM_EMAIL_NOT_FOUND');
557 -
558 - return false;
559 - }
560 -
561 - $filters = $this->getFilterCampaign($campaign->sending_params);
562 - $pluginIsExisting = true;
563 -
564 - if (empty($filters)) {
565 - $filters = [0 => []];
566 - acym_trigger('onAcymSendCampaignSpecial', [$campaign, &$filters[0], &$pluginIsExisting]);
567 - } else {
568 - foreach ($filters as $key => $filter) {
569 - acym_trigger('onAcymSendCampaignSpecial', [$campaign, &$filters[$key], &$pluginIsExisting]);
570 - }
571 - }
572 -
573 - if (!$pluginIsExisting) {
574 - return false;
575 - }
576 -
577 - $lists = acym_loadResultArray('SELECT list_id FROM #__acym_mail_has_list WHERE mail_id = '.intval($campaign->mail_id));
578 - if (empty($lists)) {
579 - $this->errors[] = acym_translation('ACYM_NO_LIST_SELECTED');
580 -
581 - return false;
582 - }
583 - acym_arrayToInteger($lists);
584 -
585 - $date = acym_date('now', 'Y-m-d H:i:s', false);
586 - $numberUsersInsertedByMailId = [];
587 -
588 - if (empty($result)) {
589 - $conditions = [
590 - '`user`.`active` = 1',
591 - '`ul`.`status` = 1',
592 - '`ul`.`list_id` IN ('.implode(',', $lists).')',
593 - ];
594 - if ($this->config->get('require_confirmation', 1) == 1) {
595 - $conditions[] = '`user`.`confirmed` = 1';
596 - }
597 -
598 - $automationHelper = new AutomationHelper();
599 - $automationHelper->removeFlag(SegmentsController::FLAG_COUNT);
600 - $automationHelper->join['ul'] = ' #__acym_user_has_list AS ul ON ul.user_id = user.id ';
601 -
602 - if (!empty($filters)) {
603 - $automationHelpers = [];
604 - foreach ($filters as $or => $orValues) {
605 - if (empty($orValues)) continue;
606 -
607 - $automationHelpers[$or] = new AutomationHelper();
608 - foreach ($orValues as $and => $andValues) {
609 - $and = intval($and);
610 - foreach ($andValues as $filterName => $options) {
611 - acym_trigger('onAcymProcessFilter_'.$filterName, [&$automationHelpers[$or], &$options, &$and]);
612 - }
613 - }
614 -
615 - $automationHelpers[$or]->addFlag(SegmentsController::FLAG_COUNT);
616 - }
617 -
618 - if (!empty($automationHelpers)) {
619 - $excludingSegment = !empty($campaign->sending_params['segment']['invert']) && $campaign->sending_params['segment']['invert'] === 'exclude';
620 - if ($excludingSegment) {
621 - $conditions[] = 'user.automation NOT LIKE "%a'.SegmentsController::FLAG_COUNT.'a%"';
622 - } else {
623 - $conditions[] = 'user.automation LIKE "%a'.SegmentsController::FLAG_COUNT.'a%"';
624 - }
625 - }
626 - }
627 -
628 - if (acym_isMultilingual()) {
629 - $select = ['IF(mail.id IS NULL, '.intval($campaign->mail_id).', `mail`.`id`)', 'ul.`user_id`', acym_escapeDB($date)];
630 - $automationHelper->leftjoin['mail'] = '`#__acym_mail` AS mail ON `mail`.`language` = `user`.language AND `mail`.`parent_id` = '.intval($campaign->mail_id);
631 - } else {
632 - $select = [intval($campaign->mail_id), 'ul.`user_id`', acym_escapeDB($date)];
633 - }
634 -
635 - if (!empty($campaign->sending_params['resendTarget']) && 'new' === $campaign->sending_params['resendTarget']) {
636 - if (acym_isMultilingual()) {
637 - $automationHelper->leftjoin['us'] = '`#__acym_user_stat` AS `us` ON `us`.`user_id` = `user`.`id` AND `us`.`mail_id` IN (SELECT id FROM #__acym_mail WHERE parent_id = '.intval(
638 - $campaign->mail_id
639 - ).' OR id = '.intval($campaign->mail_id).')';
640 - } else {
641 - $automationHelper->leftjoin['us'] = '`#__acym_user_stat` AS `us` ON `us`.`user_id` = `user`.`id` AND `us`.`mail_id` = '.intval($campaign->mail_id);
642 - }
643 - $conditions[] = '`us`.`user_id` IS NULL';
644 - }
645 -
646 - $automationHelper->where = $conditions;
647 - if (!empty($campaign->sending_params['abtest']['repartition']) && !$abTestFinal) {
648 - $totalNumberOfUsers = acym_loadResult($automationHelper->getQuery(['count(user.id)']));
649 - $numberOfUsersToSend = round($campaign->sending_params['abtest']['repartition'] * $totalNumberOfUsers / 100);
650 -
651 - $numberOfUsersToSend1 = round($numberOfUsersToSend / 2);
652 - $automationHelper->limit = '0, '.$numberOfUsersToSend1;
653 - $select1 = [intval($campaign->mail_id), 'ul.`user_id`', acym_escapeDB($date)];
654 - $numberUsersInsertedByMailId[intval($campaign->mail_id)] = acym_query(
655 - 'INSERT IGNORE INTO `#__acym_queue` (`mail_id`, `user_id`, `sending_date`) '.$automationHelper->getQuery($select1)
656 - );
657 -
658 - $numberOfUsersToSend2 = $numberOfUsersToSend1 * 2 > $numberOfUsersToSend ? $numberOfUsersToSend1 - 1 : $numberOfUsersToSend1;
659 - $automationHelper->limit = $numberOfUsersToSend.', '.$numberOfUsersToSend2;
660 - $select2 = [intval($campaign->sending_params['abtest']['B']), 'ul.`user_id`', acym_escapeDB($date)];
661 - $numberUsersInsertedByMailId[intval($campaign->sending_params['abtest']['B'])] = acym_query(
662 - 'INSERT IGNORE INTO `#__acym_queue` (`mail_id`, `user_id`, `sending_date`) '.$automationHelper->getQuery($select2)
663 - );
664 - } elseif ($abTestFinal && !empty($campaign->sending_params['abtest']['final'])) {
665 - $mailIds = [$campaign->mail_id, $campaign->sending_params['abtest']['B']];
666 - acym_arrayToInteger($mailIds);
667 - $automationHelper->where[] = 'user.id NOT IN (SELECT user_id FROM #__acym_user_stat WHERE mail_id IN ('.implode(',', $mailIds).'))';
668 -
669 - $select = [intval($campaign->sending_params['abtest']['final']), 'ul.`user_id`', acym_escapeDB($date)];
670 - $numberUsersInsertedByMailId[intval($campaign->sending_params['abtest']['final'])] = acym_query(
671 - 'INSERT IGNORE INTO `#__acym_queue` (`mail_id`, `user_id`, `sending_date`) '.$automationHelper->getQuery($select)
672 - );
673 - } else {
674 - $insertQuery = 'INSERT IGNORE INTO `#__acym_queue` (`mail_id`, `user_id`, `sending_date`) '.$automationHelper->getQuery($select);
675 - $numberUsersInsertedByMailId[intval($campaign->mail_id)] = acym_query($insertQuery);
676 - }
677 -
678 - $automationHelper->removeFlag(SegmentsController::FLAG_COUNT);
679 - } else {
680 - $numberUsersInsertedByMailId[intval($campaign->mail_id)] = $result;
681 - }
682 -
683 -
684 - $result += array_sum($numberUsersInsertedByMailId);
685 -
686 - if ($campaign->sending_type == self::SENDING_TYPE_NOW) {
687 - $campaign->sending_date = $date;
688 - $campaign->draft = 0;
689 - $this->save($campaign);
690 - }
691 -
692 - $mailStatClass = new MailStatClass();
693 - foreach ($numberUsersInsertedByMailId as $mailId => $numberOfUsersInserted) {
694 - $newMailStat = [
695 - 'mail_id' => intval($mailId),
696 - 'total_subscribers' => intval($numberOfUsersInserted),
697 - 'send_date' => $date,
698 - ];
699 -
700 - $mailStatClass->save($newMailStat);
701 - }
702 -
703 - if ($result === 0) {
704 - $this->errors[] = acym_translation('ACYM_NO_SUBSCRIBERS_FOUND');
705 -
706 - return false;
707 - }
708 -
709 - acym_query('UPDATE `#__acym_campaign` SET `sent` = 1, `active` = 1 WHERE `mail_id` = '.intval($campaign->mail_id));
710 -
711 - return $result;
712 - }
713 -
714 - public function getCampaignForDashboard()
715 - {
716 - $query = 'SELECT campaign.*, mail.name as name FROM #__acym_campaign as campaign LEFT JOIN #__acym_mail as mail ON campaign.mail_id = mail.id WHERE `active` = 1 AND `sending_type` = '.acym_escapeDB(
717 - self::SENDING_TYPE_SCHEDULED
718 - ).' AND `sent` = 0 LIMIT 3';
719 -
720 - return $this->decode(acym_loadObjectList($query));
721 - }
722 -
723 - public function getOpenRateCampaigns($mailIds)
724 - {
725 - if (!is_array($mailIds)) $mailIds = [$mailIds];
726 - acym_arrayToInteger($mailIds);
727 -
728 - $query = 'SELECT SUM(sent) AS sent, SUM(open_unique) AS open_unique FROM #__acym_mail_stat
729 - WHERE mail_id IN ('.implode(',', $mailIds).')';
730 -
731 - return acym_loadObject($query);
732 - }
733 -
734 - public function getOpenRateAllCampaign()
735 - {
736 - $query = 'SELECT SUM(sent) as sent, SUM(open_unique) as open_unique FROM #__acym_mail_stat';
737 -
738 - return acym_loadObject($query);
739 - }
740 -
741 - public function getBounceRateAllCampaign()
742 - {
743 - $query = 'SELECT SUM(sent) as sent, SUM(bounce_unique) as bounce_unique FROM #__acym_mail_stat';
744 -
745 - return acym_loadObject($query);
746 - }
747 -
748 -
749 - public function getBounceRateCampaigns($mailIds)
750 - {
751 - if (!is_array($mailIds)) $mailIds = [$mailIds];
752 -
753 - acym_arrayToInteger($mailIds);
754 -
755 - $query = 'SELECT SUM(sent) AS sent, SUM(bounce_unique) AS bounce_unique FROM #__acym_mail_stat
756 - WHERE mail_id IN ('.implode(',', $mailIds).')';
757 -
758 - return acym_loadObject($query);
759 - }
760 -
761 - public function getOpenByMonth($mailIds = [], $start = '', $end = '')
762 - {
763 - if (!is_array($mailIds)) $mailIds = [$mailIds];
764 - acym_arrayToInteger($mailIds);
765 -
766 - $query = 'SELECT COUNT(user_id) as open, DATE_FORMAT(open_date, \'%Y-%m\') as open_date FROM #__acym_user_stat WHERE open > 0';
767 - $query .= empty($mailIds) ? '' : ' AND `mail_id` IN ('.implode(',', $mailIds).')';
768 - $query .= ' AND `open_date` > "0000-00-00"';
769 - $query .= empty($start) ? '' : ' AND `open_date` >= '.acym_escapeDB($start);
770 - $query .= empty($end) ? '' : ' AND `open_date` <= '.acym_escapeDB($end);
771 - $query .= ' GROUP BY MONTH(open_date), YEAR(open_date) ORDER BY open_date';
772 -
773 - return acym_loadObjectList($query);
774 - }
775 -
776 - public function getOpenByWeek($mail_id = '', $start = '', $end = '')
777 - {
778 - $query = 'SELECT COUNT(user_id) as open, DATE_FORMAT(open_date, \'%Y-%m-%d\') as open_date FROM #__acym_user_stat WHERE open > 0';
779 - $query .= empty($mail_id) ? '' : ' AND `mail_id`='.intval($mail_id);
780 - $query .= ' AND `open_date` > "0000-00-00"';
781 - $query .= empty($start) ? '' : ' AND `open_date` >= '.acym_escapeDB($start);
782 - $query .= empty($end) ? '' : ' AND `open_date` <= '.acym_escapeDB($end);
783 - $query .= ' GROUP BY WEEK(open_date), YEAR(open_date) ORDER BY open_date';
784 -
785 - return acym_loadObjectList($query);
786 - }
787 -
788 - public function getOpenByDay($mailIds = [], $start = '', $end = '')
789 - {
790 - if (!is_array($mailIds)) $mailIds = [$mailIds];
791 - acym_arrayToInteger($mailIds);
792 -
793 - $query = 'SELECT COUNT(user_id) as open, DATE_FORMAT(open_date, \'%Y-%m-%d\') as open_date FROM #__acym_user_stat WHERE open > 0';
794 - $query .= empty($mailIds) ? '' : ' AND `mail_id` IN ('.implode(',', $mailIds).')';
795 - $query .= ' AND `open_date` > "0000-00-00"';
796 - $query .= empty($start) ? '' : ' AND `open_date` >= '.acym_escapeDB($start);
797 - $query .= empty($end) ? '' : ' AND `open_date` <= '.acym_escapeDB($end);
798 - $query .= ' GROUP BY DAYOFYEAR(open_date), YEAR(open_date) ORDER BY open_date';
799 -
800 - return acym_loadObjectList($query);
801 - }
802 -
803 - public function getOpenByHour($mailIds = [], $start = '', $end = '')
804 - {
805 - if (!is_array($mailIds)) $mailIds = [$mailIds];
806 - acym_arrayToInteger($mailIds);
807 -
808 - $query = 'SELECT COUNT(user_id) as open, DATE_FORMAT(open_date, \'%Y-%m-%d %H:00:00\') as open_date FROM #__acym_user_stat WHERE open > 0';
809 - $query .= empty($mailIds) ? '' : ' AND `mail_id` IN ('.implode(',', $mailIds).')';
810 - $query .= ' AND `open_date` > "0000-00-00 00:00:00"';
811 - $query .= empty($start) ? '' : ' AND `open_date` >= '.acym_escapeDB($start);
812 - $query .= empty($end) ? '' : ' AND `open_date` <= '.acym_escapeDB($end);
813 - $query .= ' GROUP BY HOUR(open_date), DAYOFYEAR(open_date), YEAR(open_date) ORDER BY open_date';
814 -
815 - return acym_loadObjectList($query);
816 - }
817 -
818 - public function getDevicesWithCountByMailId($mailIds = [])
819 - {
820 - if (!is_array($mailIds)) $mailIds = [$mailIds];
821 - acym_arrayToInteger($mailIds);
822 -
823 - $query = 'SELECT device, COUNT(*) as number FROM #__acym_user_stat WHERE `open` > 0';
824 - if (!empty($mailIds)) $query .= ' AND mail_id IN ('.implode(',', $mailIds).')';
825 - $query .= ' GROUP BY device';
826 -
827 - return acym_loadObjectList($query);
828 - }
829 -
830 - public function getLastNewsletters(&$params): array
831 - {
832 - $querySelect = 'SELECT mail.*, campaign.sending_date ';
833 - $queryCountSelect = 'SELECT COUNT(*) FROM (SELECT DISTINCT mail.id ';
834 -
835 - $query = 'FROM #__acym_campaign AS campaign
836 - JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id ';
837 -
838 - if (isset($params['userId']) || isset($params['lists'])) {
839 - $query .= 'JOIN #__acym_mail_has_list AS maillist ON mail.id = maillist.mail_id ';
840 - if (isset($params['userId'])) $query .= 'JOIN #__acym_user_has_list AS userlist ON maillist.list_id = userlist.list_id ';
841 - }
842 -
843 - $where = 'WHERE campaign.active = 1 AND campaign.sent = 1 AND mail.type = '.acym_escapeDB(MailClass::TYPE_STANDARD).' AND campaign.visible = 1 ';
844 -
845 - if (isset($params['lists'])) {
846 - acym_arrayToInteger($params['lists']);
847 - $where .= 'AND maillist.list_id IN ('.implode(', ', $params['lists']).') ';
848 - }
849 -
850 - if (isset($params['userId']) && !empty($params['displayUserListOnly'])) {
851 - $where .= 'AND userlist.user_id = '.intval($params['userId']).' ';
852 - }
853 -
854 - if (isset($params['search'])) {
855 - $search = acym_escapeDB('%'.acym_utf8Encode($params['search']).'%');
856 - $where .= 'AND (mail.subject LIKE '.$search.' OR mail.body LIKE '.$search.')';
857 - }
858 -
859 - $query .= $where;
860 - $return = [];
861 - $return['count'] = (int)acym_loadResult($queryCountSelect.$query.') AS r ');
862 -
863 - $endQuerySelect = 'GROUP BY mail.id ';
864 - $endQuerySelect .= 'ORDER BY campaign.sending_date DESC';
865 -
866 - $page = $params['page'] ?? 0;
867 - $numberPerPage = $params['numberPerPage'] ?? 0;
868 - $lastNewsletters = $params['limit'] ?? 0;
869 -
870 - if (!empty($page) && !empty($numberPerPage)) {
871 - if (!empty($lastNewsletters)) {
872 - $limit = $page * $numberPerPage > $lastNewsletters ? fmod($lastNewsletters, $numberPerPage) : $numberPerPage;
873 - } else {
874 - $limit = $numberPerPage;
875 - $nbTotalPage = ceil($return['count'] / $numberPerPage);
876 - if ($params['page'] > $nbTotalPage) {
877 - $params['page'] = 1;
878 - }
879 - }
880 -
881 - $offset = ($params['page'] - 1) * $numberPerPage;
882 - $endQuerySelect .= ' LIMIT '.intval($offset).', '.intval($limit);
883 - } elseif (!empty($lastNewsletters)) {
884 - $limit = $lastNewsletters;
885 -
886 - $endQuerySelect .= ' LIMIT '.intval($limit);
887 - }
888 -
889 -
890 - $return['matchingNewsletters'] = $this->decode(acym_loadObjectList($querySelect.$query.$endQuerySelect));
891 -
892 - if (isset($params['language']) && !empty($return['matchingNewsletters'])) {
893 - $mailIds = array_column($return['matchingNewsletters'], 'id');
894 -
895 - $translatedEmails = $this->decode(
896 - acym_loadObjectList(
897 - 'SELECT mail.*
898 - FROM #__acym_mail AS mail
899 - WHERE mail.parent_id IN ('.implode(',', $mailIds).') AND mail.language = '.acym_escapeDB($params['language']),
900 - 'parent_id'
901 - )
902 - );
903 - }
904 -
905 - $userClass = new UserClass();
906 - $userEmail = acym_currentUserEmail();
907 - $user = $userClass->getOneByEmail($userEmail);
908 -
909 - foreach ($return['matchingNewsletters'] as $i => $oneNewsletter) {
910 - if (isset($translatedEmails[$oneNewsletter->id])) {
911 - $translatedEmails[$oneNewsletter->id]->sending_date = $oneNewsletter->sending_date;
912 - $oneNewsletter = $translatedEmails[$oneNewsletter->id];
913 - }
914 - acym_trigger('replaceContent', [&$oneNewsletter, false]);
915 - acym_trigger('replaceUserInformation', [&$oneNewsletter, &$user, false]);
916 -
917 - $return['matchingNewsletters'][$i] = $oneNewsletter;
918 - }
919 -
920 - return $return;
921 - }
922 -
923 - public function getListsByMailId($mailId)
924 - {
925 - $query = 'SELECT list_id FROM #__acym_mail_has_list WHERE mail_id = '.intval($mailId);
926 -
927 - return acym_loadResultArray($query);
928 - }
929 -
930 - public function triggerAutoCampaign()
931 - {
932 - $activeAutoCampaigns = acym_loadObjectList(
933 - 'SELECT campaign.*, mail.name
934 - FROM #__acym_campaign AS campaign
935 - JOIN #__acym_mail AS mail ON campaign.`mail_id` = mail.`id`
936 - WHERE `active` = 1 AND `sending_type` = '.acym_escapeDB(self::SENDING_TYPE_AUTO)
937 - );
938 - $activeAutoCampaigns = $this->decode($activeAutoCampaigns);
939 -
940 - if (empty($activeAutoCampaigns)) {
941 - return;
942 - }
943 -
944 - $mailClass = new MailClass();
945 - $mailerHelper = new MailerHelper();
946 - $mailerHelper->autoAddUser = true;
947 - $adminNotificationEmail = $mailClass->getOneByName('acy_notification_auto_campaign_admin');
948 - $time = time();
949 -
950 - foreach ($activeAutoCampaigns as $campaign) {
951 - if (!empty($campaign->sending_params['start_date']) && (int)acym_getTime(acym_date($campaign->sending_params['start_date'], 'Y-m-d H:i')) > $time) {
952 - continue;
953 - }
954 -
955 - $step = new \stdClass();
956 - $step->triggers = $campaign->sending_params;
957 - $step->last_execution = $campaign->last_generated;
958 - $step->next_execution = $campaign->next_trigger;
959 -
960 - $data = ['time' => $time];
961 - $execute = !empty($step->next_execution) && $step->next_execution <= $data['time'];
962 - acym_trigger('onAcymExecuteTrigger', [&$step, &$execute, &$data], 'plgAcymTime');
963 - $campaign->next_trigger = $step->next_execution;
964 - if (!$execute) {
965 - $this->save($campaign);
966 - continue;
967 - }
968 -
969 - $campaignMail = $mailClass->getOneById($campaign->mail_id);
970 -
971 - $lastGenerated = $campaign->last_generated;
972 - $shouldGenerate = $this->updateAutoCampaign($campaign, $campaignMail, $time);
973 - $this->save($campaign);
974 -
975 - if (!$shouldGenerate) {
976 - continue;
977 - }
978 -
979 - $generatedCampaign = $this->generateCampaign($campaign, $campaignMail, $lastGenerated, $mailClass);
980 -
981 - if (empty($campaign->sending_params['need_confirm_to_send'])) {
982 - $this->send($generatedCampaign->id);
983 - } elseif (!empty($campaign->sending_params['admin_notification_emails']) && !empty($adminNotificationEmail)) {
984 - $mailerHelper->addParam('campaign_name', $campaign->name);
985 - $campaignLink = '<a href="'.acym_backendLink('campaigns&task=summaryGenerated&campaignId='.$generatedCampaign->id).'">'.$campaign->name.'</a>';
986 - $mailerHelper->addParam('campaign_link', $campaignLink);
987 -
988 - foreach ($campaign->sending_params['admin_notification_emails'] as $email) {
989 - $mailerHelper->sendOne($adminNotificationEmail->id, $email);
990 - }
991 - }
992 - }
993 - }
994 -
995 - private function shouldGenerateCampaign($campaign, $campaignMail): bool
996 - {
997 - $results = acym_trigger('generateByCategory', [&$campaignMail], null, function ($plugin) {
998 - $plugin->generateCampaignResult->status = true;
999 - });
1000 -
1001 - foreach ($results as $oneResult) {
1002 - if (isset($oneResult->status) && !$oneResult->status) {
1003 - $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_NOT_GENERATED', $campaign->name, $oneResult->message);
1004 -
1005 - return false;
1006 - }
1007 - }
1008 -
1009 - return true;
1010 - }
1011 -
1012 - private function updateAutoCampaign(&$campaign, $campaignMail, $time): bool
1013 - {
1014 - if (!$this->shouldGenerateCampaign($campaign, $campaignMail)) {
1015 - return false;
1016 - }
1017 -
1018 - if (empty($campaign->sending_params['number_generated'])) {
1019 - $campaign->sending_params['number_generated'] = 1;
1020 - } else {
1021 - $campaign->sending_params['number_generated']++;
1022 - }
1023 - $campaign->last_generated = $time;
1024 -
1025 - $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_GENERATED', $campaign->name, $campaign->sending_params['number_generated']);
1026 -
1027 - return true;
1028 - }
1029 -
1030 - private function generateCampaign($campaign, $campaignMail, $lastGenerated, $mailClass)
1031 - {
1032 - $newMail = $this->generateMailAutoCampaign($campaignMail, $campaign->sending_params['number_generated'], $mailClass);
1033 - $newCampaign = new \stdClass();
1034 - $newCampaign->mail_id = $newMail->id;
1035 - $newCampaign->parent_id = $campaign->id;
1036 - $newCampaign->active = 1;
1037 - $newCampaign->visible = $campaign->visible;
1038 - $newCampaign->draft = 1;
1039 - $newCampaign->sending_type = self::SENDING_TYPE_NOW;
1040 - $newCampaign->sent = 0;
1041 - $newCampaign->last_generated = $lastGenerated;
1042 - $newCampaign->sending_params = empty($campaign->sending_params['segment']) ? '' : ['segment' => $campaign->sending_params['segment']];
1043 -
1044 - $newCampaign->id = $this->save($newCampaign);
1045 -
1046 - acym_trigger('replaceContent', [&$newMail, false]);
1047 - $mailClass->save($newMail);
1048 -
1049 - return $newCampaign;
1050 - }
1051 -
1052 - private function generateMailAutoCampaign($newMail, $generatedMailNumber, $mailClass)
1053 - {
1054 - $mailId = $newMail->id;
1055 - unset($newMail->id);
1056 - $newMail->creation_date = acym_date('now', 'Y-m-d H:i:s', false);
1057 - $newMail->name .= ' #'.$generatedMailNumber;
1058 -
1059 - $newMail->id = $mailClass->save($newMail);
1060 - $this->setListToGeneratedCampaign($mailId, $newMail->id, $mailClass);
1061 -
1062 - if (acym_isMultilingual()) {
1063 - $this->generateMailAutoCampaignMultilingual($mailId, $generatedMailNumber, $newMail->id);
1064 - }
1065 -
1066 - return $newMail;
1067 - }
1068 -
1069 - private function generateMailAutoCampaignMultilingual($mailId, $generatedMailNumber, $newParentId)
1070 - {
1071 - $mailClass = new MailClass();
1072 - $mails = $mailClass->getTranslationsById($mailId, true);
1073 -
1074 - foreach ($mails as $mail) {
1075 - unset($mail->id);
1076 - $mail->name .= ' #'.$generatedMailNumber;
1077 - $mail->parent_id = $newParentId;
1078 -
1079 - $mailClass->save($mail);
1080 - }
1081 - }
1082 -
1083 - private function setListToGeneratedCampaign($parentMailId, $newMailId, $mailClass)
1084 - {
1085 - $lists = $mailClass->getAllListsByMailId($parentMailId);
1086 - $listIds = array_keys($lists);
1087 -
1088 - $this->manageListsToCampaign($listIds, $newMailId);
1089 - }
1090 -
1091 - public function getLastGenerated($mailId)
1092 - {
1093 - return acym_loadResult(
1094 - 'SELECT `last_generated`
1095 - FROM #__acym_campaign
1096 - WHERE `mail_id` = '.intval($mailId)
1097 - );
1098 - }
1099 -
1100 - private function getNbGeneratedCampaigns(): int
1101 - {
1102 - return (int)acym_loadResult(
1103 - 'SELECT COUNT(*)
1104 - FROM #__acym_campaign
1105 - WHERE `parent_id` IS NOT NULL
1106 - AND `sending_type` = '.acym_escapeDB(self::SENDING_TYPE_NOW)
1107 - );
1108 - }
1109 -
1110 - public function getAllCampaignsGeneratedWaiting()
1111 - {
1112 - return acym_loadObjectList(
1113 - 'SELECT id
1114 - FROM #__acym_campaign
1115 - WHERE parent_id IS NOT NULL
1116 - AND sending_type = '.acym_escapeDB(self::SENDING_TYPE_NOW).'
1117 - AND draft = 1
1118 - AND active = 1
1119 - AND sent = 0'
1120 - );
1121 - }
1122 -
1123 - public function getCampaignsByTypes($campaignTypes, $onlyActives = false)
1124 - {
1125 - if (empty($campaignTypes)) return [];
1126 - $campaignTypes = array_map('acym_escapeDB', $campaignTypes);
1127 - $query = 'SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.sending_type IN ('.implode(',', $campaignTypes).')';
1128 - if ($onlyActives) $query .= ' AND campaign.active = 1';
1129 -
1130 - return $this->decode(acym_loadObjectList($query), false);
1131 - }
1132 -
1133 - public function getCountCampaignType($type)
1134 - {
1135 - if (empty($type)) return 0;
1136 -
1137 - return acym_loadResult('SELECT COUNT(*) FROM #__acym_campaign WHERE sending_type = '.acym_escapeDB($type));
1138 - }
1139 -
1140 - public function getAllAbTestCampaignsToFinishSending()
1141 - {
1142 - $query = 'SELECT * FROM #__acym_campaign WHERE sending_params LIKE \'%"abtest":%\' AND draft = 0 AND active = 1 AND sent = 1';
1143 -
1144 - return $this->decode(acym_loadObjectList($query));
1145 - }
1146 -
1147 - public function finishAbTestCampaign($campaign)
1148 - {
1149 - $abTestParams = empty($campaign->sending_params['abtest']) ? [] : $campaign->sending_params['abtest'];
1150 -
1151 - if (empty($abTestParams['B']) || empty($abTestParams['repartition']) || !empty($abTestParams['abtest_finished']) || empty($abTestParams['after']['action'])) {
1152 - return false;
1153 - }
1154 -
1155 - if (strtotime($campaign->sending_date.' + '.$abTestParams['after']['days'].' days') > time()) {
1156 - return false;
1157 - }
1158 -
1159 - $mailStatsClass = new MailStatClass();
1160 - $mailIds = [$campaign->mail_id, $abTestParams['B']];
1161 - $bestMails = $mailStatsClass->getBestEmailByStats($mailIds, $abTestParams['after']['action']);
1162 -
1163 - if (empty($bestMails)) {
1164 - return false;
1165 - }
1166 -
1167 - $mailClass = new MailClass();
1168 -
1169 - switch ($abTestParams['after']['action']) {
1170 - case 'open_rate':
1171 - case 'click_rate':
1172 - $mail = $mailClass->getOneById($bestMails[$abTestParams['after']['action']]);
1173 -
1174 - if (empty($mail)) {
1175 - return false;
1176 - }
1177 - break;
1178 - case 'click_open_rate':
1179 - $bestMailClickRate = $mailClass->getOneById($bestMails['click_rate']);
1180 - $bestMailOpenRate = $mailClass->getOneById($bestMails['open_rate']);
1181 -
1182 - if (empty($bestMailClickRate) || empty($bestMailOpenRate)) {
1183 - return false;
1184 - }
1185 -
1186 - $mail = $bestMailClickRate;
1187 - $mail->preheader = $bestMailOpenRate->preheader;
1188 - $mail->subject = $bestMailOpenRate->subject;
1189 - $mail->from_name = $bestMailOpenRate->from_name;
1190 - $mail->from_email = $bestMailOpenRate->from_email;
1191 - $mail->reply_to_name = $bestMailOpenRate->reply_to_name;
1192 - $mail->reply_to_email = $bestMailOpenRate->reply_to_email;
1193 - break;
1194 - }
1195 -
1196 - $mail->id = 0;
1197 - $mail->parent_id = $campaign->mail_id;
1198 - $mail->name .= ' - '.acym_translation('ACYM_ABTEST_WINNER');
1199 - $newMailId = $mailClass->save($mail);
1200 - if (!$newMailId) {
1201 - return false;
1202 - }
1203 -
1204 - $campaign->sending_params['abtest']['abtest_finished'] = 1;
1205 - $campaign->sending_params['abtest']['final'] = $newMailId;
1206 -
1207 - $this->save($campaign);
1208 - $this->send($campaign->id, 0, true);
1209 -
1210 - return true;
1211 - }
1212 -
1213 - public function isAbTestMail($mailId): bool
1214 - {
1215 - $mailClass = new MailClass();
1216 - $mainMailId = $mailClass->getMainMailId($mailId);
1217 -
1218 - $campaign = acym_loadObject(
1219 - 'SELECT *
1220 - FROM #__acym_campaign
1221 - WHERE mail_id = '.intval($mainMailId).'
1222 - AND sending_params LIKE \'%"abtest":%\''
1223 - );
1224 -
1225 - return !empty($campaign);
1226 - }
1227 -
1228 - public function resetAbTestVersion($campaignId): void
1229 - {
1230 - if (empty($campaignId)) {
1231 - return;
1232 - }
1233 -
1234 - $campaign = $this->getOneById($campaignId);
1235 -
1236 - if (empty($campaign)) {
1237 - return;
1238 - }
1239 -
1240 - if (empty($campaign->sending_params['abtest'])) {
1241 - return;
1242 - }
1243 -
1244 - foreach (self::AB_TEST_VERSIONS as $version) {
1245 - if (!empty($campaign->sending_params['abtest'][$version])) {
1246 - $mailClass = new MailClass();
1247 - $mailClass->delete($campaign->sending_params['abtest'][$version]);
1248 - unset($campaign->sending_params['abtest'][$version]);
1249 - }
1250 - }
1251 -
1252 - $this->save($campaign);
1253 - }
1254 -
1255 - public function getXCampaigns(array $options)
1256 - {
1257 - $limit = $options['limit'] ?? 10;
1258 - $offset = $options['offset'] ?? 0;
1259 - $filters = $options['filters'] ?? [];
1260 -
1261 - $conditions = [];
1262 - foreach ($filters as $column => $filter) {
1263 - switch ($column) {
1264 - case 'id':
1265 - case 'draf':
1266 - case 'active':
1267 - case 'mail_id':
1268 - case 'sent':
1269 - case 'parent_id':
1270 - case 'next_trigger':
1271 - case 'visible':
1272 - case 'last_trigger':
1273 - $conditions[] = 'campaign.'.acym_secureDBColumn($column).' = '.intval($filter);
1274 - break;
1275 - case 'name':
1276 - case 'subject':
1277 - $conditions[] = 'mail.'.acym_secureDBColumn($column).' LIKE '.acym_escapeDB('%'.$filter.'%');
1278 - break;
1279 - default:
1280 - $conditions[] = 'campaign.'.acym_secureDBColumn($column).' = '.acym_escapeDB('%'.$filter.'%');
1281 - }
1282 - }
1283 -
1284 - $query = 'SELECT campaign.*, mail.subject, mail.name FROM #__acym_campaign AS campaign
1285 - LEFT JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id';
1286 -
1287 - if (!empty($conditions)) {
1288 - $query .= ' WHERE '.implode(' AND ', $conditions);
1289 - }
1290 -
1291 - return $this->decode(acym_loadObjectList($query, $this->pkey, $offset, $limit));
1292 - }
1293 -
1294 - public function getOneCampaign(): bool
1295 - {
1296 - $firstCampaign = acym_loadObject('SELECT * FROM #__acym_campaign');
1297 -
1298 - return !empty($firstCampaign);
1299 - }
1300 -}