3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * This class is used to browse past mailings.
21 class CRM_Mailing_Selector_Browse
extends CRM_Core_Selector_Base
implements CRM_Core_Selector_API
{
24 * Array of supported links, currently null
28 public static $_links = NULL;
31 * We use desc to remind us what that column is, name is used in the tpl
35 public static $_columnHeaders;
43 * @return \CRM_Mailing_Selector_Browse
45 public function __construct() {
49 * This method returns the links that are given for each search row.
53 public static function &links() {
58 * Getter for array of the parameters required for creating pager.
61 * @param array $params
63 public function getPagerParams($action, &$params) {
64 $params['csvString'] = NULL;
65 $params['rowCount'] = CRM_Utils_Pager
::ROWCOUNT
;
66 $params['status'] = ts('Mailings %%StatusMessage%%');
67 $params['buttonTop'] = 'PagerTopButton';
68 $params['buttonBottom'] = 'PagerBottomButton';
72 * Returns the column headers as an array of tuples:
73 * (name, sortName (key to the sort array))
75 * @param string $action
76 * The action being performed.
77 * @param string $output
78 * What should the result set include (web/email/csv).
81 * the column headers that need to be displayed
83 public function &getColumnHeaders($action = NULL, $output = NULL) {
84 $mailing = CRM_Mailing_BAO_Mailing
::getTableName();
85 $job = CRM_Mailing_BAO_MailingJob
::getTableName();
86 if (!isset(self
::$_columnHeaders)) {
87 $completedOrder = NULL;
89 // Set different default sort depending on type of mailings (CRM-7652)
90 $unscheduledOrder = $scheduledOrder = $archivedOrder = CRM_Utils_Sort
::DONTCARE
;
91 if ($this->_parent
->get('unscheduled')) {
92 $unscheduledOrder = CRM_Utils_Sort
::DESCENDING
;
94 elseif ($this->_parent
->get('scheduled')) {
95 $scheduledOrder = CRM_Utils_Sort
::DESCENDING
;
98 // sort by completed date for archived and undefined get
99 $completedOrder = CRM_Utils_Sort
::DESCENDING
;
101 $nameHeaderLabel = ($this->_parent
->get('sms')) ?
ts('SMS Name') : ts('Mailing Name');
103 self
::$_columnHeaders = [
105 'name' => $nameHeaderLabel,
107 'direction' => CRM_Utils_Sort
::DONTCARE
,
111 if (CRM_Core_I18n
::isMultilingual()) {
112 self
::$_columnHeaders = array_merge(
113 self
::$_columnHeaders,
116 'name' => ts('Language'),
117 'sort' => 'language',
118 'direction' => CRM_Utils_Sort
::DONTCARE
,
124 self
::$_columnHeaders = array_merge(
125 self
::$_columnHeaders,
128 'name' => ts('Status'),
130 'direction' => CRM_Utils_Sort
::DONTCARE
,
133 'name' => ts('Created By'),
134 'sort' => 'created_by',
135 'direction' => CRM_Utils_Sort
::DONTCARE
,
138 'name' => ts('Created Date'),
139 'sort' => 'created_date',
140 'direction' => $unscheduledOrder,
143 'name' => ts('Sent By'),
144 'sort' => 'scheduled_by',
145 'direction' => CRM_Utils_Sort
::DONTCARE
,
148 'name' => ts('Scheduled'),
149 'sort' => 'scheduled_date',
150 'direction' => $scheduledOrder,
153 'name' => ts('Started'),
154 'sort' => 'start_date',
155 'direction' => CRM_Utils_Sort
::DONTCARE
,
158 'name' => ts('Completed'),
159 'sort' => 'end_date',
160 'direction' => $completedOrder,
165 if (CRM_Campaign_BAO_Campaign
::isCampaignEnable()) {
166 self
::$_columnHeaders[] = [
167 'name' => ts('Campaign'),
168 'sort' => 'campaign_id',
169 'direction' => CRM_Utils_Sort
::DONTCARE
,
173 if ($output != CRM_Core_Selector_Controller
::EXPORT
) {
174 self
::$_columnHeaders[] = ['name' => ts('Action')];
178 CRM_Core_Smarty
::singleton()->assign('multilingual', CRM_Core_I18n
::isMultilingual());
179 return self
::$_columnHeaders;
183 * Returns total number of rows for the query.
185 * @param string $action
188 * Total number of rows
190 public function getTotalCount($action) {
191 $job = CRM_Mailing_BAO_MailingJob
::getTableName();
192 $mailing = CRM_Mailing_BAO_Mailing
::getTableName();
193 $mailingACL = CRM_Mailing_BAO_Mailing
::mailingACL();
195 // get the where clause.
197 $whereClause = "$mailingACL AND " . $this->whereClause($params);
199 // CRM-11919 added addition ON clauses to mailing_job to match getRows
201 SELECT COUNT( DISTINCT $mailing.id ) as count
203 LEFT JOIN $job ON ( $mailing.id = $job.mailing_id AND civicrm_mailing_job.is_test = 0 AND civicrm_mailing_job.parent_id IS NULL )
204 LEFT JOIN civicrm_contact createdContact ON ( $mailing.created_id = createdContact.id )
205 LEFT JOIN civicrm_contact scheduledContact ON ( $mailing.scheduled_id = scheduledContact.id )
208 return CRM_Core_DAO
::singleValueQuery($query, $params);
212 * Returns all the rows in the given offset and rowCount.
214 * @param string $action
215 * The action being performed.
217 * The row number to start from.
218 * @param int $rowCount
219 * The number of rows to return.
220 * @param string $sort
221 * The sql string that describes the sort order.
222 * @param string $output
223 * What should the result set include (web/email/csv).
226 * the total number of rows for this action
228 public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
229 static $actionLinks = NULL;
230 if (empty($actionLinks)) {
231 $cancelExtra = ts('Are you sure you want to cancel this mailing?');
232 $deleteExtra = ts('Are you sure you want to delete this mailing?');
233 $archiveExtra = ts('Are you sure you want to archive this mailing?');
236 CRM_Core_Action
::ENABLE
=> [
237 'name' => ts('Approve/Reject'),
238 'url' => 'civicrm/mailing/approve',
239 'qs' => 'mid=%%mid%%&reset=1',
240 'title' => ts('Approve/Reject Mailing'),
242 CRM_Core_Action
::VIEW
=> [
243 'name' => ts('Report'),
244 'url' => 'civicrm/mailing/report',
245 'qs' => 'mid=%%mid%%&reset=1',
246 'title' => ts('View Mailing Report'),
248 CRM_Core_Action
::DISABLE
=> [
249 'name' => ts('Cancel'),
250 'url' => 'civicrm/mailing/browse',
251 'qs' => 'action=disable&mid=%%mid%%&reset=1',
252 'extra' => 'onclick="if (confirm(\'' . $cancelExtra . '\')) this.href+=\'&confirmed=1\'; else return false;"',
253 'title' => ts('Cancel Mailing'),
255 CRM_Core_Action
::PREVIEW
=> [
256 'name' => ts('Continue'),
257 'url' => 'civicrm/mailing/send',
258 'qs' => 'mid=%%mid%%&continue=true&reset=1',
259 'title' => ts('Continue Mailing'),
261 CRM_Core_Action
::UPDATE
=> [
262 'name' => ts('Copy'),
263 'url' => 'civicrm/mailing/send',
264 'qs' => 'mid=%%mid%%&reset=1',
265 'title' => ts('Copy Mailing'),
267 CRM_Core_Action
::DELETE
=> [
268 'name' => ts('Delete'),
269 'url' => 'civicrm/mailing/browse',
270 'qs' => 'action=delete&mid=%%mid%%&reset=1',
271 'extra' => 'onclick="if (confirm(\'' . $deleteExtra . '\')) this.href+=\'&confirmed=1\'; else return false;"',
272 'title' => ts('Delete Mailing'),
274 CRM_Core_Action
::RENEW
=> [
275 'name' => ts('Archive'),
276 'url' => 'civicrm/mailing/browse/archived',
277 'qs' => 'action=renew&mid=%%mid%%&reset=1',
278 'extra' => 'onclick="if (confirm(\'' . $archiveExtra . '\')) this.href+=\'&confirmed=1\'; else return false;"',
279 'title' => ts('Archive Mailing'),
281 CRM_Core_Action
::REOPEN
=> [
282 'name' => ts('Resume'),
283 'url' => 'civicrm/mailing/browse',
284 'qs' => 'action=reopen&mid=%%mid%%&reset=1',
285 'title' => ts('Resume mailing'),
287 CRM_Core_Action
::CLOSE
=> [
288 'name' => ts('Pause'),
289 'url' => 'civicrm/mailing/browse',
290 'qs' => 'action=close&mid=%%mid%%&reset=1',
291 'title' => ts('Pause mailing'),
297 $workFlow = $showApprovalLinks = $showScheduleLinks = $showCreateLinks = FALSE;
298 if (CRM_Mailing_Info
::workflowEnabled()) {
301 // supercedes all permission
302 if (CRM_Core_Permission
::check('access CiviMail')) {
306 if (CRM_Core_Permission
::check('approve mailings')) {
307 $showApprovalLinks = TRUE;
310 if (CRM_Core_Permission
::check('create mailings')) {
311 $showCreateLinks = TRUE;
314 if (CRM_Core_Permission
::check('schedule mailings')) {
315 $showScheduleLinks = TRUE;
318 $mailing = new CRM_Mailing_BAO_Mailing();
322 $whereClause = ' AND ' . $this->whereClause($params);
324 if (empty($params)) {
325 $this->_parent
->assign('isSearch', 0);
328 $this->_parent
->assign('isSearch', 1);
330 $rows = &$mailing->getRows($offset, $rowCount, $sort, $whereClause, $params);
332 // get the search base mailing Ids, CRM-3711.
333 $searchMailings = $mailing->searchMailingIDs();
335 // check for delete CRM-4418
336 $allowToDelete = CRM_Core_Permission
::check('delete in CiviMail');
338 if ($output != CRM_Core_Selector_Controller
::EXPORT
) {
340 // create the appropriate $op to use for hook_civicrm_links
341 $pageTypes = ['view', 'mailing', 'browse'];
342 if ($this->_parent
->_unscheduled
) {
343 $pageTypes[] = 'unscheduled';
345 if ($this->_parent
->_scheduled
) {
346 $pageTypes[] = 'scheduled';
348 if ($this->_parent
->_archived
) {
349 $pageTypes[] = 'archived';
351 $opString = implode('.', $pageTypes);
353 // get languages for later conversion
354 $languages = CRM_Core_I18n
::languages();
356 foreach ($rows as $key => $row) {
358 if ($row['sms_provider_id']) {
359 $actionLinks[CRM_Core_Action
::PREVIEW
]['url'] = 'civicrm/sms/send';
362 if (!($row['status'] == 'Not scheduled') && !$row['sms_provider_id']) {
363 if ($allAccess ||
$showCreateLinks) {
364 $actionMask = CRM_Core_Action
::VIEW
;
368 if ($allAccess ||
($showCreateLinks ||
$showScheduleLinks)) {
369 $actionMask = CRM_Core_Action
::PREVIEW
;
372 if (in_array($row['status'], [
378 ($showApprovalLinks && $showCreateLinks && $showScheduleLinks)
381 $actionMask |
= CRM_Core_Action
::DISABLE
;
382 if ($row['status'] == "Paused") {
383 $actionMask |
= CRM_Core_Action
::REOPEN
;
386 $actionMask |
= CRM_Core_Action
::CLOSE
;
389 if ($row['status'] == 'Scheduled' &&
390 empty($row['approval_status_id'])
392 if ($workFlow && ($allAccess ||
$showApprovalLinks)) {
393 $actionMask |
= CRM_Core_Action
::ENABLE
;
398 if (in_array($row['status'], ['Complete', 'Canceled']) &&
401 if ($allAccess ||
$showCreateLinks) {
402 $actionMask |
= CRM_Core_Action
::RENEW
;
406 if ($allAccess ||
$showCreateLinks) {
407 $actionMask |
= CRM_Core_Action
::UPDATE
;
410 // check for delete permission.
411 if ($allowToDelete) {
412 $actionMask |
= CRM_Core_Action
::DELETE
;
415 if ($actionMask == NULL) {
416 $actionMask = CRM_Core_Action
::ADD
;
418 // get status strings as per locale settings CRM-4411.
419 $rows[$key]['status'] = CRM_Mailing_BAO_MailingJob
::status($row['status']);
421 // get language string
422 $rows[$key]['language'] = (isset($row['language']) ?
$languages[$row['language']] : NULL);
424 $validLinks = $actionLinks;
425 if (($mailingUrl = CRM_Mailing_BAO_Mailing
::getPublicViewUrl($row['id'])) != FALSE) {
426 $validLinks[CRM_Core_Action
::BROWSE
] = [
427 'name' => ts('Public View'),
428 'url' => 'civicrm/mailing/view',
429 'qs' => 'id=%%hashOrMid%%&reset=1',
430 'title' => ts('Public View'),
433 $actionMask |
= CRM_Core_Action
::BROWSE
;
436 $hash = CRM_Mailing_BAO_Mailing
::getMailingHash($row['id']);
437 $rows[$key]['action'] = CRM_Core_Action
::formLink(
442 'hashOrMid' => $hash ?
$hash : $row['id'],
451 // unset($rows[$key]['id']);
452 // if the scheduled date is 0, replace it with an empty string
453 if ($rows[$key]['scheduled_iso'] == '0000-00-00 00:00:00') {
454 $rows[$key]['scheduled'] = '';
456 unset($rows[$key]['scheduled_iso']);
460 // also initialize the AtoZ pager
466 * Name of export file.
468 * @param string $output
474 public function getExportFileName($output = 'csv') {
475 return ts('CiviMail Mailings');
481 public function setParent($parent) {
482 $this->_parent
= $parent;
486 * @param array $params
487 * @param bool $sortBy
491 public function whereClause(&$params, $sortBy = TRUE) {
492 $values = $clauses = [];
493 $isFormSubmitted = $this->_parent
->get('hidden_find_mailings');
495 $title = $this->_parent
->get('mailing_name');
497 $clauses[] = 'name LIKE %1';
498 if (strpos($title, '%') !== FALSE) {
499 $params[1] = [$title, 'String', FALSE];
502 $params[1] = [$title, 'String', TRUE];
506 $dateClause1 = $dateClause2 = [];
507 $from = $this->_parent
->get('mailing_low');
508 if (!CRM_Utils_System
::isNull($from)) {
509 if ($this->_parent
->get('unscheduled')) {
510 $dateClause1[] = 'civicrm_mailing.created_date >= %2';
513 $dateClause1[] = 'civicrm_mailing_job.start_date >= %2';
514 $dateClause2[] = 'civicrm_mailing_job.scheduled_date >= %2';
516 $params[2] = [$from, 'String'];
519 $to = $this->_parent
->get('mailing_high');
520 if (!CRM_Utils_System
::isNull($to)) {
521 if ($this->_parent
->get('unscheduled')) {
522 $dateClause1[] = ' civicrm_mailing.created_date <= %3 ';
525 $dateClause1[] = 'civicrm_mailing_job.start_date <= %3';
526 $dateClause2[] = 'civicrm_mailing_job.scheduled_date <= %3';
528 $params[3] = [$to, 'String'];
532 if (!empty($dateClause1)) {
533 $dateClauses[] = implode(' AND ', $dateClause1);
535 if (!empty($dateClause2)) {
536 $dateClauses[] = implode(' AND ', $dateClause2);
538 $dateClauses = implode(' OR ', $dateClauses);
539 if (!empty($dateClauses)) {
540 $clauses[] = "({$dateClauses})";
543 if ($this->_parent
->get('sms')) {
544 $clauses[] = "civicrm_mailing.sms_provider_id IS NOT NULL";
547 $clauses[] = "civicrm_mailing.sms_provider_id IS NULL";
550 // get values submitted by form
551 $isDraft = $this->_parent
->get('status_unscheduled');
552 $isArchived = $this->_parent
->get('is_archived');
553 $mailingStatus = $this->_parent
->get('mailing_status');
555 if (!$isFormSubmitted && $this->_parent
->get('scheduled')) {
556 // mimic default behavior for scheduled screen
558 $mailingStatus = ['Scheduled' => 1, 'Complete' => 1, 'Running' => 1, 'Paused' => 1, 'Canceled' => 1];
560 if (!$isFormSubmitted && $this->_parent
->get('archived')) {
561 // mimic default behavior for archived screen
564 if (!$isFormSubmitted && $this->_parent
->get('unscheduled')) {
565 // mimic default behavior for draft screen
571 $statusClauses[] = "civicrm_mailing.scheduled_id IS NULL";
573 if (!empty($mailingStatus)) {
574 $statusClauses[] = "civicrm_mailing_job.status IN ('" . implode("', '", array_keys($mailingStatus)) . "')";
576 if (!empty($statusClauses)) {
577 $clauses[] = "(" . implode(' OR ', $statusClauses) . ")";
580 if (isset($isArchived)) {
582 $clauses[] = "civicrm_mailing.is_archived = 1";
585 $clauses[] = "(civicrm_mailing.is_archived IS NULL OR civicrm_mailing.is_archived = 0)";
590 $this->_parent
->_sortByCharacter
!== NULL
592 $clauses[] = "name LIKE '" . strtolower(CRM_Core_DAO
::escapeWildCardString($this->_parent
->_sortByCharacter
)) . "%'";
595 // dont do a the below assignement when doing a
598 if (count($clauses) > 1) {
599 $this->_parent
->assign('isSearch', 1);
602 $this->_parent
->assign('isSearch', 0);
606 $createOrSentBy = $this->_parent
->get('sort_name');
607 if (!CRM_Utils_System
::isNull($createOrSentBy)) {
608 $clauses[] = '(createdContact.sort_name LIKE %4 OR scheduledContact.sort_name LIKE %4)';
609 $params[4] = ['%' . $createOrSentBy . '%', 'String'];
612 $createdId = $this->_parent
->get('createdId');
614 $clauses[] = "(created_id = {$createdId})";
615 $params[5] = [$createdId, 'Integer'];
618 $campainIds = $this->_parent
->get('campaign_id');
619 if (!CRM_Utils_System
::isNull($campainIds)) {
620 if (!is_array($campainIds)) {
621 $campaignIds = [$campaignIds];
623 $clauses[] = '( campaign_id IN ( ' . implode(' , ', array_values($campainIds)) . ' ) )';
626 if ($language = $this->_parent
->get('language')) {
627 $clauses[] = "civicrm_mailing.language = %6";
628 $params[6] = [$language, 'String'];
631 if (empty($clauses)) {
635 return implode(' AND ', $clauses);
638 public function pagerAtoZ() {
641 $whereClause = $this->whereClause($params, FALSE);
644 SELECT DISTINCT UPPER(LEFT(name, 1)) as sort_name
646 LEFT JOIN civicrm_mailing_job ON (civicrm_mailing_job.mailing_id = civicrm_mailing.id)
647 LEFT JOIN civicrm_contact createdContact ON ( civicrm_mailing.created_id = createdContact.id )
648 LEFT JOIN civicrm_contact scheduledContact ON ( civicrm_mailing.scheduled_id = scheduledContact.id )
650 ORDER BY UPPER(LEFT(name, 1))
653 $dao = CRM_Core_DAO
::executeQuery($query, $params);
655 $aToZBar = CRM_Utils_PagerAToZ
::getAToZBar($dao, $this->_parent
->_sortByCharacter
, TRUE);
656 $this->_parent
->assign('aToZ', $aToZBar);