INFRA-132 - CRM/Mailing - phpcbf
[civicrm-core.git] / CRM / Mailing / Selector / Browse.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
32 * $Id$
33 *
34 */
35
36/**
37 * This class is used to browse past mailings.
38 */
39class CRM_Mailing_Selector_Browse extends CRM_Core_Selector_Base implements CRM_Core_Selector_API {
40
41 /**
100fef9d 42 * Array of supported links, currenly null
6a488035
TO
43 *
44 * @var array
45 * @static
46 */
47 static $_links = NULL;
48
49 /**
100fef9d 50 * We use desc to remind us what that column is, name is used in the tpl
6a488035
TO
51 *
52 * @var array
53 * @static
54 */
55 static $_columnHeaders;
56
57 protected $_parent;
58
59 /**
60 * Class constructor
61 *
6a488035 62 *
6c8f6e67
EM
63 * @return \CRM_Mailing_Selector_Browse
64 @access public
6a488035 65 */
00be9182 66 public function __construct() {
6a488035 67 }
6a488035
TO
68
69 /**
70 * This method returns the links that are given for each search row.
71 *
72 * @return array
6a488035
TO
73 *
74 */
00be9182 75 public static function &links() {
6a488035
TO
76 return self::$_links;
77 }
6a488035
TO
78
79 /**
100fef9d 80 * Getter for array of the parameters required for creating pager.
6a488035 81 *
dd244018 82 * @param $action
c490a46a 83 * @param array $params
dd244018 84 *
6a488035 85 */
00be9182 86 public function getPagerParams($action, &$params) {
6a488035
TO
87 $params['csvString'] = NULL;
88 $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT;
89 $params['status'] = ts('Mailings %%StatusMessage%%');
90 $params['buttonTop'] = 'PagerTopButton';
91 $params['buttonBottom'] = 'PagerBottomButton';
92 }
6a488035
TO
93
94 /**
100fef9d 95 * Returns the column headers as an array of tuples:
6a488035
TO
96 * (name, sortName (key to the sort array))
97 *
90c8230e
TO
98 * @param string $action
99 * The action being performed.
100 * @param enum $output
101 * What should the result set include (web/email/csv).
6a488035
TO
102 *
103 * @return array the column headers that need to be displayed
6a488035 104 */
00be9182 105 public function &getColumnHeaders($action = NULL, $output = NULL) {
6a488035 106 $mailing = CRM_Mailing_BAO_Mailing::getTableName();
9da8dc8c 107 $job = CRM_Mailing_BAO_MailingJob::getTableName();
6a488035
TO
108 if (!isset(self::$_columnHeaders)) {
109 $completedOrder = NULL;
110
111 // Set different default sort depending on type of mailings (CRM-7652)
112 $unscheduledOrder = $scheduledOrder = $archivedOrder = CRM_Utils_Sort::DONTCARE;
113 if ($this->_parent->get('unscheduled')) {
114 $unscheduledOrder = CRM_Utils_Sort::DESCENDING;
115 }
116 elseif ($this->_parent->get('scheduled')) {
117 $scheduledOrder = CRM_Utils_Sort::DESCENDING;
118 }
119 else {
120 // sort by completed date for archived and undefined get
121 $completedOrder = CRM_Utils_Sort::DESCENDING;
122 }
123 $nameHeaderLabel = ($this->_parent->get('sms')) ? ts('SMS Name') : ts('Mailing Name');
124
125 self::$_columnHeaders = array(
126 array(
127 'name' => $nameHeaderLabel,
128 'sort' => 'name',
129 'direction' => CRM_Utils_Sort::DONTCARE,
130 ),
131 array(
132 'name' => ts('Status'),
133 'sort' => 'status',
134 'direction' => CRM_Utils_Sort::DONTCARE,
135 ),
136 array(
137 'name' => ts('Created By'),
138 'sort' => 'created_by',
139 'direction' => CRM_Utils_Sort::DONTCARE,
140 ),
141 array(
142 'name' => ts('Created Date'),
143 'sort' => 'created_date',
144 'direction' => $unscheduledOrder,
145 ),
146 array(
147 'name' => ts('Sent By'),
148 'sort' => 'scheduled_by',
149 'direction' => CRM_Utils_Sort::DONTCARE,
150 ),
151 array(
152 'name' => ts('Scheduled'),
153 'sort' => 'scheduled_date',
154 'direction' => $scheduledOrder,
155 ),
156 array(
157 'name' => ts('Started'),
158 'sort' => 'start_date',
159 'direction' => CRM_Utils_Sort::DONTCARE,
160 ),
161 array(
162 'name' => ts('Completed'),
163 'sort' => 'end_date',
164 'direction' => $completedOrder,
165 ),
166 );
167
168 if (CRM_Campaign_BAO_Campaign::isCampaignEnable()) {
35f7561f
TO
169 self::$_columnHeaders[] = array(
170 'name' => ts('Campaign'),
6a488035
TO
171 'sort' => 'campaign_id',
172 'direction' => CRM_Utils_Sort::DONTCARE,
173 );
174 }
175
176 if ($output != CRM_Core_Selector_Controller::EXPORT) {
177 self::$_columnHeaders[] = array('name' => ts('Action'));
178 }
179 }
180 return self::$_columnHeaders;
181 }
182
183 /**
184 * Returns total number of rows for the query.
185 *
186 * @param
187 *
188 * @return int Total number of rows
6a488035 189 */
00be9182 190 public function getTotalCount($action) {
9da8dc8c 191 $job = CRM_Mailing_BAO_MailingJob::getTableName();
6a488035
TO
192 $mailing = CRM_Mailing_BAO_Mailing::getTableName();
193 $mailingACL = CRM_Mailing_BAO_Mailing::mailingACL();
194
195 //get the where clause.
196 $params = array();
197 $whereClause = "$mailingACL AND " . $this->whereClause($params);
198
199 // CRM-11919 added addition ON clauses to mailing_job to match getRows
200 $query = "
201 SELECT COUNT( DISTINCT $mailing.id ) as count
202 FROM $mailing
203LEFT JOIN $job ON ( $mailing.id = $job.mailing_id AND civicrm_mailing_job.is_test = 0 AND civicrm_mailing_job.parent_id IS NULL )
204LEFT JOIN civicrm_contact createdContact ON ( $mailing.created_id = createdContact.id )
205LEFT JOIN civicrm_contact scheduledContact ON ( $mailing.scheduled_id = scheduledContact.id )
206 WHERE $whereClause";
207
208 return CRM_Core_DAO::singleValueQuery($query, $params);
209 }
210
211 /**
100fef9d 212 * Returns all the rows in the given offset and rowCount
6a488035 213 *
90c8230e
TO
214 * @param enum $action
215 * The action being performed.
216 * @param int $offset
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 enum $output
223 * What should the result set include (web/email/csv).
6a488035
TO
224 *
225 * @return int the total number of rows for this action
226 */
00be9182 227 public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
6a488035
TO
228 static $actionLinks = NULL;
229 if (empty($actionLinks)) {
230 $cancelExtra = ts('Are you sure you want to cancel this mailing?');
231 $deleteExtra = ts('Are you sure you want to delete this mailing?');
232 $archiveExtra = ts('Are you sure you want to archive this mailing?');
233
234 $actionLinks = array(
235 CRM_Core_Action::ENABLE => array(
236 'name' => ts('Approve/Reject'),
237 'url' => 'civicrm/mailing/approve',
238 'qs' => 'mid=%%mid%%&reset=1',
239 'title' => ts('Approve/Reject Mailing'),
240 ),
241 CRM_Core_Action::VIEW => array(
242 'name' => ts('Report'),
243 'url' => 'civicrm/mailing/report',
244 'qs' => 'mid=%%mid%%&reset=1',
245 'title' => ts('View Mailing Report'),
246 ),
247 CRM_Core_Action::UPDATE => array(
248 'name' => ts('Re-Use'),
249 'url' => 'civicrm/mailing/send',
250 'qs' => 'mid=%%mid%%&reset=1',
251 'title' => ts('Re-Send Mailing'),
252 ),
253 CRM_Core_Action::DISABLE => array(
254 'name' => ts('Cancel'),
255 'url' => 'civicrm/mailing/browse',
256 'qs' => 'action=disable&mid=%%mid%%&reset=1',
257 'extra' => 'onclick="if (confirm(\'' . $cancelExtra . '\')) this.href+=\'&amp;confirmed=1\'; else return false;"',
258 'title' => ts('Cancel Mailing'),
259 ),
260 CRM_Core_Action::PREVIEW => array(
261 'name' => ts('Continue'),
262 'url' => 'civicrm/mailing/send',
263 'qs' => 'mid=%%mid%%&continue=true&reset=1',
264 'title' => ts('Continue Mailing'),
265 ),
266 CRM_Core_Action::DELETE => array(
267 'name' => ts('Delete'),
268 'url' => 'civicrm/mailing/browse',
269 'qs' => 'action=delete&mid=%%mid%%&reset=1',
270 'extra' => 'onclick="if (confirm(\'' . $deleteExtra . '\')) this.href+=\'&amp;confirmed=1\'; else return false;"',
271 'title' => ts('Delete Mailing'),
272 ),
273 CRM_Core_Action::RENEW => array(
274 'name' => ts('Archive'),
275 'url' => 'civicrm/mailing/browse/archived',
276 'qs' => 'action=renew&mid=%%mid%%&reset=1',
277 'extra' => 'onclick="if (confirm(\'' . $archiveExtra . '\')) this.href+=\'&amp;confirmed=1\'; else return false;"',
278 'title' => ts('Archive Mailing'),
279 ),
280 );
281 }
282
283 $allAccess = TRUE;
284 $workFlow = $showApprovalLinks = $showScheduleLinks = $showCreateLinks = FALSE;
285 if (CRM_Mailing_Info::workflowEnabled()) {
286 $allAccess = FALSE;
287 $workFlow = TRUE;
288 //supercedes all permission
289 if (CRM_Core_Permission::check('access CiviMail')) {
290 $allAccess = TRUE;
291 }
292
293 if (CRM_Core_Permission::check('approve mailings')) {
294 $showApprovalLinks = TRUE;
295 }
296
297 if (CRM_Core_Permission::check('create mailings')) {
298 $showCreateLinks = TRUE;
299 }
300
301 if (CRM_Core_Permission::check('schedule mailings')) {
302 $showScheduleLinks = TRUE;
303 }
304 }
305 $mailing = new CRM_Mailing_BAO_Mailing();
306
307 $params = array();
308
309 $whereClause = ' AND ' . $this->whereClause($params);
310
311 if (empty($params)) {
312 $this->_parent->assign('isSearch', 0);
313 }
314 else {
315 $this->_parent->assign('isSearch', 1);
316 }
317 $rows = &$mailing->getRows($offset, $rowCount, $sort, $whereClause, $params);
318
319 //get the search base mailing Ids, CRM-3711.
320 $searchMailings = $mailing->searchMailingIDs();
321
322 //check for delete CRM-4418
323 $allowToDelete = CRM_Core_Permission::check('delete in CiviMail');
324
325 if ($output != CRM_Core_Selector_Controller::EXPORT) {
326
327 //create the appropriate $op to use for hook_civicrm_links
328 $pageTypes = array('view', 'mailing', 'browse');
329 if ($this->_parent->_unscheduled) {
330 $pageTypes[] = 'unscheduled';
331 }
332 if ($this->_parent->_scheduled) {
333 $pageTypes[] = 'scheduled';
334 }
335 if ($this->_parent->_archived) {
336 $pageTypes[] = 'archived';
337 }
338 $opString = implode('.', $pageTypes);
339
340 foreach ($rows as $key => $row) {
341 $actionMask = NULL;
342 if ($row['sms_provider_id']) {
343 $actionLinks[CRM_Core_Action::PREVIEW]['url'] = 'civicrm/sms/send';
344 }
345
346 if (!($row['status'] == 'Not scheduled') && !$row['sms_provider_id']) {
347 if ($allAccess || $showCreateLinks) {
348 $actionMask = CRM_Core_Action::VIEW;
349 }
350
351 if (!in_array($row['id'], $searchMailings)) {
352 if ($allAccess || $showCreateLinks) {
353 $actionMask |= CRM_Core_Action::UPDATE;
354 }
355 }
356 }
357 else {
358 if ($allAccess || ($showCreateLinks || $showScheduleLinks)) {
359 $actionMask = CRM_Core_Action::PREVIEW;
360 }
361 }
362 if (in_array($row['status'], array(
363 'Scheduled', 'Running', 'Paused'))) {
364 if ($allAccess ||
365 ($showApprovalLinks && $showCreateLinks && $showScheduleLinks)
366 ) {
367
368 $actionMask |= CRM_Core_Action::DISABLE;
369 }
370 if ($row['status'] == 'Scheduled' &&
371 empty($row['approval_status_id'])
372 ) {
373 if ($workFlow && ($allAccess || $showApprovalLinks)) {
374 $actionMask |= CRM_Core_Action::ENABLE;
375 }
376 }
377 }
378
dd244018 379 if (in_array($row['status'], array('Complete', 'Canceled')) &&
6eb1b55e 380 !$row['archived']) {
6a488035
TO
381 if ($allAccess || $showCreateLinks) {
382 $actionMask |= CRM_Core_Action::RENEW;
383 }
384 }
385
386 //check for delete permission.
387 if ($allowToDelete) {
388 $actionMask |= CRM_Core_Action::DELETE;
389 }
390
391 if ($actionMask == NULL) {
392 $actionMask = CRM_Core_Action::ADD;
393 }
394 //get status strings as per locale settings CRM-4411.
9da8dc8c 395 $rows[$key]['status'] = CRM_Mailing_BAO_MailingJob::status($row['status']);
6a488035
TO
396
397 $rows[$key]['action'] = CRM_Core_Action::formLink($actionLinks,
398 $actionMask,
399 array('mid' => $row['id']),
400 "more",
401 FALSE,
402 $opString,
403 "Mailing",
404 $row['id']
405 );
406
407 //unset($rows[$key]['id']);
408 // if the scheduled date is 0, replace it with an empty string
409 if ($rows[$key]['scheduled_iso'] == '0000-00-00 00:00:00') {
410 $rows[$key]['scheduled'] = '';
411 }
412 unset($rows[$key]['scheduled_iso']);
413 }
414 }
415
416 // also initialize the AtoZ pager
417 $this->pagerAtoZ();
418 return $rows;
419 }
420
421 /**
100fef9d 422 * Name of export file.
6a488035 423 *
90c8230e
TO
424 * @param string $output
425 * Type of output.
6a488035
TO
426 *
427 * @return string name of the file
428 */
00be9182 429 public function getExportFileName($output = 'csv') {
6a488035
TO
430 return ts('CiviMail Mailings');
431 }
432
e0ef6999
EM
433 /**
434 * @param $parent
435 */
00be9182 436 public function setParent($parent) {
6a488035
TO
437 $this->_parent = $parent;
438 }
439
e0ef6999 440 /**
c490a46a 441 * @param array $params
e0ef6999
EM
442 * @param bool $sortBy
443 *
444 * @return int|string
445 */
00be9182 446 public function whereClause(&$params, $sortBy = TRUE) {
6a488035 447 $values = $clauses = array();
f5d7a1ab 448 $isFormSubmitted = $this->_parent->get('hidden_find_mailings');
6a488035 449
f5d7a1ab 450 $title = $this->_parent->get('mailing_name');
6a488035
TO
451 if ($title) {
452 $clauses[] = 'name LIKE %1';
453 if (strpos($title, '%') !== FALSE) {
454 $params[1] = array($title, 'String', FALSE);
455 }
456 else {
457 $params[1] = array($title, 'String', TRUE);
458 }
459 }
460
f6df2c32 461 $dateClause1 = $dateClause2 = array();
6a488035
TO
462 $from = $this->_parent->get('mailing_from');
463 if (!CRM_Utils_System::isNull($from)) {
2d882552
PJ
464 if ($this->_parent->get('unscheduled')) {
465 $dateClause1[] = 'civicrm_mailing.created_date >= %2';
466 }
467 else {
468 $dateClause1[] = 'civicrm_mailing_job.start_date >= %2';
469 $dateClause2[] = 'civicrm_mailing_job.scheduled_date >= %2';
470 }
471 $params[2] = array($from, 'String');
6a488035
TO
472 }
473
474 $to = $this->_parent->get('mailing_to');
475 if (!CRM_Utils_System::isNull($to)) {
2d882552
PJ
476 if ($this->_parent->get('unscheduled')) {
477 $dateClause1[] = ' civicrm_mailing.created_date <= %3 ';
478 }
479 else {
480 $dateClause1[] = 'civicrm_mailing_job.start_date <= %3';
481 $dateClause2[] = 'civicrm_mailing_job.scheduled_date <= %3';
482 }
6a488035
TO
483 $params[3] = array($to, 'String');
484 }
485
f6df2c32 486 $dateClauses = array();
6a488035 487 if (!empty($dateClause1)) {
f6df2c32
DS
488 $dateClauses[] = implode(' AND ', $dateClause1);
489 }
490 if (!empty($dateClause2)) {
491 $dateClauses[] = implode(' AND ', $dateClause2);
492 }
493 $dateClauses = implode(' OR ', $dateClauses);
494 if (!empty($dateClauses)) {
495 $clauses[] = "({$dateClauses})";
6a488035
TO
496 }
497
6a488035 498 if ($this->_parent->get('sms')) {
f6df2c32 499 $clauses[] = "civicrm_mailing.sms_provider_id IS NOT NULL";
6a488035
TO
500 }
501 else {
f6df2c32 502 $clauses[] = "civicrm_mailing.sms_provider_id IS NULL";
6a488035
TO
503 }
504
f5d7a1ab
DS
505 // get values submitted by form
506 $isDraft = $this->_parent->get('status_unscheduled');
507 $isArchived = $this->_parent->get('is_archived');
f6df2c32
DS
508 $mailingStatus = $this->_parent->get('mailing_status');
509
f5d7a1ab
DS
510 if (!$isFormSubmitted && $this->_parent->get('scheduled')) {
511 // mimic default behavior for scheduled screen
512 $isArchived = 0;
513 $mailingStatus = array('Scheduled' => 1, 'Complete' => 1, 'Running' => 1, 'Canceled' => 1);
514 }
515 if (!$isFormSubmitted && $this->_parent->get('archived')) {
516 // mimic default behavior for archived screen
517 $isArchived = 1;
518 }
519 if (!$isFormSubmitted && $this->_parent->get('unscheduled')) {
520 // mimic default behavior for draft screen
521 $isDraft = 1;
522 }
523
753f3087 524 $statusClauses = array();
f5d7a1ab 525 if ($isDraft) {
753f3087 526 $statusClauses[] = "civicrm_mailing.scheduled_id IS NULL";
f5d7a1ab 527 }
f6df2c32 528 if (!empty($mailingStatus)) {
753f3087
DS
529 $statusClauses[] = "civicrm_mailing_job.status IN ('" . implode("', '", array_keys($mailingStatus)) . "')";
530 }
531 if (!empty($statusClauses)) {
532 $clauses[] = "(" . implode(' OR ', $statusClauses) . ")";
2d882552 533 }
cbb4cb7b 534
f6df2c32
DS
535 if (isset($isArchived)) {
536 if ($isArchived) {
753f3087 537 $clauses[] = "civicrm_mailing.is_archived = 1";
f6df2c32
DS
538 } else {
539 $clauses[] = "(civicrm_mailing.is_archived IS NULL OR civicrm_mailing.is_archived = 0)";
6a488035 540 }
2d882552
PJ
541 }
542
6a488035
TO
543 if ($sortBy &&
544 $this->_parent->_sortByCharacter !== NULL
545 ) {
546 $clauses[] = "name LIKE '" . strtolower(CRM_Core_DAO::escapeWildCardString($this->_parent->_sortByCharacter)) . "%'";
547 }
548
549 // dont do a the below assignement when doing a
550 // AtoZ pager clause
551 if ($sortBy) {
552 if (count($clauses) > 1) {
553 $this->_parent->assign('isSearch', 1);
554 }
555 else {
556 $this->_parent->assign('isSearch', 0);
557 }
558 }
559
560 $createOrSentBy = $this->_parent->get('sort_name');
561 if (!CRM_Utils_System::isNull($createOrSentBy)) {
562 $clauses[] = '(createdContact.sort_name LIKE %4 OR scheduledContact.sort_name LIKE %4)';
563 $params[4] = array('%' . $createOrSentBy . '%', 'String');
564 }
565
566 $createdId = $this->_parent->get('createdId');
567 if ($createdId) {
568 $clauses[] = "(created_id = {$createdId})";
569 $params[5] = array($createdId, 'Integer');
570 }
571
572 $campainIds = $this->_parent->get('campaign_id');
573 if (!CRM_Utils_System::isNull($campainIds)) {
574 if (!is_array($campainIds)) {
575 $campaignIds = array($campaignIds);
576 }
577 $clauses[] = '( campaign_id IN ( ' . implode(' , ', array_values($campainIds)) . ' ) )';
578 }
579
580 if (empty($clauses)) {
581 return 1;
582 }
583
584 return implode(' AND ', $clauses);
585 }
586
00be9182 587 public function pagerAtoZ() {
6a488035
TO
588
589 $params = array();
590 $whereClause = $this->whereClause($params, FALSE);
591
592 $query = "
593SELECT DISTINCT UPPER(LEFT(name, 1)) as sort_name
594FROM civicrm_mailing
595LEFT JOIN civicrm_mailing_job ON (civicrm_mailing_job.mailing_id = civicrm_mailing.id)
596LEFT JOIN civicrm_contact createdContact ON ( civicrm_mailing.created_id = createdContact.id )
597LEFT JOIN civicrm_contact scheduledContact ON ( civicrm_mailing.scheduled_id = scheduledContact.id )
598WHERE $whereClause
599ORDER BY LEFT(name, 1)
600";
601
602 $dao = CRM_Core_DAO::executeQuery($query, $params);
603
604 $aToZBar = CRM_Utils_PagerAToZ::getAToZBar($dao, $this->_parent->_sortByCharacter, TRUE);
605 $this->_parent->assign('aToZ', $aToZBar);
606 }
607}