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
::UPDATE
=> [
249 'name' => ts('Re-Use'),
250 'url' => 'civicrm/mailing/send',
251 'qs' => 'mid=%%mid%%&reset=1',
252 'title' => ts('Re-Send Mailing'),
254 CRM_Core_Action
::DISABLE
=> [
255 'name' => ts('Cancel'),
256 'url' => 'civicrm/mailing/browse',
257 'qs' => 'action=disable&mid=%%mid%%&reset=1',
258 'extra' => 'onclick="if (confirm(\'' . $cancelExtra . '\')) this.href+=\'&confirmed=1\'; else return false;"',
259 'title' => ts('Cancel Mailing'),
261 CRM_Core_Action
::PREVIEW
=> [
262 'name' => ts('Continue'),
263 'url' => 'civicrm/mailing/send',
264 'qs' => 'mid=%%mid%%&continue=true&reset=1',
265 'title' => ts('Continue 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
;
367 if (!in_array($row['id'], $searchMailings)) {
368 if ($allAccess ||
$showCreateLinks) {
369 $actionMask |
= CRM_Core_Action
::UPDATE
;
374 if ($allAccess ||
($showCreateLinks ||
$showScheduleLinks)) {
375 $actionMask = CRM_Core_Action
::PREVIEW
;
378 if (in_array($row['status'], [
384 ($showApprovalLinks && $showCreateLinks && $showScheduleLinks)
387 $actionMask |
= CRM_Core_Action
::DISABLE
;
388 if ($row['status'] == "Paused") {
389 $actionMask |
= CRM_Core_Action
::REOPEN
;
392 $actionMask |
= CRM_Core_Action
::CLOSE
;
395 if ($row['status'] == 'Scheduled' &&
396 empty($row['approval_status_id'])
398 if ($workFlow && ($allAccess ||
$showApprovalLinks)) {
399 $actionMask |
= CRM_Core_Action
::ENABLE
;
404 if (in_array($row['status'], ['Complete', 'Canceled']) &&
407 if ($allAccess ||
$showCreateLinks) {
408 $actionMask |
= CRM_Core_Action
::RENEW
;
412 // check for delete permission.
413 if ($allowToDelete) {
414 $actionMask |
= CRM_Core_Action
::DELETE
;
417 if ($actionMask == NULL) {
418 $actionMask = CRM_Core_Action
::ADD
;
420 // get status strings as per locale settings CRM-4411.
421 $rows[$key]['status'] = CRM_Mailing_BAO_MailingJob
::status($row['status']);
423 // get language string
424 $rows[$key]['language'] = (isset($row['language']) ?
$languages[$row['language']] : NULL);
426 $validLinks = $actionLinks;
427 if (($mailingUrl = CRM_Mailing_BAO_Mailing
::getPublicViewUrl($row['id'])) != FALSE) {
428 $validLinks[CRM_Core_Action
::BROWSE
] = [
429 'name' => ts('Public View'),
430 'url' => 'civicrm/mailing/view',
431 'qs' => 'id=%%hashOrMid%%&reset=1',
432 'title' => ts('Public View'),
435 $actionMask |
= CRM_Core_Action
::BROWSE
;
438 $hash = CRM_Mailing_BAO_Mailing
::getMailingHash($row['id']);
439 $rows[$key]['action'] = CRM_Core_Action
::formLink(
444 'hashOrMid' => $hash ?
$hash : $row['id'],
453 // unset($rows[$key]['id']);
454 // if the scheduled date is 0, replace it with an empty string
455 if ($rows[$key]['scheduled_iso'] == '0000-00-00 00:00:00') {
456 $rows[$key]['scheduled'] = '';
458 unset($rows[$key]['scheduled_iso']);
462 // also initialize the AtoZ pager
468 * Name of export file.
470 * @param string $output
476 public function getExportFileName($output = 'csv') {
477 return ts('CiviMail Mailings');
483 public function setParent($parent) {
484 $this->_parent
= $parent;
488 * @param array $params
489 * @param bool $sortBy
493 public function whereClause(&$params, $sortBy = TRUE) {
494 $values = $clauses = [];
495 $isFormSubmitted = $this->_parent
->get('hidden_find_mailings');
497 $title = $this->_parent
->get('mailing_name');
499 $clauses[] = 'name LIKE %1';
500 if (strpos($title, '%') !== FALSE) {
501 $params[1] = [$title, 'String', FALSE];
504 $params[1] = [$title, 'String', TRUE];
508 $dateClause1 = $dateClause2 = [];
509 $from = $this->_parent
->get('mailing_low');
510 if (!CRM_Utils_System
::isNull($from)) {
511 if ($this->_parent
->get('unscheduled')) {
512 $dateClause1[] = 'civicrm_mailing.created_date >= %2';
515 $dateClause1[] = 'civicrm_mailing_job.start_date >= %2';
516 $dateClause2[] = 'civicrm_mailing_job.scheduled_date >= %2';
518 $params[2] = [$from, 'String'];
521 $to = $this->_parent
->get('mailing_high');
522 if (!CRM_Utils_System
::isNull($to)) {
523 if ($this->_parent
->get('unscheduled')) {
524 $dateClause1[] = ' civicrm_mailing.created_date <= %3 ';
527 $dateClause1[] = 'civicrm_mailing_job.start_date <= %3';
528 $dateClause2[] = 'civicrm_mailing_job.scheduled_date <= %3';
530 $params[3] = [$to, 'String'];
534 if (!empty($dateClause1)) {
535 $dateClauses[] = implode(' AND ', $dateClause1);
537 if (!empty($dateClause2)) {
538 $dateClauses[] = implode(' AND ', $dateClause2);
540 $dateClauses = implode(' OR ', $dateClauses);
541 if (!empty($dateClauses)) {
542 $clauses[] = "({$dateClauses})";
545 if ($this->_parent
->get('sms')) {
546 $clauses[] = "civicrm_mailing.sms_provider_id IS NOT NULL";
549 $clauses[] = "civicrm_mailing.sms_provider_id IS NULL";
552 // get values submitted by form
553 $isDraft = $this->_parent
->get('status_unscheduled');
554 $isArchived = $this->_parent
->get('is_archived');
555 $mailingStatus = $this->_parent
->get('mailing_status');
557 if (!$isFormSubmitted && $this->_parent
->get('scheduled')) {
558 // mimic default behavior for scheduled screen
560 $mailingStatus = ['Scheduled' => 1, 'Complete' => 1, 'Running' => 1, 'Paused' => 1, 'Canceled' => 1];
562 if (!$isFormSubmitted && $this->_parent
->get('archived')) {
563 // mimic default behavior for archived screen
566 if (!$isFormSubmitted && $this->_parent
->get('unscheduled')) {
567 // mimic default behavior for draft screen
573 $statusClauses[] = "civicrm_mailing.scheduled_id IS NULL";
575 if (!empty($mailingStatus)) {
576 $statusClauses[] = "civicrm_mailing_job.status IN ('" . implode("', '", array_keys($mailingStatus)) . "')";
578 if (!empty($statusClauses)) {
579 $clauses[] = "(" . implode(' OR ', $statusClauses) . ")";
582 if (isset($isArchived)) {
584 $clauses[] = "civicrm_mailing.is_archived = 1";
587 $clauses[] = "(civicrm_mailing.is_archived IS NULL OR civicrm_mailing.is_archived = 0)";
592 $this->_parent
->_sortByCharacter
!== NULL
594 $clauses[] = "name LIKE '" . strtolower(CRM_Core_DAO
::escapeWildCardString($this->_parent
->_sortByCharacter
)) . "%'";
597 // dont do a the below assignement when doing a
600 if (count($clauses) > 1) {
601 $this->_parent
->assign('isSearch', 1);
604 $this->_parent
->assign('isSearch', 0);
608 $createOrSentBy = $this->_parent
->get('sort_name');
609 if (!CRM_Utils_System
::isNull($createOrSentBy)) {
610 $clauses[] = '(createdContact.sort_name LIKE %4 OR scheduledContact.sort_name LIKE %4)';
611 $params[4] = ['%' . $createOrSentBy . '%', 'String'];
614 $createdId = $this->_parent
->get('createdId');
616 $clauses[] = "(created_id = {$createdId})";
617 $params[5] = [$createdId, 'Integer'];
620 $campainIds = $this->_parent
->get('campaign_id');
621 if (!CRM_Utils_System
::isNull($campainIds)) {
622 if (!is_array($campainIds)) {
623 $campaignIds = [$campaignIds];
625 $clauses[] = '( campaign_id IN ( ' . implode(' , ', array_values($campainIds)) . ' ) )';
628 if ($language = $this->_parent
->get('language')) {
629 $clauses[] = "civicrm_mailing.language = %6";
630 $params[6] = [$language, 'String'];
633 if (empty($clauses)) {
637 return implode(' AND ', $clauses);
640 public function pagerAtoZ() {
643 $whereClause = $this->whereClause($params, FALSE);
646 SELECT DISTINCT UPPER(LEFT(name, 1)) as sort_name
648 LEFT JOIN civicrm_mailing_job ON (civicrm_mailing_job.mailing_id = civicrm_mailing.id)
649 LEFT JOIN civicrm_contact createdContact ON ( civicrm_mailing.created_id = createdContact.id )
650 LEFT JOIN civicrm_contact scheduledContact ON ( civicrm_mailing.scheduled_id = scheduledContact.id )
652 ORDER BY UPPER(LEFT(name, 1))
655 $dao = CRM_Core_DAO
::executeQuery($query, $params);
657 $aToZBar = CRM_Utils_PagerAToZ
::getAToZBar($dao, $this->_parent
->_sortByCharacter
, TRUE);
658 $this->_parent
->assign('aToZ', $aToZBar);