| @@ -20,10 +20,8 @@ | ||
| 20 | 20 | self::SENDING_TYPE_AUTO, |
| 21 | 21 | ]; |
| 22 | 22 | const AB_TEST_VERSIONS = ['B']; |
| 23 | 23 | |
| 24 | - private array $jsonColumns = ['sending_params']; | |
| 25 | - | |
| 26 | 24 | public function __construct() |
| 27 | 25 | { |
| 28 | 26 | parent::__construct(); |
| 29 | 27 | |
| @@ -28,11 +26,25 @@ | ||
| 28 | 26 | parent::__construct(); |
| 29 | 27 | |
| 30 | 28 | $this->table = 'campaign'; |
| 31 | 29 | $this->pkey = 'id'; |
| 30 | + $this->jsonColumns = ['sending_params']; | |
| 31 | + $this->intColumns = [ | |
| 32 | + 'id', | |
| 33 | + 'mail_id', | |
| 34 | + 'parent_id', | |
| 35 | + 'draft', | |
| 36 | + 'active', | |
| 37 | + 'sent', | |
| 38 | + 'visible', | |
| 39 | + 'subscribers', | |
| 40 | + 'open_unique', | |
| 41 | + 'tracking_sale', | |
| 42 | + 'tracking', | |
| 43 | + ]; | |
| 32 | 44 | } |
| 33 | 45 | |
| 34 | - public function decode($campaign, $decodeMail = true) | |
| 46 | + public function decode($campaign, bool $decodeMail = true) | |
| 35 | 47 | { |
| 36 | 48 | if (empty($campaign)) return $campaign; |
| 37 | 49 | |
| 38 | 50 | if (is_array($campaign)) { |
| @@ -38,16 +50,12 @@ | ||
| 38 | 50 | if (is_array($campaign)) { |
| 39 | 51 | foreach ($campaign as $i => $oneCampaign) { |
| 40 | 52 | $campaign[$i] = $this->decode($oneCampaign, false); |
| 41 | 53 | } |
| 54 | + } else { | |
| 55 | + $this->fixTypes($campaign); | |
| 42 | 56 | } |
| 43 | 57 | |
| 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 | 58 | if ($decodeMail) { |
| 51 | 59 | $mailClass = new MailClass(); |
| 52 | 60 | $campaign = $mailClass->decode($campaign); |
| 53 | 61 | } |
| @@ -88,8 +96,9 @@ | ||
| 88 | 96 | if ($this->config->get('front_campaigns_filter', 'own') === 'allowed') { |
| 89 | 97 | $listClass = new ListClass(); |
| 90 | 98 | $allowedLists = $listClass->getManageableLists(); |
| 91 | 99 | if (!empty($allowedLists)) { |
| 100 | + acym_arrayToInteger($allowedLists); | |
| 92 | 101 | $query .= ' LEFT JOIN #__acym_mail_has_list AS mailList ON campaign.mail_id = mailList.mail_id AND mailList.list_id IN ('.implode(',', $allowedLists).')'; |
| 93 | 102 | $queryCount .= ' LEFT JOIN #__acym_mail_has_list AS mailList ON campaign.mail_id = mailList.mail_id AND mailList.list_id IN ('.implode(',', $allowedLists).')'; |
| 94 | 103 | $condition .= ' OR mailList.list_id IS NOT NULL'; |
| 95 | 104 | } |
| @@ -144,11 +153,12 @@ | ||
| 144 | 153 | } |
| 145 | 154 | |
| 146 | 155 | $query .= ' GROUP BY campaign.id'; |
| 147 | 156 | |
| 148 | - if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) { | |
| 157 | + if (!empty($settings['ordering'])) { | |
| 149 | 158 | $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'])); | |
| 159 | + $order = isset($settings['ordering_sort_order']) && strtolower($settings['ordering_sort_order']) === 'asc' ? 'ASC' : 'DESC'; | |
| 160 | + $query .= ' ORDER BY '.$table.'.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn($order); | |
| 151 | 161 | } |
| 152 | 162 | |
| 153 | 163 | if (empty($settings['offset']) || $settings['offset'] < 0) { |
| 154 | 164 | $settings['offset'] = 0; |
| @@ -228,9 +238,9 @@ | ||
| 228 | 238 | |
| 229 | 239 | return $results; |
| 230 | 240 | } |
| 231 | 241 | |
| 232 | - private function prepareStatsCampaign(&$element) | |
| 242 | + private function prepareStatsCampaign(object $element): void | |
| 233 | 243 | { |
| 234 | 244 | $query = 'SELECT SUM(mailstat.sent) AS subscribers, SUM(mailstat.open_unique) AS open_unique, SUM(mailstat.tracking_sale) AS tracking_sale |
| 235 | 245 | FROM #__acym_mail_stat AS mailstat |
| 236 | 246 | LEFT JOIN #__acym_mail AS mail ON mail.id = mailstat.mail_id WHERE mail.parent_id = '.intval($element->mail_id); |
| @@ -239,22 +249,29 @@ | ||
| 239 | 249 | $element->open_unique += $stats->open_unique; |
| 240 | 250 | $element->tracking_sale += $stats->tracking_sale; |
| 241 | 251 | } |
| 242 | 252 | |
| 243 | - public function getStatsCampaign(&$element, $urlClickClass, $isAbTest = false) | |
| 253 | + public function getStatsCampaign(object $element, UrlClickClass $urlClickClass, bool $isAbTest = false): void | |
| 244 | 254 | { |
| 245 | 255 | $element->open = 0; |
| 246 | 256 | $element->click = 0; |
| 247 | 257 | |
| 248 | 258 | if (!empty($element->subscribers)) { |
| 249 | - $element->open = number_format($element->open_unique / $element->subscribers * 100, 2); | |
| 259 | + // In anonymous mode opens/clicks are counted globally (totals, not unique subscribers), so a percentage of recipients is meaningless: expose the average number of opens/clicks per email sent instead (e.g. 3.25), rendered as "3.25×" in the view | |
| 260 | + $anonymousStats = !empty($this->config->get('anonymous_stats', 0)); | |
| 261 | + $clicksNb = $urlClickClass->getNumberUsersClicked([$element->mail_id], $isAbTest); | |
| 250 | 262 | |
| 251 | - $clicksNb = $urlClickClass->getNumberUsersClicked($element->mail_id, $isAbTest); | |
| 252 | - $element->click = number_format($clicksNb / $element->subscribers * 100, 2); | |
| 263 | + if ($anonymousStats) { | |
| 264 | + $element->open = number_format($element->open_unique / $element->subscribers, 2); | |
| 265 | + $element->click = number_format($clicksNb / $element->subscribers, 2); | |
| 266 | + } else { | |
| 267 | + $element->open = number_format($element->open_unique / $element->subscribers * 100, 2); | |
| 268 | + $element->click = number_format($clicksNb / $element->subscribers * 100, 2); | |
| 269 | + } | |
| 253 | 270 | } |
| 254 | 271 | } |
| 255 | 272 | |
| 256 | - public function getTrackingSales(&$element) | |
| 273 | + public function getTrackingSales(object $element): void | |
| 257 | 274 | { |
| 258 | 275 | $element->sale = 0; |
| 259 | 276 | $element->currency = ''; |
| 260 | 277 | |
| @@ -271,32 +288,48 @@ | ||
| 271 | 288 | } |
| 272 | 289 | $this->formatSaleTracking($element, $trackingSales); |
| 273 | 290 | } |
| 274 | 291 | |
| 275 | - private function getStatsCampaignAuto(&$element, $urlClickClass) | |
| 292 | + private function getStatsCampaignAuto(object $element, UrlClickClass $urlClickClass): void | |
| 276 | 293 | { |
| 277 | 294 | $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 | - ).')' | |
| 295 | + 'SELECT mail_stat.* | |
| 296 | + FROM #__acym_mail AS mail | |
| 297 | + JOIN #__acym_mail_stat AS mail_stat | |
| 298 | + ON mail.id = mail_stat.mail_id | |
| 299 | + WHERE mail.id IN (SELECT mail_id FROM #__acym_campaign WHERE parent_id = '.intval($element->id).')' | |
| 281 | 300 | ); |
| 301 | + | |
| 282 | 302 | $element->open = 0; |
| 283 | 303 | $element->click = 0; |
| 284 | 304 | $element->subscribers = 0; |
| 285 | - if (empty($generatedMailsStats)) return; | |
| 305 | + if (empty($generatedMailsStats)) { | |
| 306 | + return; | |
| 307 | + } | |
| 286 | 308 | |
| 287 | 309 | foreach ($generatedMailsStats as $key => $mailsStat) { |
| 288 | 310 | $element->open += $mailsStat->open_unique; |
| 289 | - $element->click += $urlClickClass->getNumberUsersClicked($element->id); | |
| 311 | + $element->click += $urlClickClass->getNumberUsersClicked([$element->id]); | |
| 290 | 312 | $element->subscribers += $mailsStat->sent; |
| 291 | 313 | } |
| 292 | 314 | |
| 293 | 315 | 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); | |
| 316 | + // In anonymous mode opens/clicks are counted globally (totals, not unique subscribers), so expose the average number of opens/clicks per email sent (e.g. 3.25) instead of a percentage, rendered as "3.25×" in the view | |
| 317 | + $anonymousStats = !empty($this->config->get('anonymous_stats', 0)); | |
| 318 | + | |
| 319 | + if ($anonymousStats) { | |
| 320 | + $element->open = number_format($element->open / $element->subscribers, 2); | |
| 321 | + $element->click = number_format($element->click / $element->subscribers, 2); | |
| 322 | + } else { | |
| 323 | + $element->open = number_format($element->open / $element->subscribers * 100, 2); | |
| 324 | + $element->click = number_format($element->click / $element->subscribers * 100, 2); | |
| 325 | + } | |
| 296 | 326 | } |
| 297 | 327 | |
| 298 | - if (!acym_isTrackingSalesActive()) return; | |
| 328 | + //Tracking sales | |
| 329 | + if (!acym_isTrackingSalesActive()) { | |
| 330 | + return; | |
| 331 | + } | |
| 299 | 332 | |
| 300 | 333 | $trackingSales = acym_loadObject( |
| 301 | 334 | 'SELECT SUM(mail_stat.tracking_sale) AS sale, mail_stat.currency |
| 302 | 335 | FROM #__acym_mail_stat AS mail_stat |
| @@ -304,9 +337,9 @@ | ||
| 304 | 337 | ); |
| 305 | 338 | $this->formatSaleTracking($element, $trackingSales); |
| 306 | 339 | } |
| 307 | 340 | |
| 308 | - private function formatSaleTracking(&$element, $trackingSales) | |
| 341 | + private function formatSaleTracking(object $element, object $trackingSales): void | |
| 309 | 342 | { |
| 310 | 343 | $element->sale = $trackingSales->sale; |
| 311 | 344 | if (empty($element->currency)) $element->currency = ''; |
| 312 | 345 | acym_trigger('getCurrency', [&$element->currency]); |
| @@ -311,43 +344,44 @@ | ||
| 311 | 344 | if (empty($element->currency)) $element->currency = ''; |
| 312 | 345 | acym_trigger('getCurrency', [&$element->currency]); |
| 313 | 346 | } |
| 314 | 347 | |
| 315 | - public function getOneById($id) | |
| 348 | + public function getOneById(int $id): ?object | |
| 316 | 349 | { |
| 317 | - return $this->decode(acym_loadObject('SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.id = '.intval($id))); | |
| 350 | + $campaign = parent::getOneById($id); | |
| 351 | + | |
| 352 | + return empty($campaign) ? null : $this->decode($campaign); | |
| 318 | 353 | } |
| 319 | 354 | |
| 320 | - public function getOneByIdWithMail($id) | |
| 355 | + public function getOneByMailId(int $mailId): ?object | |
| 321 | 356 | { |
| 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); | |
| 357 | + $campaign = acym_loadObject( | |
| 358 | + 'SELECT * | |
| 359 | + FROM #__acym_campaign | |
| 360 | + WHERE `mail_id` = '.intval($mailId) | |
| 361 | + ); | |
| 326 | 362 | |
| 327 | - return $this->decode(acym_loadObject($query)); | |
| 363 | + return empty($campaign) ? null : $campaign; | |
| 328 | 364 | } |
| 329 | 365 | |
| 330 | - public function get($identifier, $column = 'id') | |
| 366 | + public function getOneByIdWithMail(int $id): ?object | |
| 331 | 367 | { |
| 332 | - return $this->decode(acym_loadObject('SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.'.acym_secureDBColumn($column).' = '.acym_escapeDB($identifier))); | |
| 333 | - } | |
| 368 | + $campaign = acym_loadObject( | |
| 369 | + '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 | |
| 370 | + FROM #__acym_campaign AS campaign | |
| 371 | + JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id | |
| 372 | + WHERE campaign.id = '.intval($id) | |
| 373 | + ); | |
| 334 | 374 | |
| 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)); | |
| 375 | + return empty($campaign) ? null : $this->decode($campaign); | |
| 342 | 376 | } |
| 343 | 377 | |
| 344 | - public function getOneCampaignByMailId($mailId) | |
| 378 | + public function getOneCampaignByMailId(int $mailId) | |
| 345 | 379 | { |
| 346 | 380 | return $this->decode(acym_loadObject('SELECT * FROM #__acym_campaign WHERE mail_id = '.intval($mailId))); |
| 347 | 381 | } |
| 348 | 382 | |
| 349 | - public function getAutoCampaignFromGeneratedMailId($mailId) | |
| 383 | + public function getAutoCampaignFromGeneratedMailId(int $mailId) | |
| 350 | 384 | { |
| 351 | 385 | $queryCampaign = 'SELECT * FROM #__acym_campaign WHERE id = (SELECT parent_id FROM #__acym_campaign WHERE mail_id = '.intval($mailId).')'; |
| 352 | 386 | |
| 353 | 387 | return $this->decode(acym_loadObject($queryCampaign)); |
| @@ -352,9 +386,9 @@ | ||
| 352 | 386 | |
| 353 | 387 | return $this->decode(acym_loadObject($queryCampaign)); |
| 354 | 388 | } |
| 355 | 389 | |
| 356 | - public function manageListsToCampaign($listsIds, $mailId, $unselectedListIds = []) | |
| 390 | + public function manageListsToCampaign($listsIds, int $mailId, array $unselectedListIds = []): bool | |
| 357 | 391 | { |
| 358 | 392 | if (!empty($unselectedListIds)) { |
| 359 | 393 | acym_arrayToInteger($unselectedListIds); |
| 360 | 394 | acym_query('DELETE FROM #__acym_mail_has_list WHERE mail_id = '.intval($mailId).' AND list_id IN ('.implode(', ', $unselectedListIds).')'); |
| @@ -362,11 +396,22 @@ | ||
| 362 | 396 | |
| 363 | 397 | acym_arrayToInteger($listsIds); |
| 364 | 398 | if (empty($listsIds)) return false; |
| 365 | 399 | |
| 400 | + $listsIds = array_unique($listsIds); | |
| 401 | + | |
| 402 | + $existingListsIds = acym_loadResultArray('SELECT `id` FROM #__acym_list WHERE `id` IN ('.implode(',', $listsIds).')'); | |
| 403 | + acym_arrayToInteger($existingListsIds); | |
| 404 | + | |
| 405 | + $unknownListsIds = array_diff($listsIds, $existingListsIds); | |
| 406 | + if (!empty($unknownListsIds)) { | |
| 407 | + $this->errors[] = acym_translationSprintf('ACYM_LIST_NOT_FOUND', implode(', ', $unknownListsIds)); | |
| 408 | + } | |
| 409 | + | |
| 410 | + if (empty($existingListsIds)) return false; | |
| 411 | + | |
| 366 | 412 | $values = []; |
| 367 | - $listsIds = array_unique($listsIds); | |
| 368 | - foreach ($listsIds as $listId) { | |
| 413 | + foreach ($existingListsIds as $listId) { | |
| 369 | 414 | $values[] = '('.intval($mailId).', '.intval($listId).')'; |
| 370 | 415 | } |
| 371 | 416 | |
| 372 | 417 | if (!empty($values)) { |
| @@ -375,11 +420,11 @@ | ||
| 375 | 420 | |
| 376 | 421 | return true; |
| 377 | 422 | } |
| 378 | 423 | |
| 379 | - public function save($campaignToSave) | |
| 424 | + public function save(object $element): ?int | |
| 380 | 425 | { |
| 381 | - $campaign = clone $campaignToSave; | |
| 426 | + $campaign = clone $element; | |
| 382 | 427 | if (isset($campaign->tags)) { |
| 383 | 428 | $tags = $campaign->tags; |
| 384 | 429 | unset($campaign->tags); |
| 385 | 430 | } |
| @@ -388,9 +433,9 @@ | ||
| 388 | 433 | if (in_array($oneAttribute, $this->jsonColumns)) { |
| 389 | 434 | $campaign->$oneAttribute = json_encode(empty($value) ? [] : $value); |
| 390 | 435 | } else { |
| 391 | 436 | if (empty($value)) continue; |
| 392 | - $campaign->$oneAttribute = strip_tags($value); | |
| 437 | + $campaign->$oneAttribute = acym_stripTags($value); | |
| 393 | 438 | } |
| 394 | 439 | } |
| 395 | 440 | |
| 396 | 441 | $campaignID = parent::save($campaign); |
| @@ -402,9 +447,9 @@ | ||
| 402 | 447 | |
| 403 | 448 | return $campaignID; |
| 404 | 449 | } |
| 405 | 450 | |
| 406 | - public function onlyManageableCampaigns(&$elements) | |
| 451 | + public function onlyManageableCampaigns(array &$elements): void | |
| 407 | 452 | { |
| 408 | 453 | if (acym_isAdmin()) return; |
| 409 | 454 | |
| 410 | 455 | $idCurrentUser = acym_currentUserId(); |
| @@ -425,13 +470,13 @@ | ||
| 425 | 470 | if (empty($userId)) { |
| 426 | 471 | return false; |
| 427 | 472 | } |
| 428 | 473 | |
| 429 | - if (acym_isAdmin()) { | |
| 474 | + if (acym_isAdmin() && acym_isAllowed('campaigns')) { | |
| 430 | 475 | return true; |
| 431 | 476 | } |
| 432 | 477 | |
| 433 | - $query = 'SELECT COUNT(*) FROM #__acym_campaign AS campaign | |
| 478 | + $query = 'SELECT COUNT(*) FROM #__acym_campaign AS campaign | |
| 434 | 479 | JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id '; |
| 435 | 480 | |
| 436 | 481 | $condition = 'mail.creator_id = '.intval($userId); |
| 437 | 482 | if ($this->config->get('front_campaigns_filter', 'own') === 'allowed') { |
| @@ -447,11 +492,14 @@ | ||
| 447 | 492 | |
| 448 | 493 | return acym_loadResult($query) > 0; |
| 449 | 494 | } |
| 450 | 495 | |
| 451 | - public function delete($elements) | |
| 496 | + /** | |
| 497 | + * Delete a campaign. Needs to delete the tag associated with the campaign and the mail attached to the campaign. | |
| 498 | + * Deleting a mail of a campaign needs to clean the association table mail_has_list and its tags | |
| 499 | + */ | |
| 500 | + public function delete(array $elements): int | |
| 452 | 501 | { |
| 453 | - if (!is_array($elements)) $elements = [$elements]; | |
| 454 | 502 | acym_arrayToInteger($elements); |
| 455 | 503 | $this->onlyManageableCampaigns($elements); |
| 456 | 504 | |
| 457 | 505 | if (empty($elements)) return 0; |
| @@ -467,9 +515,9 @@ | ||
| 467 | 515 | |
| 468 | 516 | return parent::delete($elements); |
| 469 | 517 | } |
| 470 | 518 | |
| 471 | - public function countUsersCampaign($campaignID, $onlyActive = false): int | |
| 519 | + public function countUsersCampaign(int $campaignID, bool $onlyActive = false): int | |
| 472 | 520 | { |
| 473 | 521 | $campaign = $this->getOneById($campaignID); |
| 474 | 522 | if (empty($campaign)) { |
| 475 | 523 | return 0; |
| @@ -528,29 +576,32 @@ | ||
| 528 | 576 | return $numberOfRecipients; |
| 529 | 577 | } |
| 530 | 578 | } |
| 531 | 579 | |
| 532 | - public function getFilterCampaign($sendingParams) | |
| 580 | + public function getFilterCampaign($sendingParams): array | |
| 533 | 581 | { |
| 534 | - $filters = []; | |
| 582 | + if (empty($sendingParams['segment'])) { | |
| 583 | + return []; | |
| 584 | + } | |
| 535 | 585 | |
| 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 | - } | |
| 586 | + if (!empty($sendingParams['segment']['filters'])) { | |
| 587 | + return $sendingParams['segment']['filters']; | |
| 588 | + } | |
| 589 | + | |
| 590 | + if (!empty($sendingParams['segment']['segment_id'])) { | |
| 591 | + $segmentClass = new SegmentClass(); | |
| 592 | + $segment = $segmentClass->getOneById($sendingParams['segment']['segment_id']); | |
| 593 | + if (!empty($segment)) { | |
| 594 | + return $segment->filters; | |
| 545 | 595 | } |
| 546 | 596 | } |
| 547 | 597 | |
| 548 | - return $filters; | |
| 598 | + return []; | |
| 549 | 599 | } |
| 550 | 600 | |
| 551 | - public function send($campaignID, $result = 0, $abTestFinal = false) | |
| 601 | + public function send(int $campaignID, int $result = 0, bool $abTestFinal = false) | |
| 552 | 602 | { |
| 603 | + // Make sure the email we're trying to send exists | |
| 553 | 604 | $campaign = $this->getOneById($campaignID); |
| 554 | 605 | |
| 555 | 606 | if (empty($campaign->mail_id)) { |
| 556 | 607 | $this->errors[] = acym_translation('ACYM_EMAIL_NOT_FOUND'); |
| @@ -564,17 +615,20 @@ | ||
| 564 | 615 | if (empty($filters)) { |
| 565 | 616 | $filters = [0 => []]; |
| 566 | 617 | acym_trigger('onAcymSendCampaignSpecial', [$campaign, &$filters[0], &$pluginIsExisting]); |
| 567 | 618 | } else { |
| 619 | + // Adds the special campaigns conditions to the "OR" blocs of the segment | |
| 568 | 620 | foreach ($filters as $key => $filter) { |
| 569 | 621 | acym_trigger('onAcymSendCampaignSpecial', [$campaign, &$filters[$key], &$pluginIsExisting]); |
| 570 | 622 | } |
| 571 | 623 | } |
| 572 | 624 | |
| 625 | + // This is a special campaign type, but the required plugin is not installed | |
| 573 | 626 | if (!$pluginIsExisting) { |
| 574 | 627 | return false; |
| 575 | 628 | } |
| 576 | 629 | |
| 630 | + // Make sure some receivers have been selected | |
| 577 | 631 | $lists = acym_loadResultArray('SELECT list_id FROM #__acym_mail_has_list WHERE mail_id = '.intval($campaign->mail_id)); |
| 578 | 632 | if (empty($lists)) { |
| 579 | 633 | $this->errors[] = acym_translation('ACYM_NO_LIST_SELECTED'); |
| 580 | 634 | |
| @@ -631,8 +685,9 @@ | ||
| 631 | 685 | } else { |
| 632 | 686 | $select = [intval($campaign->mail_id), 'ul.`user_id`', acym_escapeDB($date)]; |
| 633 | 687 | } |
| 634 | 688 | |
| 689 | + // Resending a campaign only to users who didn't receive it | |
| 635 | 690 | if (!empty($campaign->sending_params['resendTarget']) && 'new' === $campaign->sending_params['resendTarget']) { |
| 636 | 691 | if (acym_isMultilingual()) { |
| 637 | 692 | $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 | 693 | $campaign->mail_id |
| @@ -654,10 +709,11 @@ | ||
| 654 | 709 | $numberUsersInsertedByMailId[intval($campaign->mail_id)] = acym_query( |
| 655 | 710 | 'INSERT IGNORE INTO `#__acym_queue` (`mail_id`, `user_id`, `sending_date`) '.$automationHelper->getQuery($select1) |
| 656 | 711 | ); |
| 657 | 712 | |
| 713 | + // If we have an odd number of users to send, we send one more to the first mail | |
| 658 | 714 | $numberOfUsersToSend2 = $numberOfUsersToSend1 * 2 > $numberOfUsersToSend ? $numberOfUsersToSend1 - 1 : $numberOfUsersToSend1; |
| 659 | - $automationHelper->limit = $numberOfUsersToSend.', '.$numberOfUsersToSend2; | |
| 715 | + $automationHelper->limit = $numberOfUsersToSend1.', '.$numberOfUsersToSend2; | |
| 660 | 716 | $select2 = [intval($campaign->sending_params['abtest']['B']), 'ul.`user_id`', acym_escapeDB($date)]; |
| 661 | 717 | $numberUsersInsertedByMailId[intval($campaign->sending_params['abtest']['B'])] = acym_query( |
| 662 | 718 | 'INSERT IGNORE INTO `#__acym_queue` (`mail_id`, `user_id`, `sending_date`) '.$automationHelper->getQuery($select2) |
| 663 | 719 | ); |
| @@ -690,13 +746,12 @@ | ||
| 690 | 746 | } |
| 691 | 747 | |
| 692 | 748 | $mailStatClass = new MailStatClass(); |
| 693 | 749 | foreach ($numberUsersInsertedByMailId as $mailId => $numberOfUsersInserted) { |
| 694 | - $newMailStat = [ | |
| 695 | - 'mail_id' => intval($mailId), | |
| 696 | - 'total_subscribers' => intval($numberOfUsersInserted), | |
| 697 | - 'send_date' => $date, | |
| 698 | - ]; | |
| 750 | + $newMailStat = new \stdClass(); | |
| 751 | + $newMailStat->mail_id = intval($mailId); | |
| 752 | + $newMailStat->total_subscribers = intval($numberOfUsersInserted); | |
| 753 | + $newMailStat->send_date = $date; | |
| 699 | 754 | |
| 700 | 755 | $mailStatClass->save($newMailStat); |
| 701 | 756 | } |
| 702 | 757 | |
| @@ -710,22 +765,29 @@ | ||
| 710 | 765 | |
| 711 | 766 | return $result; |
| 712 | 767 | } |
| 713 | 768 | |
| 714 | - public function getCampaignForDashboard() | |
| 769 | + public function getCampaignForDashboard(): array | |
| 715 | 770 | { |
| 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'; | |
| 771 | + $campaigns = acym_loadObjectList( | |
| 772 | + 'SELECT campaign.*, mail.name AS name | |
| 773 | + FROM #__acym_campaign AS campaign | |
| 774 | + LEFT JOIN #__acym_mail AS mail | |
| 775 | + ON campaign.mail_id = mail.id | |
| 776 | + WHERE `active` = 1 | |
| 777 | + AND `sent` = 0 | |
| 778 | + AND `sending_type` = '.acym_escapeDB(self::SENDING_TYPE_SCHEDULED).' | |
| 779 | + LIMIT 3' | |
| 780 | + ); | |
| 719 | 781 | |
| 720 | - return $this->decode(acym_loadObjectList($query)); | |
| 782 | + return $this->decode($campaigns); | |
| 721 | 783 | } |
| 722 | 784 | |
| 723 | - public function getOpenRateCampaigns($mailIds) | |
| 785 | + public function getOpenRateCampaigns(array $mailIds) | |
| 724 | 786 | { |
| 725 | - if (!is_array($mailIds)) $mailIds = [$mailIds]; | |
| 726 | 787 | acym_arrayToInteger($mailIds); |
| 727 | 788 | |
| 789 | + //TODO move these methods in mail stat class | |
| 728 | 790 | $query = 'SELECT SUM(sent) AS sent, SUM(open_unique) AS open_unique FROM #__acym_mail_stat |
| 729 | 791 | WHERE mail_id IN ('.implode(',', $mailIds).')'; |
| 730 | 792 | |
| 731 | 793 | return acym_loadObject($query); |
| @@ -744,13 +806,10 @@ | ||
| 744 | 806 | |
| 745 | 807 | return acym_loadObject($query); |
| 746 | 808 | } |
| 747 | 809 | |
| 748 | - | |
| 749 | - public function getBounceRateCampaigns($mailIds) | |
| 810 | + public function getBounceRateCampaigns(array $mailIds) | |
| 750 | 811 | { |
| 751 | - if (!is_array($mailIds)) $mailIds = [$mailIds]; | |
| 752 | - | |
| 753 | 812 | acym_arrayToInteger($mailIds); |
| 754 | 813 | |
| 755 | 814 | $query = 'SELECT SUM(sent) AS sent, SUM(bounce_unique) AS bounce_unique FROM #__acym_mail_stat |
| 756 | 815 | WHERE mail_id IN ('.implode(',', $mailIds).')'; |
| @@ -757,9 +816,9 @@ | ||
| 757 | 816 | |
| 758 | 817 | return acym_loadObject($query); |
| 759 | 818 | } |
| 760 | 819 | |
| 761 | - public function getOpenByMonth($mailIds = [], $start = '', $end = '') | |
| 820 | + public function getOpenByMonth(array $mailIds = [], string $start = '', string $end = ''): array | |
| 762 | 821 | { |
| 763 | 822 | if (!is_array($mailIds)) $mailIds = [$mailIds]; |
| 764 | 823 | acym_arrayToInteger($mailIds); |
| 765 | 824 | |
| @@ -772,22 +831,10 @@ | ||
| 772 | 831 | |
| 773 | 832 | return acym_loadObjectList($query); |
| 774 | 833 | } |
| 775 | 834 | |
| 776 | - public function getOpenByWeek($mail_id = '', $start = '', $end = '') | |
| 835 | + public function getOpenByDay(array $mailIds = [], string $start = '', string $end = ''): array | |
| 777 | 836 | { |
| 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 | 837 | if (!is_array($mailIds)) $mailIds = [$mailIds]; |
| 791 | 838 | acym_arrayToInteger($mailIds); |
| 792 | 839 | |
| 793 | 840 | $query = 'SELECT COUNT(user_id) as open, DATE_FORMAT(open_date, \'%Y-%m-%d\') as open_date FROM #__acym_user_stat WHERE open > 0'; |
| @@ -799,9 +846,9 @@ | ||
| 799 | 846 | |
| 800 | 847 | return acym_loadObjectList($query); |
| 801 | 848 | } |
| 802 | 849 | |
| 803 | - public function getOpenByHour($mailIds = [], $start = '', $end = '') | |
| 850 | + public function getOpenByHour(array $mailIds = [], string $start = '', string $end = ''): array | |
| 804 | 851 | { |
| 805 | 852 | if (!is_array($mailIds)) $mailIds = [$mailIds]; |
| 806 | 853 | acym_arrayToInteger($mailIds); |
| 807 | 854 | |
| @@ -814,11 +861,10 @@ | ||
| 814 | 861 | |
| 815 | 862 | return acym_loadObjectList($query); |
| 816 | 863 | } |
| 817 | 864 | |
| 818 | - public function getDevicesWithCountByMailId($mailIds = []) | |
| 865 | + public function getDevicesWithCountByMailId(array $mailIds = []): array | |
| 819 | 866 | { |
| 820 | - if (!is_array($mailIds)) $mailIds = [$mailIds]; | |
| 821 | 867 | acym_arrayToInteger($mailIds); |
| 822 | 868 | |
| 823 | 869 | $query = 'SELECT device, COUNT(*) as number FROM #__acym_user_stat WHERE `open` > 0'; |
| 824 | 870 | if (!empty($mailIds)) $query .= ' AND mail_id IN ('.implode(',', $mailIds).')'; |
| @@ -826,32 +872,39 @@ | ||
| 826 | 872 | |
| 827 | 873 | return acym_loadObjectList($query); |
| 828 | 874 | } |
| 829 | 875 | |
| 830 | - public function getLastNewsletters(&$params): array | |
| 876 | + public function getLastNewsletters(array &$params): array | |
| 831 | 877 | { |
| 878 | + // Init select elements | |
| 832 | 879 | $querySelect = 'SELECT mail.*, campaign.sending_date '; |
| 833 | 880 | $queryCountSelect = 'SELECT COUNT(*) FROM (SELECT DISTINCT mail.id '; |
| 834 | 881 | |
| 882 | + // Form the query | |
| 835 | 883 | $query = 'FROM #__acym_campaign AS campaign |
| 836 | 884 | JOIN #__acym_mail AS mail ON campaign.mail_id = mail.id '; |
| 837 | 885 | |
| 886 | + // We may need some joins depending on the selected options | |
| 838 | 887 | if (isset($params['userId']) || isset($params['lists'])) { |
| 839 | 888 | $query .= 'JOIN #__acym_mail_has_list AS maillist ON mail.id = maillist.mail_id '; |
| 840 | 889 | if (isset($params['userId'])) $query .= 'JOIN #__acym_user_has_list AS userlist ON maillist.list_id = userlist.list_id '; |
| 841 | 890 | } |
| 842 | 891 | |
| 892 | + // Make sure we display only active campaigns | |
| 843 | 893 | $where = 'WHERE campaign.active = 1 AND campaign.sent = 1 AND mail.type = '.acym_escapeDB(MailClass::TYPE_STANDARD).' AND campaign.visible = 1 '; |
| 844 | 894 | |
| 895 | + // If we want an archive of some specific lists | |
| 845 | 896 | if (isset($params['lists'])) { |
| 846 | 897 | acym_arrayToInteger($params['lists']); |
| 847 | 898 | $where .= 'AND maillist.list_id IN ('.implode(', ', $params['lists']).') '; |
| 848 | 899 | } |
| 849 | 900 | |
| 901 | + // If we want an archive for a specific user | |
| 850 | 902 | if (isset($params['userId']) && !empty($params['displayUserListOnly'])) { |
| 851 | 903 | $where .= 'AND userlist.user_id = '.intval($params['userId']).' '; |
| 852 | 904 | } |
| 853 | 905 | |
| 906 | + // If the user search for a newsletter | |
| 854 | 907 | if (isset($params['search'])) { |
| 855 | 908 | $search = acym_escapeDB('%'.acym_utf8Encode($params['search']).'%'); |
| 856 | 909 | $where .= 'AND (mail.subject LIKE '.$search.' OR mail.body LIKE '.$search.')'; |
| 857 | 910 | } |
| @@ -859,11 +912,13 @@ | ||
| 859 | 912 | $query .= $where; |
| 860 | 913 | $return = []; |
| 861 | 914 | $return['count'] = (int)acym_loadResult($queryCountSelect.$query.') AS r '); |
| 862 | 915 | |
| 916 | + // Make sure we display campaigns only once | |
| 863 | 917 | $endQuerySelect = 'GROUP BY mail.id '; |
| 864 | 918 | $endQuerySelect .= 'ORDER BY campaign.sending_date DESC'; |
| 865 | 919 | |
| 920 | + // Init the pagination | |
| 866 | 921 | $page = $params['page'] ?? 0; |
| 867 | 922 | $numberPerPage = $params['numberPerPage'] ?? 0; |
| 868 | 923 | $lastNewsletters = $params['limit'] ?? 0; |
| 869 | 924 | |
| @@ -919,16 +974,17 @@ | ||
| 919 | 974 | |
| 920 | 975 | return $return; |
| 921 | 976 | } |
| 922 | 977 | |
| 923 | - public function getListsByMailId($mailId) | |
| 978 | + public function getListsByMailId(int $mailId): array | |
| 924 | 979 | { |
| 925 | - $query = 'SELECT list_id FROM #__acym_mail_has_list WHERE mail_id = '.intval($mailId); | |
| 980 | + $listIds = acym_loadResultArray('SELECT list_id FROM #__acym_mail_has_list WHERE mail_id = '.intval($mailId)); | |
| 981 | + acym_arrayToInteger($listIds); | |
| 926 | 982 | |
| 927 | - return acym_loadResultArray($query); | |
| 983 | + return $listIds; | |
| 928 | 984 | } |
| 929 | 985 | |
| 930 | - public function triggerAutoCampaign() | |
| 986 | + public function triggerAutoCampaign(): void | |
| 931 | 987 | { |
| 932 | 988 | $activeAutoCampaigns = acym_loadObjectList( |
| 933 | 989 | 'SELECT campaign.*, mail.name |
| 934 | 990 | FROM #__acym_campaign AS campaign |
| @@ -947,12 +1003,19 @@ | ||
| 947 | 1003 | $adminNotificationEmail = $mailClass->getOneByName('acy_notification_auto_campaign_admin'); |
| 948 | 1004 | $time = time(); |
| 949 | 1005 | |
| 950 | 1006 | 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) { | |
| 1007 | + // Check the start date | |
| 1008 | + $nextTrigger = $campaign->next_trigger; | |
| 1009 | + if (empty($nextTrigger) && !empty($campaign->sending_params['start_date'])) { | |
| 1010 | + $nextTrigger = $campaign->sending_params['start_date']; | |
| 1011 | + } | |
| 1012 | + | |
| 1013 | + if (!empty($nextTrigger) && acym_getTime(acym_date($nextTrigger, 'Y-m-d H:i')) > $time) { | |
| 952 | 1014 | continue; |
| 953 | 1015 | } |
| 954 | 1016 | |
| 1017 | + //check if we trigger the campaign | |
| 955 | 1018 | $step = new \stdClass(); |
| 956 | 1019 | $step->triggers = $campaign->sending_params; |
| 957 | 1020 | $step->last_execution = $campaign->last_generated; |
| 958 | 1021 | $step->next_execution = $campaign->next_trigger; |
| @@ -965,8 +1028,9 @@ | ||
| 965 | 1028 | $this->save($campaign); |
| 966 | 1029 | continue; |
| 967 | 1030 | } |
| 968 | 1031 | |
| 1032 | + //update the campaign | |
| 969 | 1033 | $campaignMail = $mailClass->getOneById($campaign->mail_id); |
| 970 | 1034 | |
| 971 | 1035 | $lastGenerated = $campaign->last_generated; |
| 972 | 1036 | $shouldGenerate = $this->updateAutoCampaign($campaign, $campaignMail, $time); |
| @@ -975,10 +1039,18 @@ | ||
| 975 | 1039 | if (!$shouldGenerate) { |
| 976 | 1040 | continue; |
| 977 | 1041 | } |
| 978 | 1042 | |
| 1043 | + //We generate the new campaign | |
| 979 | 1044 | $generatedCampaign = $this->generateCampaign($campaign, $campaignMail, $lastGenerated, $mailClass); |
| 1045 | + if (empty($generatedCampaign)) { | |
| 1046 | + $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_FAILED_GENERATING', $campaign->name); | |
| 1047 | + continue; | |
| 1048 | + } | |
| 980 | 1049 | |
| 1050 | + $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_GENERATED', $campaign->name, $campaign->sending_params['number_generated']); | |
| 1051 | + | |
| 1052 | + // We send it directly if no confirmation is needed | |
| 981 | 1053 | if (empty($campaign->sending_params['need_confirm_to_send'])) { |
| 982 | 1054 | $this->send($generatedCampaign->id); |
| 983 | 1055 | } elseif (!empty($campaign->sending_params['admin_notification_emails']) && !empty($adminNotificationEmail)) { |
| 984 | 1056 | $mailerHelper->addParam('campaign_name', $campaign->name); |
| @@ -991,14 +1063,16 @@ | ||
| 991 | 1063 | } |
| 992 | 1064 | } |
| 993 | 1065 | } |
| 994 | 1066 | |
| 995 | - private function shouldGenerateCampaign($campaign, $campaignMail): bool | |
| 1067 | + private function shouldGenerateCampaign(object $campaign, object $campaignMail): bool | |
| 996 | 1068 | { |
| 1069 | + // The generateByCategory function is the only one that can stop a campaign generation, with min number of items | |
| 997 | 1070 | $results = acym_trigger('generateByCategory', [&$campaignMail], null, function ($plugin) { |
| 998 | 1071 | $plugin->generateCampaignResult->status = true; |
| 999 | 1072 | }); |
| 1000 | 1073 | |
| 1074 | + // If one of the return statuses is "false", we won't generate the campaign | |
| 1001 | 1075 | foreach ($results as $oneResult) { |
| 1002 | 1076 | if (isset($oneResult->status) && !$oneResult->status) { |
| 1003 | 1077 | $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_NOT_GENERATED', $campaign->name, $oneResult->message); |
| 1004 | 1078 | |
| @@ -1008,9 +1082,9 @@ | ||
| 1008 | 1082 | |
| 1009 | 1083 | return true; |
| 1010 | 1084 | } |
| 1011 | 1085 | |
| 1012 | - private function updateAutoCampaign(&$campaign, $campaignMail, $time): bool | |
| 1086 | + private function updateAutoCampaign(object $campaign, object $campaignMail, int $time): bool | |
| 1013 | 1087 | { |
| 1014 | 1088 | if (!$this->shouldGenerateCampaign($campaign, $campaignMail)) { |
| 1015 | 1089 | return false; |
| 1016 | 1090 | } |
| @@ -1021,16 +1095,18 @@ | ||
| 1021 | 1095 | $campaign->sending_params['number_generated']++; |
| 1022 | 1096 | } |
| 1023 | 1097 | $campaign->last_generated = $time; |
| 1024 | 1098 | |
| 1025 | - $this->messages[] = acym_translationSprintf('ACYM_CAMPAIGN_GENERATED', $campaign->name, $campaign->sending_params['number_generated']); | |
| 1026 | - | |
| 1027 | 1099 | return true; |
| 1028 | 1100 | } |
| 1029 | 1101 | |
| 1030 | - private function generateCampaign($campaign, $campaignMail, $lastGenerated, $mailClass) | |
| 1102 | + private function generateCampaign(object $campaign, object $campaignMail, ?int $lastGenerated, MailClass $mailClass): ?object | |
| 1031 | 1103 | { |
| 1032 | 1104 | $newMail = $this->generateMailAutoCampaign($campaignMail, $campaign->sending_params['number_generated'], $mailClass); |
| 1105 | + if (empty($newMail)) { | |
| 1106 | + return null; | |
| 1107 | + } | |
| 1108 | + | |
| 1033 | 1109 | $newCampaign = new \stdClass(); |
| 1034 | 1110 | $newCampaign->mail_id = $newMail->id; |
| 1035 | 1111 | $newCampaign->parent_id = $campaign->id; |
| 1036 | 1112 | $newCampaign->active = 1; |
| @@ -1042,8 +1118,9 @@ | ||
| 1042 | 1118 | $newCampaign->sending_params = empty($campaign->sending_params['segment']) ? '' : ['segment' => $campaign->sending_params['segment']]; |
| 1043 | 1119 | |
| 1044 | 1120 | $newCampaign->id = $this->save($newCampaign); |
| 1045 | 1121 | |
| 1122 | + // Replace content in the generated mail. MUST be done after campaign has been saved | |
| 1046 | 1123 | acym_trigger('replaceContent', [&$newMail, false]); |
| 1047 | 1124 | $mailClass->save($newMail); |
| 1048 | 1125 | |
| 1049 | 1126 | return $newCampaign; |
| @@ -1048,9 +1125,9 @@ | ||
| 1048 | 1125 | |
| 1049 | 1126 | return $newCampaign; |
| 1050 | 1127 | } |
| 1051 | 1128 | |
| 1052 | - private function generateMailAutoCampaign($newMail, $generatedMailNumber, $mailClass) | |
| 1129 | + private function generateMailAutoCampaign(object $newMail, int $generatedMailNumber, MailClass $mailClass): ?object | |
| 1053 | 1130 | { |
| 1054 | 1131 | $mailId = $newMail->id; |
| 1055 | 1132 | unset($newMail->id); |
| 1056 | 1133 | $newMail->creation_date = acym_date('now', 'Y-m-d H:i:s', false); |
| @@ -1056,8 +1133,12 @@ | ||
| 1056 | 1133 | $newMail->creation_date = acym_date('now', 'Y-m-d H:i:s', false); |
| 1057 | 1134 | $newMail->name .= ' #'.$generatedMailNumber; |
| 1058 | 1135 | |
| 1059 | 1136 | $newMail->id = $mailClass->save($newMail); |
| 1137 | + if (empty($newMail->id)) { | |
| 1138 | + return null; | |
| 1139 | + } | |
| 1140 | + | |
| 1060 | 1141 | $this->setListToGeneratedCampaign($mailId, $newMail->id, $mailClass); |
| 1061 | 1142 | |
| 1062 | 1143 | if (acym_isMultilingual()) { |
| 1063 | 1144 | $this->generateMailAutoCampaignMultilingual($mailId, $generatedMailNumber, $newMail->id); |
| @@ -1065,9 +1146,9 @@ | ||
| 1065 | 1146 | |
| 1066 | 1147 | return $newMail; |
| 1067 | 1148 | } |
| 1068 | 1149 | |
| 1069 | - private function generateMailAutoCampaignMultilingual($mailId, $generatedMailNumber, $newParentId) | |
| 1150 | + private function generateMailAutoCampaignMultilingual(int $mailId, int $generatedMailNumber, int $newParentId): void | |
| 1070 | 1151 | { |
| 1071 | 1152 | $mailClass = new MailClass(); |
| 1072 | 1153 | $mails = $mailClass->getTranslationsById($mailId, true); |
| 1073 | 1154 | |
| @@ -1079,9 +1160,9 @@ | ||
| 1079 | 1160 | $mailClass->save($mail); |
| 1080 | 1161 | } |
| 1081 | 1162 | } |
| 1082 | 1163 | |
| 1083 | - private function setListToGeneratedCampaign($parentMailId, $newMailId, $mailClass) | |
| 1164 | + private function setListToGeneratedCampaign(int $parentMailId, int $newMailId, MailClass $mailClass): void | |
| 1084 | 1165 | { |
| 1085 | 1166 | $lists = $mailClass->getAllListsByMailId($parentMailId); |
| 1086 | 1167 | $listIds = array_keys($lists); |
| 1087 | 1168 | |
| @@ -1087,15 +1168,17 @@ | ||
| 1087 | 1168 | |
| 1088 | 1169 | $this->manageListsToCampaign($listIds, $newMailId); |
| 1089 | 1170 | } |
| 1090 | 1171 | |
| 1091 | - public function getLastGenerated($mailId) | |
| 1172 | + public function getLastGenerated(int $mailId): int | |
| 1092 | 1173 | { |
| 1093 | - return acym_loadResult( | |
| 1174 | + $lastGenerated = acym_loadResult( | |
| 1094 | 1175 | 'SELECT `last_generated` |
| 1095 | 1176 | FROM #__acym_campaign |
| 1096 | 1177 | WHERE `mail_id` = '.intval($mailId) |
| 1097 | 1178 | ); |
| 1179 | + | |
| 1180 | + return empty($lastGenerated) ? 0 : $lastGenerated; | |
| 1098 | 1181 | } |
| 1099 | 1182 | |
| 1100 | 1183 | private function getNbGeneratedCampaigns(): int |
| 1101 | 1184 | { |
| @@ -1106,11 +1189,11 @@ | ||
| 1106 | 1189 | AND `sending_type` = '.acym_escapeDB(self::SENDING_TYPE_NOW) |
| 1107 | 1190 | ); |
| 1108 | 1191 | } |
| 1109 | 1192 | |
| 1110 | - public function getAllCampaignsGeneratedWaiting() | |
| 1193 | + public function getAllCampaignsGeneratedWaiting(): array | |
| 1111 | 1194 | { |
| 1112 | - return acym_loadObjectList( | |
| 1195 | + $campaignIds = acym_loadObjectList( | |
| 1113 | 1196 | 'SELECT id |
| 1114 | 1197 | FROM #__acym_campaign |
| 1115 | 1198 | WHERE parent_id IS NOT NULL |
| 1116 | 1199 | AND sending_type = '.acym_escapeDB(self::SENDING_TYPE_NOW).' |
| @@ -1117,11 +1200,14 @@ | ||
| 1117 | 1200 | AND draft = 1 |
| 1118 | 1201 | AND active = 1 |
| 1119 | 1202 | AND sent = 0' |
| 1120 | 1203 | ); |
| 1204 | + acym_arrayToInteger($campaignIds); | |
| 1205 | + | |
| 1206 | + return $campaignIds; | |
| 1121 | 1207 | } |
| 1122 | 1208 | |
| 1123 | - public function getCampaignsByTypes($campaignTypes, $onlyActives = false) | |
| 1209 | + public function getCampaignsByTypes(array $campaignTypes, bool $onlyActives = false): array | |
| 1124 | 1210 | { |
| 1125 | 1211 | if (empty($campaignTypes)) return []; |
| 1126 | 1212 | $campaignTypes = array_map('acym_escapeDB', $campaignTypes); |
| 1127 | 1213 | $query = 'SELECT campaign.* FROM #__acym_campaign AS campaign WHERE campaign.sending_type IN ('.implode(',', $campaignTypes).')'; |
| @@ -1129,16 +1215,16 @@ | ||
| 1129 | 1215 | |
| 1130 | 1216 | return $this->decode(acym_loadObjectList($query), false); |
| 1131 | 1217 | } |
| 1132 | 1218 | |
| 1133 | - public function getCountCampaignType($type) | |
| 1219 | + public function getCountCampaignType(string $type): int | |
| 1134 | 1220 | { |
| 1135 | 1221 | if (empty($type)) return 0; |
| 1136 | 1222 | |
| 1137 | - return acym_loadResult('SELECT COUNT(*) FROM #__acym_campaign WHERE sending_type = '.acym_escapeDB($type)); | |
| 1223 | + return (int)acym_loadResult('SELECT COUNT(*) FROM #__acym_campaign WHERE sending_type = '.acym_escapeDB($type)); | |
| 1138 | 1224 | } |
| 1139 | 1225 | |
| 1140 | - public function getAllAbTestCampaignsToFinishSending() | |
| 1226 | + public function getAllAbTestCampaignsToFinishSending(): array | |
| 1141 | 1227 | { |
| 1142 | 1228 | $query = 'SELECT * FROM #__acym_campaign WHERE sending_params LIKE \'%"abtest":%\' AND draft = 0 AND active = 1 AND sent = 1'; |
| 1143 | 1229 | |
| 1144 | 1230 | return $this->decode(acym_loadObjectList($query)); |
| @@ -1143,9 +1229,9 @@ | ||
| 1143 | 1229 | |
| 1144 | 1230 | return $this->decode(acym_loadObjectList($query)); |
| 1145 | 1231 | } |
| 1146 | 1232 | |
| 1147 | - public function finishAbTestCampaign($campaign) | |
| 1233 | + public function finishAbTestCampaign(object $campaign): bool | |
| 1148 | 1234 | { |
| 1149 | 1235 | $abTestParams = empty($campaign->sending_params['abtest']) ? [] : $campaign->sending_params['abtest']; |
| 1150 | 1236 | |
| 1151 | 1237 | if (empty($abTestParams['B']) || empty($abTestParams['repartition']) || !empty($abTestParams['abtest_finished']) || empty($abTestParams['after']['action'])) { |
| @@ -1196,9 +1282,9 @@ | ||
| 1196 | 1282 | $mail->id = 0; |
| 1197 | 1283 | $mail->parent_id = $campaign->mail_id; |
| 1198 | 1284 | $mail->name .= ' - '.acym_translation('ACYM_ABTEST_WINNER'); |
| 1199 | 1285 | $newMailId = $mailClass->save($mail); |
| 1200 | - if (!$newMailId) { | |
| 1286 | + if (empty($newMailId)) { | |
| 1201 | 1287 | return false; |
| 1202 | 1288 | } |
| 1203 | 1289 | |
| 1204 | 1290 | $campaign->sending_params['abtest']['abtest_finished'] = 1; |
| @@ -1209,9 +1295,9 @@ | ||
| 1209 | 1295 | |
| 1210 | 1296 | return true; |
| 1211 | 1297 | } |
| 1212 | 1298 | |
| 1213 | - public function isAbTestMail($mailId): bool | |
| 1299 | + public function isAbTestMail(int $mailId): bool | |
| 1214 | 1300 | { |
| 1215 | 1301 | $mailClass = new MailClass(); |
| 1216 | 1302 | $mainMailId = $mailClass->getMainMailId($mailId); |
| 1217 | 1303 | |
| @@ -1224,9 +1310,9 @@ | ||
| 1224 | 1310 | |
| 1225 | 1311 | return !empty($campaign); |
| 1226 | 1312 | } |
| 1227 | 1313 | |
| 1228 | - public function resetAbTestVersion($campaignId): void | |
| 1314 | + public function resetAbTestVersion(int $campaignId): void | |
| 1229 | 1315 | { |
| 1230 | 1316 | if (empty($campaignId)) { |
| 1231 | 1317 | return; |
| 1232 | 1318 | } |
| @@ -1243,9 +1329,9 @@ | ||
| 1243 | 1329 | |
| 1244 | 1330 | foreach (self::AB_TEST_VERSIONS as $version) { |
| 1245 | 1331 | if (!empty($campaign->sending_params['abtest'][$version])) { |
| 1246 | 1332 | $mailClass = new MailClass(); |
| 1247 | - $mailClass->delete($campaign->sending_params['abtest'][$version]); | |
| 1333 | + $mailClass->delete([$campaign->sending_params['abtest'][$version]]); | |
| 1248 | 1334 | unset($campaign->sending_params['abtest'][$version]); |
| 1249 | 1335 | } |
| 1250 | 1336 | } |
| 1251 | 1337 | |
| @@ -1251,9 +1337,9 @@ | ||
| 1251 | 1337 | |
| 1252 | 1338 | $this->save($campaign); |
| 1253 | 1339 | } |
| 1254 | 1340 | |
| 1255 | - public function getXCampaigns(array $options) | |
| 1341 | + public function getXCampaigns(array $options): array | |
| 1256 | 1342 | { |
| 1257 | 1343 | $limit = $options['limit'] ?? 10; |
| 1258 | 1344 | $offset = $options['offset'] ?? 0; |
| 1259 | 1345 | $filters = $options['filters'] ?? []; |