Merge pull request #8491 from seamuslee001/CRM-18752
[civicrm-core.git] / CRM / Contact / Form / Search / Custom / ActivitySearch.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
fa938177 6 | Copyright CiviCRM LLC (c) 2004-2016 |
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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
fa938177 31 * @copyright CiviCRM LLC (c) 2004-2016
6a488035 32 */
17da84f5 33class CRM_Contact_Form_Search_Custom_ActivitySearch extends CRM_Contact_Form_Search_Custom_Base implements CRM_Contact_Form_Search_Interface {
6a488035 34
430ae6dd 35 protected $_formValues;
d14ccbdc
SL
36 protected $_aclFrom = NULL;
37 protected $_aclWhere = NULL;
430ae6dd 38
86538308 39 /**
5a409b50 40 * Class constructor.
41 *
42 * @param array $formValues
86538308 43 */
00be9182 44 public function __construct(&$formValues) {
6a488035
TO
45 $this->_formValues = $formValues;
46
47 /**
48 * Define the columns for search result rows
49 */
50 $this->_columns = array(
51 ts('Name') => 'sort_name',
52 ts('Status') => 'activity_status',
53 ts('Activity Type') => 'activity_type',
54 ts('Activity Subject') => 'activity_subject',
55 ts('Scheduled By') => 'source_contact',
56 ts('Scheduled Date') => 'activity_date',
ba8f6a69
CW
57 ' ' => 'activity_id',
58 ' ' => 'activity_type_id',
59 ' ' => 'case_id',
6a488035
TO
60 ts('Location') => 'location',
61 ts('Duration') => 'duration',
62 ts('Details') => 'details',
63 ts('Assignee') => 'assignee',
64 );
65
66 $this->_groupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup',
67 'activity_status',
68 'id',
69 'name'
70 );
71
72 //Add custom fields to columns array for inclusion in export
18b623d0 73 $groupTree = CRM_Core_BAO_CustomGroup::getTree('Activity');
6a488035 74
6a488035 75 //use simplified formatted groupTree
18b623d0 76 $groupTree = CRM_Core_BAO_CustomGroup::formatGroupTree($groupTree);
6a488035
TO
77
78 //cycle through custom fields and assign to _columns array
79 foreach ($groupTree as $key) {
80 foreach ($key['fields'] as $field) {
81 $fieldlabel = $key['title'] . ": " . $field['label'];
82 $this->_columns[$fieldlabel] = $field['column_name'];
83 }
84 }
6a488035
TO
85 }
86
86538308 87 /**
c490a46a 88 * @param CRM_Core_Form $form
86538308 89 */
00be9182 90 public function buildForm(&$form) {
6a488035
TO
91
92 /**
93 * You can define a custom title for the search form
94 */
95 $this->setTitle('Find Latest Activities');
96
97 /**
98 * Define the search form fields here
99 */
100 // Allow user to choose which type of contact to limit search on
101 $form->add('select', 'contact_type', ts('Find...'), CRM_Core_SelectValues::contactType());
102
103 // Text box for Activity Subject
104 $form->add('text',
105 'activity_subject',
106 ts('Activity Subject')
107 );
108
109 // Select box for Activity Type
110 $activityType = array('' => ' - select activity - ') + CRM_Core_PseudoConstant::activityType();
111
112 $form->add('select', 'activity_type_id', ts('Activity Type'),
113 $activityType,
114 FALSE
115 );
116
117 // textbox for Activity Status
118 $activityStatus = array('' => ' - select status - ') + CRM_Core_PseudoConstant::activityStatus();
119
120 $form->add('select', 'activity_status_id', ts('Activity Status'),
121 $activityStatus,
122 FALSE
123 );
124
125 // Activity Date range
126 $form->addDate('start_date', ts('Activity Date From'), FALSE, array('formatType' => 'custom'));
127 $form->addDate('end_date', ts('...through'), FALSE, array('formatType' => 'custom'));
128
6a488035
TO
129 // Contact Name field
130 $form->add('text', 'sort_name', ts('Contact Name'));
131
132 /**
133 * If you are using the sample template, this array tells the template fields to render
134 * for the search form.
135 */
136 $form->assign('elements', array(
353ffa53
TO
137 'contact_type',
138 'activity_subject',
139 'activity_type_id',
140 'activity_status_id',
141 'start_date',
142 'end_date',
143 'sort_name',
144 ));
6a488035
TO
145 }
146
147 /**
148 * Define the smarty template used to layout the search form and results listings.
149 */
00be9182 150 public function templateFile() {
6a488035
TO
151 return 'CRM/Contact/Form/Search/Custom/ActivitySearch.tpl';
152 }
153
154 /**
fe482240 155 * Construct the search query.
54957108 156 *
157 * @param int $offset
158 * @param int $rowcount
159 * @param null $sort
160 * @param bool $includeContactIDs
161 * @param bool $justIDs
162 *
163 * @return string
6a488035 164 */
d5cc0fc2 165 public function all(
51ccfbbe 166 $offset = 0, $rowcount = 0, $sort = NULL,
6a488035
TO
167 $includeContactIDs = FALSE, $justIDs = FALSE
168 ) {
169
170 // SELECT clause must include contact_id as an alias for civicrm_contact.id
171 if ($justIDs) {
172 $select = 'contact_a.id as contact_id';
173 }
174 else {
175 $select = '
176 contact_a.id as contact_id,
177 contact_a.sort_name as sort_name,
178 contact_a.contact_type as contact_type,
179 activity.id as activity_id,
180 activity.activity_type_id as activity_type_id,
181 contact_b.sort_name as source_contact,
182 ov1.label as activity_type,
183 activity.subject as activity_subject,
184 activity.activity_date_time as activity_date,
185 ov2.label as activity_status,
186 cca.case_id as case_id,
187 activity.location as location,
188 activity.duration as duration,
189 activity.details as details,
190 assignment.activity_id as assignment_activity,
191 contact_c.display_name as assignee
192 ';
193 }
194
195 $from = $this->from();
196
197 $where = $this->where($includeContactIDs);
198
199 if (!empty($where)) {
200 $where = "WHERE $where";
201 }
202
203 // add custom group fields to SELECT and FROM clause
48cba3e6 204 $groupTree = CRM_Core_BAO_CustomGroup::getTree('Activity');
6a488035
TO
205
206 foreach ($groupTree as $key) {
7c34ab11 207 if (!empty($key['extends']) && $key['extends'] == 'Activity') {
6a488035
TO
208 $select .= ", " . $key['table_name'] . ".*";
209 $from .= " LEFT JOIN " . $key['table_name'] . " ON " . $key['table_name'] . ".entity_id = activity.id";
210 }
211 }
212 // end custom groups add
213
214 $sql = " SELECT $select FROM $from $where ";
215
216 //no need to add order when only contact Ids.
217 if (!$justIDs) {
218 // Define ORDER BY for query in $sort, with default value
219 if (!empty($sort)) {
220 if (is_string($sort)) {
21d32567 221 $sort = CRM_Utils_Type::escape($sort, 'String');
6a488035
TO
222 $sql .= " ORDER BY $sort ";
223 }
224 else {
225 $sql .= ' ORDER BY ' . trim($sort->orderBy());
226 }
227 }
228 else {
229 $sql .= 'ORDER BY contact_a.sort_name, activity.activity_date_time DESC, activity.activity_type_id, activity.status_id, activity.subject';
230 }
231 }
7c34ab11 232 else {
26a9b6ab
C
233 //CRM-14107, since there could be multiple activities against same contact,
234 //we need to provide GROUP BY on contact id to prevent duplicacy on prev/next entries
235 $sql .= 'GROUP BY contact_a.id
236ORDER BY contact_a.sort_name';
7c34ab11 237 }
6a488035
TO
238
239 if ($rowcount > 0 && $offset >= 0) {
bf00d1b6 240 $offset = CRM_Utils_Type::escape($offset, 'Int');
dd3a4117 241 $rowcount = CRM_Utils_Type::escape($rowcount, 'Int');
6a488035
TO
242 $sql .= " LIMIT $offset, $rowcount ";
243 }
244 return $sql;
245 }
246
86538308 247 /**
4f1f1f2a
CW
248 * Alters the date display in the Activity Date Column. We do this after we already have
249 * the result so that sorting on the date column stays pertinent to the numeric date value
86538308
EM
250 * @param $row
251 */
00be9182 252 public function alterRow(&$row) {
6a488035
TO
253 $row['activity_date'] = CRM_Utils_Date::customFormat($row['activity_date'], '%B %E%f, %Y %l:%M %P');
254 }
255
86538308 256 /**
4f1f1f2a 257 * Regular JOIN statements here to limit results to contacts who have activities.
86538308
EM
258 * @return string
259 */
00be9182 260 public function from() {
47b8444f 261 $this->buildACLClause('contact_a');
e7e657f0 262 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
9e74e3ce 263 $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
ecaec004
RN
264 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
265 $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
266
d14ccbdc 267 $from = "
ecaec004
RN
268 civicrm_activity activity
269 LEFT JOIN civicrm_activity_contact target
270 ON activity.id = target.activity_id AND target.record_type_id = {$targetID}
271 JOIN civicrm_contact contact_a
272 ON contact_a.id = target.contact_id
6a488035
TO
273 JOIN civicrm_option_value ov1
274 ON activity.activity_type_id = ov1.value AND ov1.option_group_id = 2
275 JOIN civicrm_option_value ov2
276 ON activity.status_id = ov2.value AND ov2.option_group_id = {$this->_groupId}
ecaec004 277 LEFT JOIN civicrm_activity_contact sourceContact
8ef12e64 278 ON activity.id = sourceContact.activity_id AND sourceContact.record_type_id = {$sourceID}
6a488035 279 JOIN civicrm_contact contact_b
ecaec004 280 ON sourceContact.contact_id = contact_b.id
6a488035
TO
281 LEFT JOIN civicrm_case_activity cca
282 ON activity.id = cca.activity_id
38ba593b 283 LEFT JOIN civicrm_activity_contact assignment
9e74e3ce 284 ON activity.id = assignment.activity_id AND assignment.record_type_id = {$assigneeID}
6a488035 285 LEFT JOIN civicrm_contact contact_c
d14ccbdc
SL
286 ON assignment.contact_id = contact_c.id {$this->_aclFrom}";
287
d14ccbdc 288 return $from;
6a488035
TO
289 }
290
86538308 291 /**
fe482240 292 * WHERE clause is an array built from any required JOINS plus conditional filters based on search criteria field values.
c490a46a 293 *
86538308
EM
294 * @param bool $includeContactIDs
295 *
296 * @return string
297 */
00be9182 298 public function where($includeContactIDs = FALSE) {
6a488035
TO
299 $clauses = array();
300
301 // add contact name search; search on primary name, source contact, assignee
302 $contactname = $this->_formValues['sort_name'];
303 if (!empty($contactname)) {
353ffa53 304 $dao = new CRM_Core_DAO();
6a488035 305 $contactname = $dao->escape($contactname);
353ffa53 306 $clauses[] = "(contact_a.sort_name LIKE '%{$contactname}%' OR
6a488035
TO
307 contact_b.sort_name LIKE '%{$contactname}%' OR
308 contact_c.display_name LIKE '%{$contactname}%')";
309 }
310
311 $subject = $this->_formValues['activity_subject'];
312
313 if (!empty($this->_formValues['contact_type'])) {
314 $clauses[] = "contact_a.contact_type LIKE '%{$this->_formValues['contact_type']}%'";
315 }
316
317 if (!empty($subject)) {
353ffa53
TO
318 $dao = new CRM_Core_DAO();
319 $subject = $dao->escape($subject);
6a488035
TO
320 $clauses[] = "activity.subject LIKE '%{$subject}%'";
321 }
322
323 if (!empty($this->_formValues['activity_status_id'])) {
324 $clauses[] = "activity.status_id = {$this->_formValues['activity_status_id']}";
325 }
326
327 if (!empty($this->_formValues['activity_type_id'])) {
328 $clauses[] = "activity.activity_type_id = {$this->_formValues['activity_type_id']}";
329 }
330
331 $startDate = $this->_formValues['start_date'];
332 if (!empty($startDate)) {
333 $startDate .= '00:00:00';
334 $startDateFormatted = CRM_Utils_Date::processDate($startDate);
335 if ($startDateFormatted) {
336 $clauses[] = "activity.activity_date_time >= $startDateFormatted";
337 }
338 }
339
340 $endDate = $this->_formValues['end_date'];
341 if (!empty($endDate)) {
342 $endDate .= '23:59:59';
343 $endDateFormatted = CRM_Utils_Date::processDate($endDate);
344 if ($endDateFormatted) {
345 $clauses[] = "activity.activity_date_time <= $endDateFormatted";
346 }
347 }
348
349 if ($includeContactIDs) {
350 $contactIDs = array();
351 foreach ($this->_formValues as $id => $value) {
352 if ($value &&
353 substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX
354 ) {
355 $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN);
356 }
357 }
358
359 if (!empty($contactIDs)) {
360 $contactIDs = implode(', ', $contactIDs);
361 $clauses[] = "contact_a.id IN ( $contactIDs )";
362 }
363 }
364
47b8444f
SL
365 if ($this->_aclWhere) {
366 $clauses[] = " {$this->_aclWhere} ";
367 }
6a488035
TO
368 return implode(' AND ', $clauses);
369 }
370
546b78fa 371 /*
6a488035 372 * Functions below generally don't need to be modified
546b78fa
CW
373 */
374
375 /**
376 * @inheritDoc
6a488035 377 */
00be9182 378 public function count() {
6a488035
TO
379 $sql = $this->all();
380
381 $dao = CRM_Core_DAO::executeQuery($sql,
382 CRM_Core_DAO::$_nullArray
383 );
384 return $dao->N;
385 }
386
86538308
EM
387 /**
388 * @param int $offset
389 * @param int $rowcount
390 * @param null $sort
d14ccbdc 391 * @param bool $returnSQL Not used; included for consistency with parent; SQL is always returned
86538308
EM
392 *
393 * @return string
394 */
e98a9804 395 public function contactIDs($offset = 0, $rowcount = 0, $sort = NULL, $returnSQL = TRUE) {
6a488035
TO
396 return $this->all($offset, $rowcount, $sort, FALSE, TRUE);
397 }
398
86538308
EM
399 /**
400 * @return array
401 */
00be9182 402 public function &columns() {
6a488035
TO
403 return $this->_columns;
404 }
405
86538308
EM
406 /**
407 * @param $title
408 */
00be9182 409 public function setTitle($title) {
6a488035
TO
410 if ($title) {
411 CRM_Utils_System::setTitle($title);
412 }
413 else {
414 CRM_Utils_System::setTitle(ts('Search'));
415 }
416 }
417
86538308
EM
418 /**
419 * @return null
420 */
00be9182 421 public function summary() {
6a488035
TO
422 return NULL;
423 }
96025800 424
d14ccbdc
SL
425 /**
426 * @param string $tableAlias
427 */
428 public function buildACLClause($tableAlias = 'contact') {
429 list($this->_aclFrom, $this->_aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause($tableAlias);
430 }
431
6a488035 432}