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/Controllers/Stats/GlobalStats.php +0 -926 10.10.2 → 11.1.1 View file →
@@ -1,926 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Controllers\Stats;
4 -
5 -use AcyMailing\Classes\CampaignClass;
6 -use AcyMailing\Classes\MailClass;
7 -use AcyMailing\Classes\MailStatClass;
8 -use AcyMailing\Classes\UrlClickClass;
9 -use AcyMailing\Classes\UserStatClass;
10 -use AcyMailing\Helpers\ExportHelper;
11 -use AcyMailing\Helpers\MailerHelper;
12 -use AcyMailing\Helpers\PaginationHelper;
13 -use AcyMailing\Helpers\WorkflowHelper;
14 -use AcyMailing\Libraries\Browser\BrowserDetection;
15 -use AcyMailing\Classes\UserClass;
16 -
17 -trait GlobalStats
18 -{
19 - public function globalStats(): void
20 - {
21 - acym_setVar('layout', 'global_stats');
22 -
23 - $data = [];
24 -
25 - $this->prepareDefaultPageInfo($data);
26 -
27 - $this->prepareOpenTimeChart($data);
28 - $this->preparecharts($data);
29 - $this->prepareListReceivers($data);
30 - $this->prepareDefaultRoundCharts($data);
31 - $this->prepareDefaultLineChart($data);
32 - $this->prepareDefaultDevicesChart($data);
33 - $this->prepareDefaultBrowsersChart($data);
34 - if (count($this->selectedMailIds) == 1) {
35 - if ($data['isAbTest']) {
36 - $this->prepareAbTestMails($data);
37 - } elseif (acym_isMultilingual()) {
38 - $this->prepareMultilingualMails($data);
39 - }
40 - }
41 - $this->prepareMailFilter($data);
42 -
43 - parent::display($data);
44 - }
45 -
46 - private function prepareMailFilter(array &$data): void
47 - {
48 - $data['input_mail_ids'] = '';
49 -
50 - if (!empty($this->multiLanguageMailAdded) || !empty($this->generatedMailAdded)) {
51 - $this->selectedMailIds = array_filter(
52 - $this->selectedMailIds,
53 - function ($mailId) {
54 - return !in_array($mailId, $this->multiLanguageMailAdded) && !in_array($mailId, $this->generatedMailAdded);
55 - }
56 - );
57 - }
58 -
59 - if (count($this->selectedMailIds) > 1) {
60 - $data['input_mail_ids'] = '<input type="hidden" value="'.implode(',', $this->selectedMailIds).'" name="mail_ids">';
61 - }
62 -
63 - $attributes = [
64 - 'class' => 'acym__select acym_select2_ajax acym__stats__select__mails',
65 - 'data-placeholder' => acym_translation('ACYM_ALL_EMAILS'),
66 - 'data-ctrl' => 'stats',
67 - 'data-task' => 'searchSentMail',
68 - 'data-min' => '0',
69 - 'id' => 'mail_ids',
70 - ];
71 -
72 - if (!empty($this->selectedMailIds)) {
73 - $attributes['data-selected'] = implode(',', $this->selectedMailIds);
74 - }
75 -
76 - $data['mail_filter'] = acym_selectMultiple(
77 - [],
78 - 'mail_ids',
79 - [],
80 - $attributes
81 - );
82 -
83 - $data['emailVersionsFilters'] = '';
84 -
85 - if (!empty($data['emailVersions'])) {
86 - $data['emailVersionsFilters'] = acym_select(
87 - $data['emailVersions'],
88 - 'mail_id_version',
89 - $this->selectedMailIds[0],
90 - [
91 - 'class' => 'acym__select acym__stats__select__language',
92 - ]
93 - );
94 - }
95 - if (!empty($data['emailTranslations'])) {
96 - $data['emailVersionsFilters'] = acym_select(
97 - $data['emailTranslations'],
98 - 'mail_id_version',
99 - $this->selectedMailIds[0],
100 - [
101 - 'class' => 'acym__select acym__stats__select__language',
102 - ]
103 - );
104 - }
105 - }
106 -
107 - private function prepareClickStats(array &$data): void
108 - {
109 - if (empty($data['selectedMailid'])) {
110 - return;
111 - }
112 -
113 - $urlClickClass = new UrlClickClass();
114 - $allClickInfo = $urlClickClass->getAllLinkFromEmail($this->selectedMailIds[0]);
115 -
116 - $data['url_click'] = [];
117 - $data['url_click']['allClick'] = $allClickInfo['allClick'];
118 -
119 - $allPercentage = [];
120 - foreach ($allClickInfo['urls_click'] as $url) {
121 - $percentage = 0;
122 - if (empty($url->click)) {
123 - $data['url_click'][$url->name] = ['percentage' => $percentage, 'numberClick' => '0'];
124 - } else {
125 - $percentage = intval(($url->click * 100) / $allClickInfo['allClick']);
126 - $data['url_click'][$url->name] = ['percentage' => $percentage, 'numberClick' => $url->click];
127 - }
128 - $allPercentage[] = $percentage;
129 - }
130 -
131 - $helperMailer = new MailerHelper();
132 - if (!empty($data['mailInformation'])) {
133 - $helperMailer->body = $data['mailInformation']->body;
134 - $helperMailer->statClick(intval($data['mailInformation']->id), 0, true);
135 - $data['mailInformation']->body = preg_replace('#&(amp;)?autoSubId=[^"]+"#Uis', '"', $helperMailer->body);
136 - }
137 -
138 - if (!empty($allPercentage)) {
139 - $maxPercentage = max($allPercentage);
140 -
141 - foreach ($data['url_click'] as $name => $val) {
142 - if ($name === 'allClick') continue;
143 - $percentageRecalc = intval(($val['percentage'] * 100) / $maxPercentage);
144 - if ($percentageRecalc <= 33) {
145 - $data['url_click'][$name]['color'] = '0, 164, 255';
146 - } elseif ($percentageRecalc <= 66) {
147 - $data['url_click'][$name]['color'] = '248, 31, 255';
148 - } else {
149 - $data['url_click'][$name]['color'] = '255, 82, 89';
150 - }
151 - }
152 - }
153 -
154 - $data['url_click'] = json_encode($data['url_click']);
155 -
156 - $data['url_foundation_email'] = ACYM_CSS.'libraries/foundation_email.min.css?v='.filemtime(ACYM_MEDIA.'css'.DS.'libraries'.DS.'foundation_email.min.css');
157 - $data['url_click_map_email'] = ACYM_CSS.'click_map.min.css?v='.filemtime(ACYM_MEDIA.'css'.DS.'click_map.min.css');
158 - }
159 -
160 - public function prepareDefaultRoundCharts(array &$data): void
161 - {
162 - $charts = [
163 - 'delivery' => [
164 - 'percentage' => 95,
165 - 'text' => 'ACYM_SUCCESSFULLY_SENT',
166 - ],
167 - 'open' => [
168 - 'percentage' => 25,
169 - 'text' => 'ACYM_OPEN_RATE',
170 - ],
171 - 'click' => [
172 - 'percentage' => 10,
173 - 'text' => 'ACYM_CLICK_RATE',
174 - ],
175 - 'fail' => [
176 - 'percentage' => 2,
177 - 'text' => 'ACYM_BOUNCE_RATE',
178 - ],
179 - 'unsub' => [
180 - 'percentage' => 3,
181 - 'text' => 'ACYM_UNSUBSCRIBE',
182 - ],
183 - ];
184 -
185 - $data['example_round_chart'] = '';
186 - foreach ($charts as $type => $oneChart) {
187 - if ($type == 'unsub' && empty($this->selectedMailIds)) continue;
188 - $data['example_round_chart'] .= '<div class="cell acym__stats__donut__one-chart">';
189 - $data['example_round_chart'] .= acym_roundChart(
190 - $oneChart['percentage'],
191 - $type,
192 - '',
193 - acym_translation($oneChart['text'])
194 - );
195 - $data['example_round_chart'] .= '</div>';
196 - }
197 - }
198 -
199 - public function prepareDefaultLineChart(array &$data): void
200 - {
201 - $dataMonth = [];
202 - $dataMonth['Jan 18'] = ['open' => '150', 'click' => '40'];
203 - $dataDay = [];
204 - $dataDay['23 Jan'] = ['open' => '150', 'click' => '40'];
205 - $dataHour = [];
206 - $dataHour['23 Jan 08:00'] = ['open' => '25', 'click' => '10'];
207 - $dataHour['23 Jan 09:00'] = ['open' => '50', 'click' => '10'];
208 - $dataHour['23 Jan 10:00'] = ['open' => '16', 'click' => '10'];
209 - $dataHour['23 Jan 11:00'] = ['open' => '59', 'click' => '10'];
210 - $data['example_line_chart'] = acym_lineChart($dataMonth, $dataDay, $dataHour);
211 - }
212 -
213 - public function prepareDefaultDevicesChart(array &$data): void
214 - {
215 - $defaultData = [
216 - 'ACYM_MOBILE' => 25662,
217 - 'ACYM_DESKTOP' => 12471,
218 - 'ACYM_OTHER' => 3548,
219 - 'ACYM_UNKNOWN' => 6213,
220 - ];
221 -
222 - $data['example_devices_chart'] = acym_pieChart($defaultData, '', acym_translation('ACYM_DEVICES'));
223 - }
224 -
225 - public function prepareDefaultBrowsersChart(array &$data): void
226 - {
227 - $exampleData = [
228 - 'Apple Mail' => 15835,
229 - 'Google Chrome' => 13375,
230 - 'Safari' => 2667,
231 - 'Outlook' => 2458,
232 - 'Edge' => 1190,
233 - 'Firefox' => 826,
234 - 'ACYM_OTHER' => 4775,
235 - 'ACYM_UNKNOWN' => 6123,
236 - ];
237 -
238 - $data['example_source_chart'] = acym_pieChart($exampleData, '', acym_translation('ACYM_OPENED_WITH'));
239 - }
240 -
241 - public function setDataForChartLine(): void
242 - {
243 - $newStart = acym_date(acym_getVar('string', 'start'), 'Y-m-d H:i:s');
244 - $newEnd = acym_date(acym_getVar('string', 'end'), 'Y-m-d H:i:s');
245 - $mailIds = acym_getVar('int', 'id');
246 -
247 - if (empty($mailIds)) {
248 - $mailIds = [];
249 - }
250 -
251 - $mailClass = new MailClass();
252 - if (!empty($mailIds)) {
253 - $mailIds = $mailClass->getAutomaticMailIds($mailIds);
254 - }
255 -
256 - if (!empty($mailIds) && !is_array($mailIds)) {
257 - $mailIds = [$mailIds];
258 - }
259 -
260 - if ($newStart >= $newEnd) {
261 - echo 'error';
262 - exit;
263 - }
264 -
265 - $statsCampaignSelected = new \stdClass();
266 - $this->prepareLineChart($statsCampaignSelected, $mailIds, $newStart, $newEnd);
267 -
268 - echo acym_lineChart($statsCampaignSelected->month, $statsCampaignSelected->day, $statsCampaignSelected->hour, true);
269 - exit;
270 - }
271 -
272 - private function getValues(string $modifier, string $intervalCode, array $campaignOpens, array $campaignClicks, string $dateCode, bool $hour = false): array
273 - {
274 - $opens = [];
275 - foreach ($campaignOpens as $one) {
276 - if (!empty($one->open_date)) {
277 - $opens[acym_date(acym_getTimeFromUTCDate($one->open_date), $dateCode)] = $one->open;
278 - }
279 - }
280 -
281 - $clicks = [];
282 - foreach ($campaignClicks as $one) {
283 - if (!empty($one->date_click)) {
284 - $clicks[acym_date(acym_getTimeFromUTCDate($one->date_click), $dateCode)] = $one->click;
285 - }
286 - }
287 -
288 - $startDate = $campaignOpens[0]->open_date ?? null;
289 - if (!empty($campaignClicks) && !empty($campaignClicks[0]->date_click)) {
290 - $clickDate = $campaignClicks[0]->date_click;
291 - if (!empty($startDate)) {
292 - $startDate = min([$startDate, $clickDate]);
293 - } else {
294 - $startDate = $clickDate;
295 - }
296 - }
297 -
298 - $lastOpen = end($campaignOpens);
299 - $endDate = $lastOpen->open_date ?? null;
300 - if (!empty($campaignClicks)) {
301 - $lastClick = end($campaignClicks);
302 - $clickDate = $lastClick->date_click ?? null;
303 - if (!empty($endDate) && !empty($clickDate)) {
304 - $endDate = max([$endDate, $clickDate]);
305 - } elseif (!empty($clickDate)) {
306 - $endDate = $clickDate;
307 - }
308 - }
309 -
310 - if (empty($startDate) || empty($endDate)) {
311 - return [];
312 - }
313 -
314 - if ($modifier === 'min') {
315 - $startDate = acym_date(strtotime($startDate) + date('Z'), 'Y-m-d H:i:s');
316 - $endDate = acym_date(strtotime($endDate) + date('Z'), 'Y-m-d H:i:s');
317 - }
318 -
319 - $begin = new \DateTime($startDate);
320 - $end = new \DateTime($endDate);
321 -
322 - $end->modify('+1 '.$modifier);
323 -
324 - $interval = new \DateInterval($intervalCode);
325 - $daterange = new \DatePeriod($begin, $interval, $end);
326 -
327 - $result = [];
328 - foreach ($daterange as $date) {
329 - $one = $date->format($dateCode);
330 -
331 - $current = [];
332 - $current['open'] = empty($opens[$one]) ? 0 : $opens[$one];
333 - $current['click'] = empty($clicks[$one]) ? 0 : $clicks[$one];
334 -
335 - $key = $hour ? $one.':00' : $one;
336 - $result[$key] = $current;
337 - }
338 -
339 - return $result;
340 - }
341 -
342 - public function prepareLineChart(object &$statsCampaignSelected, array $mailIdsOfCampaign, string $newStart = '', string $newEnd = ''): void
343 - {
344 - $campaignClass = new CampaignClass();
345 - $statsCampaignSelected->hasStats = true;
346 -
347 - $campaignOpenByMonth = $campaignClass->getOpenByMonth($mailIdsOfCampaign, $newStart, $newEnd);
348 - $campaignOpenByDay = $campaignClass->getOpenByDay($mailIdsOfCampaign, $newStart, $newEnd);
349 - $campaignOpenByHour = $campaignClass->getOpenByHour($mailIdsOfCampaign, $newStart, $newEnd);
350 -
351 - if (empty($campaignOpenByMonth) || empty($campaignOpenByDay) || empty($campaignOpenByHour)) {
352 - $statsCampaignSelected->hasStats = false;
353 -
354 - return;
355 - }
356 -
357 - $urlClickClass = new UrlClickClass();
358 - $campaignClickByMonth = $urlClickClass->getAllClickByMailMonth($mailIdsOfCampaign, $newStart, $newEnd);
359 - $campaignClickByDay = $urlClickClass->getAllClickByMailDay($mailIdsOfCampaign, $newStart, $newEnd);
360 - $campaignClickByHour = $urlClickClass->getAllClickByMailHour($mailIdsOfCampaign, $newStart, $newEnd);
361 -
362 - $statsCampaignSelected->month = $this->getValues('day', 'P1M', $campaignOpenByMonth, $campaignClickByMonth, 'Y-m');
363 - $statsCampaignSelected->day = $this->getValues('hour', 'P1D', $campaignOpenByDay, $campaignClickByDay, 'Y-m-d');
364 - $statsCampaignSelected->hour = $this->getValues('min', 'PT1H', $campaignOpenByHour, $campaignClickByHour, 'Y-m-d H:i', true);
365 -
366 - $allHour = array_keys($statsCampaignSelected->hour);
367 -
368 - $statsCampaignSelected->startEndDateHour = [];
369 - if (!empty($allHour)) {
370 - $statsCampaignSelected->startEndDateHour['start'] = $allHour[0];
371 - $statsCampaignSelected->startEndDateHour['end'] = end($allHour);
372 - }
373 - }
374 -
375 - public function exportGlobal(): void
376 - {
377 - $exportType = acym_getVar('string', 'export_type', 'charts');
378 -
379 - $functionName = 'exportGlobal'.ucfirst($exportType);
380 -
381 - if (!method_exists($this, $functionName)) {
382 - acym_enqueueMessage(acym_translation('ACYM_EXPORT_METHOD_NOT_FOUND'), 'error');
383 - $this->listing();
384 -
385 - return;
386 - }
387 -
388 - $this->$functionName();
389 - }
390 -
391 - public function prepareOpenTimeChart(array &$data): void
392 - {
393 - $userStatClass = new UserStatClass();
394 - $statsDB = $userStatClass->getOpenTimeStats($this->selectedMailIds);
395 -
396 - if (empty($statsDB['total_open'])) {
397 - $data['openTime'] = $userStatClass->getDefaultStat();
398 - $data['empty_open'] = true;
399 -
400 - return;
401 - }
402 -
403 - $data['empty_open'] = false;
404 -
405 - $stats = [];
406 -
407 - for ($day = 0; $day < 7; $day++) {
408 - $stats[$day] = [];
409 - for ($hour = 0; $hour < 8; $hour++) {
410 - if (empty($statsDB['stats'][$day.'_'.$hour])) {
411 - $percentage = 0;
412 - } else {
413 - $percentage = ($statsDB['stats'][$day.'_'.$hour]->open_total * 100) / $statsDB['total_open'];
414 - }
415 - $stats[$day][$hour] = round($percentage);
416 - }
417 - }
418 -
419 - $data['openTime'] = $stats;
420 - }
421 -
422 - public function prepareStatByList(array &$data): void
423 - {
424 - $mailid = (count(array_unique($data['selectedMailid'])) != 1) ? 0 : $data['selectedMailid'][0];
425 -
426 - if (empty($mailid)) {
427 - return;
428 - }
429 -
430 - $mailSelected = $this->getVarFiltersListing('int', 'mail_id_language', $mailid);
431 -
432 - $mailClass = new MailClass();
433 - $mail = $mailClass->getOneById($mailSelected);
434 - $mainMailId = empty($mail->parent_id) ? $mail->id : $mail->parent_id;
435 -
436 - $data['lists'] = [];
437 - $data['emailsSent'] = [];
438 - $data['emailsOpen'] = [];
439 - $data['bounces'] = [];
440 - $data['unsubscribed'] = [];
441 - $data['click'] = [];
442 - $data['listsStats'] = [];
443 - $data['userPerList'] = [];
444 -
445 - $query = 'SELECT l.id, l.name, l.color FROM #__acym_list l';
446 - $query .= ' JOIN #__acym_mail_has_list ml on l.id = ml.list_id';
447 - $query .= ' WHERE ml.mail_id = '.$mainMailId;
448 -
449 - $data['lists'] = acym_loadObjectList($query, 'id');
450 - $listIds = implode(',', array_keys($data['lists']));
451 -
452 - if (!empty($listIds)) {
453 - $query = 'SELECT ul.list_id, SUM(us.sent) as nbSent, SUM(IF(us.open >= 1, 1, 0)) as nbOpen, SUM(us.bounce) as nbBounce, SUM(us.unsubscribe) as nbUnsub from #__acym_user_has_list ul';
454 - $query .= ' JOIN #__acym_user_stat us on ul.user_id = us.user_id';
455 - $query .= ' WHERE ul.list_id in ('.$listIds.') AND us.mail_id = '.$mailSelected;
456 - $query .= ' GROUP BY ul.list_id;';
457 - $data['listsStats'] = acym_loadObjectList($query, 'list_id');
458 -
459 - $query = 'SELECT ul.list_id, COUNT(uc.click) as nbClick';
460 - $query .= ' FROM #__acym_user_has_list ul ';
461 - $query .= ' JOIN #__acym_url_click uc on ul.user_id = uc.user_id';
462 - $query .= ' WHERE ul.list_id in ('.$listIds.') AND uc.mail_id = '.$mailSelected;
463 - $query .= ' GROUP BY ul.list_id;';
464 -
465 - $data['nbClick'] = acym_loadObjectList($query, 'list_id');
466 -
467 - $query = 'SELECT ul.list_id, COUNT(ul.user_id) as nbUser';
468 - $query .= ' FROM #__acym_user_has_list ul';
469 - $query .= ' JOIN #__acym_user_stat us ON ul.user_id = us.user_id';
470 - $query .= ' WHERE ul.list_id in ('.$listIds.') AND us.mail_id = '.$mailSelected;
471 - $query .= ' GROUP BY ul.list_id;';
472 -
473 - $data['userPerList'] = acym_loadObjectList($query, 'list_id');
474 - }
475 -
476 - foreach ($data['listsStats'] as $listId => $item) {
477 - $nbSent = empty($item->nbSent) ? 1 : $item->nbSent;
478 -
479 - $data['emailsSent'][$listId] = [
480 - 'label' => $data['lists'][$listId]->name,
481 - 'value' => $item->nbSent,
482 - 'color' => $data['lists'][$listId]->color,
483 - ];
484 - $data['emailsOpen'][$listId] = [
485 - 'label' => $data['lists'][$listId]->name,
486 - 'value' => round(($item->nbOpen * 100) / $nbSent),
487 - 'color' => $data['lists'][$listId]->color,
488 - ];
489 - $data['bounces'][$listId] = [
490 - 'label' => $data['lists'][$listId]->name,
491 - 'value' => round(($item->nbBounce * 100) / $nbSent),
492 - 'color' => $data['lists'][$listId]->color,
493 - ];
494 - $data['unsubscribed'][$listId] = [
495 - 'label' => $data['lists'][$listId]->name,
496 - 'value' => round(($item->nbUnsub * 100) / $nbSent),
497 - 'color' => $data['lists'][$listId]->color,
498 - ];
499 - }
500 -
501 - foreach ($data['userPerList'] as $listId => $item) {
502 - $nbUser = $item->nbUser;
503 - $data['click'][$listId] = ['label' => $data['lists'][$listId]->name, 'value' => 0, 'color' => $data['lists'][$listId]->color];
504 -
505 - if ($nbUser > 0 && !empty($data['nbClick'][$listId]->nbClick)) {
506 - $data['click'][$listId]['value'] = round(($data['nbClick'][$listId]->nbClick * 100) / $nbUser);
507 - }
508 - }
509 - }
510 -
511 - private function prepareAbTestMails(array &$data): void
512 - {
513 - if (empty($this->selectedMailIds)) return;
514 -
515 - $mailClass = new MailClass();
516 -
517 - $mailVersions = [];
518 -
519 - if (empty($data['mailInformation']->parent_id)) {
520 - $mailVersions = $mailClass->getParentAndChildMails($data['mailInformation']->id);
521 - } elseif (!empty($data['mailInformation']->parent_id)) {
522 - $parentEmail = $mailClass->getOneById($data['mailInformation']->parent_id);
523 - if (empty($parentEmail)) return;
524 - $mailVersions = $mailClass->getParentAndChildMails($parentEmail->id);
525 - }
526 -
527 - $data['emailVersions'] = [];
528 -
529 - foreach ($mailVersions as $email) {
530 - $data['emailVersions'][$email->id] = $email->name.' - '.$email->subject;
531 - }
532 - }
533 -
534 - private function prepareMultilingualMails(array &$data): void
535 - {
536 - if (empty($this->selectedMailIds)) return;
537 -
538 - $mailClass = new MailClass();
539 -
540 - $translatedEmails = [];
541 -
542 - if (empty($data['mailInformation']->parent_id)) {
543 - $translatedEmails = $mailClass->getTranslationsById($data['mailInformation']->id, true, true);
544 - } elseif (!empty($data['mailInformation']->parent_id)) {
545 - $parentEmail = $mailClass->getOneById($data['mailInformation']->parent_id);
546 - if (empty($parentEmail)) return;
547 - $translatedEmails = $mailClass->getTranslationsById($parentEmail->id, true, true);
548 - }
549 -
550 - $data['emailTranslations'] = [];
551 - $allLanguages = acym_getLanguages();
552 -
553 - foreach ($translatedEmails as $email) {
554 - if (!empty($email->language)) {
555 - $data['emailTranslations'][$email->id] = empty($allLanguages[$email->language]) ? $email->language
556 - : $allLanguages[$email->language]->name;
557 - }
558 - }
559 - }
560 -
561 - private function prepareDevicesStats(array &$data): void
562 - {
563 - $campaignClass = new CampaignClass();
564 - $devicesCampaign = $campaignClass->getDevicesWithCountByMailId($this->selectedMailIds);
565 -
566 - $defaultDataDevices = [
567 - 'ACYM_MOBILE' => 0,
568 - 'ACYM_DESKTOP' => 0,
569 - 'ACYM_OTHER' => 0,
570 - 'ACYM_UNKNOWN' => 0,
571 - ];
572 - $data['devices'] = $defaultDataDevices;
573 -
574 - foreach ($devicesCampaign as $oneDevice) {
575 - if (empty($oneDevice->number)) {
576 - continue;
577 - }
578 -
579 - if (empty($oneDevice->device)) {
580 - $device = 'ACYM_UNKNOWN';
581 - } elseif (in_array($oneDevice->device, array_merge(BrowserDetection::PLATFORMS_MOBILE, BrowserDetection::LEGACY_PLATFORMS_MOBILE))) {
582 - $device = 'ACYM_MOBILE';
583 - } elseif (in_array($oneDevice->device, array_merge(BrowserDetection::PLATFORMS_DESKTOP, BrowserDetection::LEGACY_PLATFORMS_DESKTOP))) {
584 - $device = 'ACYM_DESKTOP';
585 - } else {
586 - $device = 'ACYM_OTHER';
587 - }
588 -
589 - $data['devices'][$device] += $oneDevice->number;
590 - }
591 -
592 - if ($data['devices'] === $defaultDataDevices) {
593 - $data['devices'] = [];
594 - }
595 - }
596 -
597 - private function prepareOpenSourcesStats(array &$data): void
598 - {
599 - $userStatClass = new UserStatClass();
600 - $openedFromStats = $userStatClass->getOpenSourcesStats($this->selectedMailIds);
601 -
602 - $data['openedWith'] = [];
603 - foreach ($openedFromStats as $oneSource) {
604 - if (empty($oneSource->number)) {
605 - continue;
606 - }
607 -
608 - if (!empty($oneSource->opened_with) && isset(BrowserDetection::LEGACY_OPENED_WITH_MAP[$oneSource->opened_with])) {
609 - $oneSource->opened_with = BrowserDetection::LEGACY_OPENED_WITH_MAP[$oneSource->opened_with];
610 - }
611 -
612 - if (empty($oneSource->opened_with)) {
613 - $oneSource->opened_with = 'ACYM_UNKNOWN';
614 - }
615 -
616 - $data['openedWith'][$oneSource->opened_with] = $oneSource->number;
617 - }
618 - }
619 -
620 - public function preparecharts(array &$data): void
621 - {
622 - $mailStatClass = new MailStatClass();
623 -
624 - $data['mail'] = $mailStatClass->getSentFailByMailIds($this->selectedMailIds);
625 - if (empty($data['mail'])) return;
626 -
627 - $campaignClass = new CampaignClass();
628 - $urlClickClass = new UrlClickClass();
629 -
630 - $data['mail']->totalMail = $data['mail']->sent + $data['mail']->fail;
631 - $data['mail']->percentageSent = empty($data['mail']->totalMail) ? 0 : number_format(($data['mail']->sent * 100) / $data['mail']->totalMail, 2);
632 - $data['mail']->allSent = empty($data['mail']->totalMail)
633 - ? acym_translationSprintf('ACYM_X_MAIL_SUCCESSFULLY_SENT_OF_X', 0, 0)
634 - : acym_translationSprintf(
635 - 'ACYM_X_MAIL_SUCCESSFULLY_SENT_OF_X',
636 - $data['mail']->sent,
637 - $data['mail']->totalMail
638 - );
639 -
640 - $openRateCampaign = empty($this->selectedMailIds) ? $campaignClass->getOpenRateAllCampaign() : $campaignClass->getOpenRateCampaigns($this->selectedMailIds);
641 - $data['mail']->percentageOpen = empty($openRateCampaign->sent) ? 0 : number_format(($openRateCampaign->open_unique * 100) / $openRateCampaign->sent, 2);
642 - $data['mail']->allOpen = empty($openRateCampaign->sent)
643 - ? acym_translationSprintf('ACYM_X_MAIL_OPENED_OF_X', 0, 0)
644 - : acym_translationSprintf(
645 - 'ACYM_X_MAIL_OPENED_OF_X',
646 - $openRateCampaign->open_unique,
647 - $openRateCampaign->sent
648 - );
649 -
650 - $clickRateCampaign = $urlClickClass->getNumberUsersClicked($this->selectedMailIds);
651 - $data['mail']->percentageClick = empty($data['mail']->sent) ? 0 : number_format(($clickRateCampaign * 100) / $data['mail']->sent, 2);
652 - $data['mail']->allClick = empty($data['mail']->sent)
653 - ? acym_translationSprintf('ACYM_X_MAIL_CLICKED_OF_X', 0, 0)
654 - : acym_translationSprintf(
655 - 'ACYM_X_MAIL_CLICKED_OF_X',
656 - $clickRateCampaign,
657 - $data['mail']->sent
658 - );
659 -
660 - $bounceRateCampaign = empty($this->selectedMailIds) ? $campaignClass->getBounceRateAllCampaign() : $campaignClass->getBounceRateCampaigns($this->selectedMailIds);
661 - $data['mail']->percentageBounce = empty($data['mail']->sent) ? 0 : number_format(($bounceRateCampaign->bounce_unique * 100) / $data['mail']->sent, 2);
662 - $data['mail']->allBounce = empty($data['mail']->sent)
663 - ? acym_translationSprintf('ACYM_X_BOUNCE_OF_X', 0, 0)
664 - : acym_translationSprintf(
665 - 'ACYM_X_BOUNCE_OF_X',
666 - $bounceRateCampaign->bounce_unique,
667 - $data['mail']->sent
668 - );
669 -
670 - if (!empty($this->selectedMailIds)) {
671 - $mailStat = $mailStatClass->getByMailIds($this->selectedMailIds);
672 - $data['mail']->allUnsub = 0;
673 - $data['mail']->percentageUnsub = 0;
674 - if (!empty($mailStat)) {
675 - $data['mail']->percentageUnsub = empty($data['mail']->sent) ? 0 : number_format(($mailStat->unsubscribe_total * 100) / $data['mail']->sent, 2);
676 - $data['mail']->allUnsub = empty($data['mail']->sent)
677 - ? acym_translationSprintf('ACYM_X_USERS_UNSUBSCRIBED_OF_X', 0, 0)
678 - : acym_translationSprintf(
679 - 'ACYM_X_USERS_UNSUBSCRIBED_OF_X',
680 - $mailStat->unsubscribe_total,
681 - $data['mail']->sent
682 - );
683 - }
684 - }
685 -
686 - $this->prepareDevicesStats($data);
687 - $this->prepareOpenSourcesStats($data);
688 - $this->prepareLineChart($data['mail'], $this->selectedMailIds);
689 - $this->prepareComparedStats($data);
690 - }
691 -
692 - private function decode(array &$detailedStats, array $columnsToDecode = ['mail_subject', 'mail_name']): void
693 - {
694 - foreach ($detailedStats as $oneDetailedStat) {
695 - foreach ($columnsToDecode as $column) {
696 - if (!empty($oneDetailedStat->$column)) {
697 - $oneDetailedStat->$column = acym_utf8Decode($oneDetailedStat->$column);
698 - }
699 - }
700 - }
701 - }
702 -
703 - private function prepareLinksDetailsListing(array &$data): void
704 - {
705 - $data['search'] = $this->getVarFiltersListing('string', 'links_details_search', '');
706 - $data['ordering'] = $this->getVarFiltersListing('string', 'links_details_ordering', 'id');
707 - $data['orderingSortOrder'] = $this->getVarFiltersListing('string', 'links_details_ordering_sort_order', 'desc');
708 -
709 - if (empty($this->selectedMailIds)) return;
710 -
711 - $pagination = new PaginationHelper();
712 - $urlClickClass = new UrlClickClass();
713 -
714 - $detailedStatsPerPage = $pagination->getListLimit();
715 - $page = $this->getVarFiltersListing('int', 'links_details_pagination_page', 1);
716 -
717 - $urlClicks = $urlClickClass->getUrlsFromMailsWithDetails(
718 - [
719 - 'ordering' => $data['ordering'],
720 - 'search' => $data['search'],
721 - 'detailedStatsPerPage' => $detailedStatsPerPage,
722 - 'offset' => ($page - 1) * $detailedStatsPerPage,
723 - 'ordering_sort_order' => $data['orderingSortOrder'],
724 - 'mail_ids' => $this->selectedMailIds,
725 - ]
726 - );
727 -
728 - $this->decode($urlClicks['links_details']);
729 -
730 - $pagination->setStatus((int)$urlClicks['total']->total, $page, $detailedStatsPerPage);
731 -
732 - $data['pagination'] = $pagination;
733 - $data['links_details'] = $urlClicks['links_details'];
734 - $data['query'] = $urlClicks['query'];
735 - }
736 -
737 - private function prepareListReceivers(array &$data): void
738 - {
739 - if (empty($this->selectedMailIds)) return;
740 -
741 - $mailStatClass = new MailStatClass();
742 - $mailClass = new MailClass();
743 -
744 - $data['mailStat'] = $mailStatClass->getByMailIds($this->selectedMailIds);
745 - $data['lists'] = $mailClass->getAllListsByMailId($this->selectedMailIds[0]);
746 - }
747 -
748 - private function exportGlobalFormatted(): void
749 - {
750 - $exportHelper = new ExportHelper();
751 - $data = [];
752 - $this->prepareDefaultPageInfo($data);
753 - $data['show_date_filters'] = true;
754 - $data['page_title'] = false;
755 - $timeLinechart = acym_getVar('string', 'time_linechart', 'month');
756 -
757 -
758 - $this->prepareMailFilter($data);
759 - $this->prepareClickStats($data);
760 - $this->preparecharts($data);
761 - $this->prepareDefaultRoundCharts($data);
762 - $this->prepareDefaultLineChart($data);
763 - $this->prepareDefaultDevicesChart($data);
764 - $this->prepareDefaultBrowsersChart($data);
765 -
766 - $globalDonut = [
767 - $data['mail']->percentageSent,
768 - $data['mail']->percentageOpen,
769 - $data['mail']->percentageClick,
770 - $data['mail']->percentageBounce,
771 - $data['mail']->percentageUnsub,
772 - ];
773 - $mailName = empty($this->selectedMailIds) ? acym_translation('ACYM_ALL_MAILS') : $data['mailInformation']->name;
774 - $globalLine = $data['mail']->$timeLinechart;
775 -
776 - $exportHelper->exportStatsFormattedCSV($mailName, $globalDonut, $globalLine, $timeLinechart);
777 - exit;
778 - }
779 -
780 - private function exportGlobalFull(): void
781 - {
782 - $exportHelper = new ExportHelper();
783 - $data = [];
784 - $this->prepareDefaultPageInfo($data);
785 -
786 - $where = '';
787 - if (!empty($this->selectedMailIds)) {
788 - $where = 'WHERE mail_id IN ('.implode(',', $this->selectedMailIds).')';
789 - }
790 -
791 - $columnsMailStat = acym_getColumns('mail_stat');
792 - $columnsToExport = [];
793 -
794 - $columnsToExport['mail.subject'] = acym_translation('ACYM_EMAIL_SUBJECT');
795 - foreach ($columnsMailStat as $column) {
796 - if ($column === 'mail_id') {
797 - continue;
798 - }
799 -
800 - $translation = acym_translation('ACYM_'.strtoupper($column).'_COLUMN_STAT');
801 - if ($column === 'send_date') {
802 - $translation = acym_translation('ACYM_SEND_DATE');
803 - } elseif ($column === 'click_total') {
804 - $translation = acym_translation('ACYM_TOTAL_CLICKS');
805 - } elseif ($column === 'click_unique') {
806 - $translation = acym_translation('ACYM_UNIQUE_CLICKS');
807 - }
808 -
809 - $columnsToExport['mailstat.'.$column] = $translation;
810 - }
811 -
812 - $query = 'SELECT '.implode(', ', array_keys($columnsToExport)).' FROM #__acym_mail_stat AS mailstat LEFT JOIN #__acym_mail AS mail ON mail.id = mailstat.mail_id '.$where;
813 - $exportHelper->exportStatsFullCSV($query, $columnsToExport);
814 - exit;
815 - }
816 -
817 - private function prepareComparedStats(array &$data): void
818 - {
819 - if (empty($data['totalSubscribers']) || empty($data['mail']->percentageOpen) || empty($data['mail']->percentageClick) || empty($data['mail']->percentageBounce)) {
820 - return;
821 - }
822 -
823 - $currentDate = acym_date('now', 'Y-m-d');
824 -
825 - $newStats = [
826 - 'date' => $currentDate,
827 - 'value' => [
828 - 'totalSubscribers' => $data['totalSubscribers'],
829 - 'openRate' => $data['mail']->percentageOpen,
830 - 'clickRate' => $data['mail']->percentageClick,
831 - 'bounceRate' => $data['mail']->percentageBounce,
832 - 'totalNewSubscribers' => $data['totalSubscribers'],
833 - ],
834 - ];
835 -
836 - $keys = [
837 - 'totalSubscribersHistory' => true,
838 - 'percentageOpenHistory' => false,
839 - 'percentageClickHistory' => false,
840 - 'percentageBounceHistory' => false,
841 - 'totalNewSubscribersHistory' => false,
842 - ];
843 -
844 - $oldEvolutionData = json_decode($this->config->get('statsEvolution', '{}'), true);
845 -
846 - foreach ($keys as $key => $isPercentage) {
847 - $history = json_decode($this->config->get($key, '[]'), true);
848 -
849 - if (!empty($history) && end($history)['date'] === $currentDate) {
850 - continue;
851 - }
852 -
853 - $history[] = ['date' => $currentDate, 'value' => $newStats['value'][$this->getStatKey($key)]];
854 -
855 - if (count($history) > 30) {
856 - array_shift($history);
857 - }
858 -
859 - $this->config->saveConfig([$key => json_encode($history)]);
860 -
861 - $evolutionKey = $this->getEvolutionKey($key);
862 - $oldEvolutionData[$evolutionKey] = $this->calculateEvolution($history, $isPercentage);
863 - }
864 -
865 - $this->config->saveConfig(['statsEvolution' => json_encode($oldEvolutionData)]);
866 -
867 - if (!empty($data)) {
868 - $this->updateDashboardData($data);
869 - }
870 - }
871 -
872 - private function getStatKey(string $key): ?string
873 - {
874 - return [
875 - 'totalSubscribersHistory' => 'totalSubscribers',
876 - 'percentageOpenHistory' => 'openRate',
877 - 'percentageClickHistory' => 'clickRate',
878 - 'percentageBounceHistory' => 'bounceRate',
879 - 'totalNewSubscribersHistory' => 'totalNewSubscribers',
880 - ][$key] ?? null;
881 - }
882 -
883 - private function getEvolutionKey(string $key): ?string
884 - {
885 - return [
886 - 'totalSubscribersHistory' => 'totalSubscribersEvolution',
887 - 'percentageOpenHistory' => 'openRateEvolution',
888 - 'percentageClickHistory' => 'clickRateEvolution',
889 - 'percentageBounceHistory' => 'bounceRateEvolution',
890 - 'totalNewSubscribersHistory' => 'totalNewSubscribersEvolution',
891 - ][$key] ?? null;
892 - }
893 -
894 - private function calculateEvolution(array $history, bool $isPercentage = false): ?float
895 - {
896 - if (empty($history)) {
897 - return null;
898 - }
899 -
900 - $oldValue = $history[0]['value'] ?? 0;
901 - $newValue = end($history)['value'] ?? 0;
902 -
903 - if ($oldValue === 0) {
904 - return null;
905 - }
906 -
907 - if ($isPercentage) {
908 - return round((($newValue - $oldValue) / $oldValue) * 100, 2);
909 - } else {
910 - return round($newValue - $oldValue, 2);
911 - }
912 - }
913 -
914 - private function updateDashboardData(array &$data): void
915 - {
916 - $evolutionData = json_decode($this->config->get('statsEvolution', '{}'), true);
917 -
918 - if (!empty($evolutionData)) {
919 - $data['totalSubscribersEvolution'] = $evolutionData['totalSubscribersEvolution'] ?? null;
920 - $data['openRateEvolution'] = $evolutionData['openRateEvolution'] ?? null;
921 - $data['clickRateEvolution'] = $evolutionData['clickRateEvolution'] ?? null;
922 - $data['bounceRateEvolution'] = $evolutionData['bounceRateEvolution'] ?? null;
923 - $data['totalNewSubscribersEvolution'] = $evolutionData['totalNewSubscribersEvolution'] ?? null;
924 - }
925 - }
926 -}