PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.11.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.11.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
acymailing / back / Classes / UserStatClass.php

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

343 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace AcyMailing\Classes;
4
5 use AcyMailing\Helpers\ScenarioHelper;
6 use AcyMailing\Core\AcymClass;
7
8 class UserStatClass extends AcymClass
9 {
10 public function __construct()
11 {
12 parent::__construct();
13
14 $this->table = 'user_stat';
15 }
16
17 public function save(object $element, bool $overrideSendDate = false): ?int
18 {
19 $userStat = get_object_vars($element);
20
21 $column = [];
22 $valueColumn = [];
23 $columnName = acym_getColumns('user_stat');
24
25 foreach ($userStat as $key => $value) {
26 if (in_array($key, $columnName)) {
27 $column[] = '`'.acym_secureDBColumn($key).'`';
28
29 if ($key === 'tracking_sale') {
30 $valueColumn[] = strlen($value) === 0 ? 'NULL' : floatval($value);
31 } else {
32 $valueColumn[] = acym_escapeDB($value);
33 }
34 }
35 }
36
37 $query = 'INSERT INTO #__acym_user_stat ('.implode(',', $column).') VALUE ('.implode(', ', $valueColumn).')';
38 $onDuplicate = [];
39
40 if (!empty($userStat['statusSending'])) {
41 $onDuplicate[] = $userStat['statusSending'] == 0 ? 'fail = fail + 1' : 'sent = sent + 1';
42 }
43
44 if ($overrideSendDate && !empty($userStat['send_date'])) {
45 $onDuplicate[] = 'send_date = '.acym_escapeDB($userStat['send_date']);
46 }
47
48 if (!empty($userStat['open'])) {
49 $onDuplicate[] = 'open = open + 1';
50 $automationClass = new AutomationClass();
51 $automationClass->trigger('user_open', ['userId' => $userStat['user_id'], 'mailId' => $userStat['mail_id']]);
52
53 $scenarioHelper = new ScenarioHelper();
54 $scenarioHelper->trigger('user_open', ['userId' => $userStat['user_id'], 'mailId' => $userStat['mail_id']]);
55 }
56
57 if (!empty($userStat['open_date'])) {
58 $onDuplicate[] = 'open_date = '.acym_escapeDB($userStat['open_date']);
59 }
60
61 if (!empty($userStat['tracking_sale'])) {
62 $onDuplicate[] = 'tracking_sale = '.floatval($userStat['tracking_sale']);
63 }
64
65 if (!empty($userStat['currency'])) {
66 $onDuplicate[] = 'currency = '.acym_escapeDB($userStat['currency']);
67 }
68
69 if (!empty($userStat['unsubscribe'])) {
70 $onDuplicate[] = 'unsubscribe = '.intval($userStat['unsubscribe']);
71 }
72
73 if (!empty($userStat['device'])) {
74 $onDuplicate[] = 'device = '.acym_escapeDB($userStat['device']);
75 }
76
77 if (!empty($userStat['opened_with'])) {
78 $onDuplicate[] = 'opened_with = '.acym_escapeDB($userStat['opened_with']);
79 }
80
81 if (!empty($onDuplicate)) {
82 $query .= ' ON DUPLICATE KEY UPDATE ';
83 $query .= implode(',', $onDuplicate);
84 }
85
86 return (int)acym_query($query);
87 }
88
89 public function getOneByMailAndUserId(int $mailId, int $userId): ?object
90 {
91 $userStat = acym_loadObject('SELECT * FROM #__acym_user_stat WHERE `mail_id` = '.intval($mailId).' AND `user_id` = '.intval($userId));
92
93 return empty($userStat) ? null : $userStat;
94 }
95
96 public function getDetailedStatistics(array $options): array
97 {
98 $limit = $options['limit'] ?? 10;
99 $offset = $options['offset'] ?? 0;
100 $mailId = $options['mail_id'] ?? 0;
101
102 return acym_loadObjectList(
103 'SELECT user_stat.*, `user`.email
104 FROM #__acym_user_stat AS user_stat
105 JOIN #__acym_user AS `user` ON user_stat.user_id = `user`.id
106 WHERE `mail_id` = '.intval($mailId),
107 '',
108 $offset,
109 $limit
110 );
111 }
112
113 public function getAllUserStatByUserId(int $userId): array
114 {
115 return acym_loadObjectList(
116 'SELECT userStat.*, mail.subject
117 FROM #__acym_user_stat AS userStat
118 JOIN #__acym_mail AS mail ON mail.id = userStat.mail_id
119 WHERE userStat.user_id = '.intval($userId)
120 );
121 }
122
123 public function getDetailedStats(array $settings): array
124 {
125 $mailClass = new MailClass();
126
127 $query = 'SELECT us.*, m.name, m.subject, m.parent_id, u.email, u.name AS username
128 FROM #__acym_user_stat AS us
129 LEFT JOIN #__acym_user AS u ON us.user_id = u.id
130 INNER JOIN #__acym_mail AS m ON us.mail_id = m.id';
131 $queryCount = 'SELECT COUNT(*) AS total FROM #__acym_user_stat as us
132 LEFT JOIN #__acym_user AS u ON us.user_id = u.id
133 INNER JOIN #__acym_mail AS m ON us.mail_id = m.id';
134 $where = [];
135
136 if (!empty($settings['mail_ids'])) {
137 if (!is_array($settings['mail_ids'])) $settings['mail_ids'] = [$settings['mail_ids']];
138 acym_arrayToInteger($settings['mail_ids']);
139 $where[] = 'us.mail_id IN ('.implode(',', $settings['mail_ids']).')';
140 }
141
142 if (!empty($settings['search'])) {
143 $searchTerms = acym_escapeDB('%'.$settings['search'].'%');
144 $where[] = 'm.name LIKE '.$searchTerms.' OR u.email LIKE '.$searchTerms.' OR u.name LIKE '.$searchTerms;
145 }
146
147 if (!empty($where)) {
148 $query .= ' WHERE ('.implode(') AND (', $where).')';
149 $queryCount .= ' WHERE ('.implode(') AND (', $where).')';
150 }
151
152 if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) {
153 if (in_array($settings['ordering'], ['email', 'name'])) {
154 $table = 'u';
155 } elseif ($settings['ordering'] === 'subject') {
156 $table = 'm';
157 } else {
158 $table = 'us';
159 }
160 $query .= ' ORDER BY '.$table.'.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn(strtoupper($settings['ordering_sort_order'])).', us.user_id ASC';
161 }
162
163 $mails = acym_loadObjectList($query, '', $settings['offset'], $settings['detailedStatsPerPage']);
164
165 if (!empty($mails)) {
166 if (acym_isTrackingSalesActive()) {
167 $mailIds = [];
168 foreach ($mails as $mail) {
169 if (!in_array($mail->mail_id, $mailIds)) $mailIds[] = $mail->mail_id;
170 }
171
172 $trackingSales = [];
173 $trackingSalesDB = acym_loadObjectList(
174 'SELECT SUM(tracking_sale) as sale, currency, mail_id, user_id FROM #__acym_user_stat WHERE mail_id IN ('.implode(
175 ',',
176 $mailIds
177 ).') AND currency IS NOT NULL GROUP BY user_id, mail_id'
178 );
179 foreach ($trackingSalesDB as $oneMailTrackSales) {
180 $trackingSales[$oneMailTrackSales->mail_id.'-'.$oneMailTrackSales->user_id] = $oneMailTrackSales;
181 }
182 }
183
184 $totalClicksForMails = [];
185 $campaignsForMails = [];
186 foreach ($mails as $key => $mail) {
187 if (!empty($trackingSales[$mail->mail_id.'-'.$mail->user_id])) {
188 acym_trigger('getCurrency', [&$mails[$key]->currency]);
189 $mails[$key]->sales = $trackingSales[$mail->mail_id.'-'.$mail->user_id]->sale;
190 }
191
192 if (!isset($totalClicksForMails[$mail->mail_id])) {
193 $totalClicksForMails[$mail->mail_id] = acym_loadObjectList(
194 'SELECT SUM(click) AS nbClicks, user_id
195 FROM #__acym_url_click
196 WHERE mail_id = '.intval($mail->mail_id).'
197 GROUP BY user_id',
198 'user_id'
199 );
200 }
201 $mails[$key]->total_click = empty($totalClicksForMails[$mail->mail_id][$mail->user_id]) ? 0 : $totalClicksForMails[$mail->mail_id][$mail->user_id]->nbClicks;
202
203 $mainMailId = empty($mail->parent_id) ? $mail->mail_id : $mail->parent_id;
204 if (!isset($campaignsForMails[$mainMailId])) {
205 $campaignsForMails[$mainMailId] = acym_loadObject('SELECT id AS campaign_id, parent_id FROM #__acym_campaign WHERE mail_id = '.intval($mainMailId));
206 }
207
208 $mails[$key]->campaign_id = empty($campaignsForMails[$mainMailId]) ? 0 : $campaignsForMails[$mainMailId]->campaign_id;
209 $mails[$key]->parent_id = empty($campaignsForMails[$mainMailId]) ? 0 : $campaignsForMails[$mainMailId]->parent_id;
210 }
211 }
212
213 return [
214 'detailed_stats' => $mailClass->decode($mails),
215 'total' => acym_loadObject($queryCount),
216 ];
217 }
218
219 public function getOpenTimeStats(array $mailIds): array
220 {
221 acym_arrayToInteger($mailIds);
222 $specificMailsCondition = empty($mailIds) ? '' : ' AND mail_id in ('.implode(',', $mailIds).')';
223 $offsetSeconds = acym_getTimeOffsetCMS();
224
225 return [
226 'total_open' => acym_loadResult(
227 'SELECT SUM(`open`)
228 FROM #__acym_user_stat
229 WHERE open_date IS NOT NULL '.$specificMailsCondition
230 ),
231 'stats' => acym_loadObjectList(
232 'SELECT
233 SUM(`open`) AS `open_total`,
234 DATE_FORMAT(DATE_ADD(open_date, INTERVAL '.$offsetSeconds.' SECOND), "%w") AS `day`,
235 FORMAT(CONVERT(DATE_FORMAT(DATE_ADD(open_date, INTERVAL '.$offsetSeconds.' SECOND), "%H"), SIGNED INTEGER) / 3, 0) AS `hour`,
236 CONCAT(
237 DATE_FORMAT(DATE_ADD(open_date, INTERVAL '.$offsetSeconds.' SECOND), "%w"),
238 "_",
239 FORMAT(CONVERT(DATE_FORMAT(DATE_ADD(open_date, INTERVAL '.$offsetSeconds.' SECOND), "%H"), SIGNED INTEGER) / 3, 0)
240 ) AS `date_id`
241 FROM `#__acym_user_stat`
242 WHERE open_date IS NOT NULL '.$specificMailsCondition.'
243 GROUP BY date_id',
244 'date_id'
245 ),
246 ];
247 }
248
249 public function getDefaultStat(): array
250 {
251 $percentageRemaining = 100;
252 $stats = [];
253
254 for ($day = 0; $day < 7; $day++) {
255 $stats[$day] = [];
256 for ($hour = 0; $hour < 8; $hour++) {
257 $stats[$day][$hour] = $this->getRandomStatOpenTime($percentageRemaining, $hour);
258 }
259 }
260
261 return $stats;
262 }
263
264 public function getOpenSourcesStats(array $mailIds = []): array
265 {
266 acym_arrayToInteger($mailIds);
267
268 $query = 'SELECT opened_with, COUNT(*) AS number FROM #__acym_user_stat WHERE `open` > 0';
269 if (!empty($mailIds)) {
270 $query .= ' AND mail_id IN ('.implode(',', $mailIds).')';
271 }
272 $query .= ' GROUP BY opened_with';
273
274 return acym_loadObjectList($query);
275 }
276
277 public function deleteDetailedStatsPeriod(): array
278 {
279 $shouldClearExpiredStats = $this->config->get('delete_stats_enabled', 0);
280 if (empty($shouldClearExpiredStats)) {
281 return [];
282 }
283
284 $deleteAfterXSeconds = $this->config->get('delete_stats', 86400 * 360);
285 if (empty($deleteAfterXSeconds)) {
286 return [];
287 }
288
289 $date = acym_date(time() - $deleteAfterXSeconds, 'Y-m-d H:i', false);
290
291 $queries = [
292 '#__acym_user_stat' => 'DELETE FROM #__acym_user_stat WHERE send_date < '.acym_escapeDB($date),
293 '#__acym_url_click' => 'DELETE FROM #__acym_url_click WHERE date_click < '.acym_escapeDB($date),
294 ];
295
296 $messages = [];
297 foreach ($queries as $table => $query) {
298 try {
299 $status = acym_query($query);
300 if (!empty($status)) {
301 $messages[] = acym_translationSprintf('ACYM_DELETE_X_ROWS_TABLE_X', $status, acym_translation('ACYM_USER_DETAILED_STATS').' ('.$table.')');
302 }
303 } catch (\Exception $e) {
304 $messages[] = $e->getMessage();
305 }
306 }
307
308 if (empty($messages)) {
309 return [];
310 }
311
312 return ['message' => implode("\r\n", $messages)];
313 }
314
315 private function getRandomStatOpenTime(int &$percentageRemaining, int $hour): int
316 {
317 if (empty($percentageRemaining)) {
318 return 0;
319 }
320
321 $randoms = [
322 0 => [0, 1],
323 1 => [0, 2],
324 2 => [1, 2],
325 3 => [1, 3],
326 4 => [3, 5],
327 5 => [1, 3],
328 6 => [1, 2],
329 7 => [0, 2],
330 ];
331
332 $percentage = rand($randoms[$hour][0], $randoms[$hour][1]);
333
334 if ($percentageRemaining - $percentage < 0) {
335 return 0;
336 }
337
338 $percentageRemaining -= $percentage;
339
340 return $percentage;
341 }
342 }
343