PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/civicrm/ext/legacycustomsearches/CRM/Contact/Form/Search/Custom/ActivitySearch.php

https://github.com/nysenate/Bluebird-CRM
PHP | 431 lines | 256 code | 55 blank | 120 comment | 27 complexity | e53da287b0276ec1527693051321dba1 MD5 | raw file
Possible License(s): JSON, BSD-3-Clause, MPL-2.0-no-copyleft-exception, AGPL-1.0, GPL-2.0, AGPL-3.0, Apache-2.0, MIT, GPL-3.0, CC-BY-4.0, LGPL-2.1, BSD-2-Clause, LGPL-3.0
  1. <?php
  2. /*
  3. +--------------------------------------------------------------------+
  4. | Copyright CiviCRM LLC. All rights reserved. |
  5. | |
  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. +--------------------------------------------------------------------+
  10. */
  11. /**
  12. *
  13. * @package CRM
  14. * @copyright CiviCRM LLC https://civicrm.org/licensing
  15. */
  16. class CRM_Contact_Form_Search_Custom_ActivitySearch extends CRM_Contact_Form_Search_Custom_Base implements CRM_Contact_Form_Search_Interface {
  17. protected $_formValues;
  18. protected $_aclFrom = NULL;
  19. protected $_aclWhere = NULL;
  20. /**
  21. * Class constructor.
  22. *
  23. * @param array $formValues
  24. *
  25. * @throws \CRM_Core_Exception
  26. */
  27. public function __construct(&$formValues) {
  28. $this->_formValues = self::formatSavedSearchFields($formValues);
  29. /**
  30. * Define the columns for search result rows
  31. */
  32. $this->_columns = [
  33. ts('Name') => 'sort_name',
  34. ts('Status') => 'activity_status_id',
  35. ts('Activity Type') => 'activity_type_id',
  36. ts('Activity Subject') => 'activity_subject',
  37. ts('Scheduled By') => 'source_contact',
  38. ts('Scheduled Date') => 'activity_date',
  39. ' ' => 'activity_id',
  40. ' ' => 'case_id',
  41. ts('Location') => 'location',
  42. ts('Duration') => 'duration',
  43. ts('Details') => 'details',
  44. ts('Assignee') => 'assignee',
  45. ];
  46. //Add custom fields to columns array for inclusion in export
  47. $groupTree = CRM_Core_BAO_CustomGroup::getTree('Activity',
  48. [],
  49. NULL,
  50. NULL,
  51. [],
  52. NULL,
  53. TRUE,
  54. NULL,
  55. FALSE,
  56. CRM_Core_Permission::VIEW
  57. );
  58. //use simplified formatted groupTree
  59. $groupTree = CRM_Core_BAO_CustomGroup::formatGroupTree($groupTree);
  60. //cycle through custom fields and assign to _columns array
  61. foreach ($groupTree as $key) {
  62. foreach ($key['fields'] as $field) {
  63. $fieldlabel = $key['title'] . ": " . $field['label'];
  64. $this->_columns[$fieldlabel] = $field['column_name'];
  65. }
  66. }
  67. }
  68. /**
  69. * @param CRM_Core_Form $form
  70. */
  71. public function buildForm(&$form) {
  72. /**
  73. * You can define a custom title for the search form
  74. */
  75. $this->setTitle(ts('Find Latest Activities'));
  76. /**
  77. * Define the search form fields here
  78. */
  79. // Allow user to choose which type of contact to limit search on
  80. $form->add('select', 'contact_type', ts('Find...'), CRM_Core_SelectValues::contactType());
  81. // Text box for Activity Subject
  82. $form->add('text',
  83. 'activity_subject',
  84. ts('Activity Subject')
  85. );
  86. // Select box for Activity Type
  87. $activityType = ['' => ts(' - select activity - ')] + CRM_Core_PseudoConstant::activityType();
  88. $form->add('select', 'activity_type_id', ts('Activity Type'),
  89. $activityType,
  90. FALSE
  91. );
  92. // textbox for Activity Status
  93. $activityStatus = ['' => ts(' - select status - ')] + CRM_Core_PseudoConstant::activityStatus();
  94. $form->add('select', 'activity_status_id', ts('Activity Status'),
  95. $activityStatus,
  96. FALSE
  97. );
  98. // Activity Date range
  99. $form->add('datepicker', 'start_date', ts('Activity Date From'), [], FALSE, ['time' => FALSE]);
  100. $form->add('datepicker', 'end_date', ts('...through'), [], FALSE, ['time' => FALSE]);
  101. // Contact Name field
  102. $form->add('text', 'sort_name', ts('Contact Name'));
  103. /**
  104. * If you are using the sample template, this array tells the template fields to render
  105. * for the search form.
  106. */
  107. $form->assign('elements', [
  108. 'contact_type',
  109. 'activity_subject',
  110. 'activity_type_id',
  111. 'activity_status_id',
  112. 'start_date',
  113. 'end_date',
  114. 'sort_name',
  115. ]);
  116. }
  117. /**
  118. * Define the smarty template used to layout the search form and results listings.
  119. */
  120. public function templateFile() {
  121. return 'CRM/Contact/Form/Search/Custom/ActivitySearch.tpl';
  122. }
  123. /**
  124. * Construct the search query.
  125. *
  126. * @param int $offset
  127. * @param int $rowcount
  128. * @param null $sort
  129. * @param bool $includeContactIDs
  130. * @param bool $justIDs
  131. *
  132. * @return string
  133. * @throws \CRM_Core_Exception
  134. */
  135. public function all(
  136. $offset = 0, $rowcount = 0, $sort = NULL,
  137. $includeContactIDs = FALSE, $justIDs = FALSE
  138. ) {
  139. // SELECT clause must include contact_id as an alias for civicrm_contact.id
  140. if ($justIDs) {
  141. $select = 'contact_a.id as contact_id';
  142. }
  143. else {
  144. $select = '
  145. contact_a.id as contact_id,
  146. contact_a.sort_name as sort_name,
  147. contact_a.contact_type as contact_type,
  148. activity.id as activity_id,
  149. activity.activity_type_id as activity_type_id,
  150. contact_b.sort_name as source_contact,
  151. activity.subject as activity_subject,
  152. activity.activity_date_time as activity_date,
  153. activity.status_id as activity_status_id,
  154. cca.case_id as case_id,
  155. activity.location as location,
  156. activity.duration as duration,
  157. activity.details as details,
  158. assignment.activity_id as assignment_activity,
  159. contact_c.display_name as assignee
  160. ';
  161. }
  162. $from = $this->from();
  163. $where = $this->where($includeContactIDs);
  164. if (!empty($where)) {
  165. $where = "WHERE $where";
  166. }
  167. // add custom group fields to SELECT and FROM clause
  168. $groupTree = CRM_Core_BAO_CustomGroup::getTree('Activity',
  169. [],
  170. NULL,
  171. NULL,
  172. [],
  173. NULL,
  174. TRUE,
  175. NULL,
  176. FALSE,
  177. CRM_Core_Permission::VIEW
  178. );
  179. foreach ($groupTree as $key) {
  180. if (!empty($key['extends']) && $key['extends'] === 'Activity') {
  181. $select .= ", " . $key['table_name'] . ".*";
  182. $from .= " LEFT JOIN " . $key['table_name'] . " ON " . $key['table_name'] . ".entity_id = activity.id";
  183. }
  184. }
  185. // end custom groups add
  186. $sql = " SELECT $select FROM $from $where ";
  187. //no need to add order when only contact Ids.
  188. if (!$justIDs) {
  189. // Define ORDER BY for query in $sort, with default value
  190. if (!empty($sort)) {
  191. if (is_string($sort)) {
  192. $sort = CRM_Utils_Type::escape($sort, 'String');
  193. $sql .= " ORDER BY $sort ";
  194. }
  195. else {
  196. $sql .= ' ORDER BY ' . trim($sort->orderBy());
  197. }
  198. }
  199. else {
  200. $sql .= 'ORDER BY contact_a.sort_name, activity.activity_date_time DESC, activity.activity_type_id, activity.status_id, activity.subject';
  201. }
  202. }
  203. else {
  204. //CRM-14107, since there could be multiple activities against same contact,
  205. //we need to provide GROUP BY on contact id to prevent duplicacy on prev/next entries
  206. $sql .= 'GROUP BY contact_a.id
  207. ORDER BY contact_a.sort_name';
  208. }
  209. if ($rowcount > 0 && $offset >= 0) {
  210. $offset = CRM_Utils_Type::escape($offset, 'Int');
  211. $rowcount = CRM_Utils_Type::escape($rowcount, 'Int');
  212. $sql .= " LIMIT $offset, $rowcount ";
  213. }
  214. return $sql;
  215. }
  216. /**
  217. * Alters the date display in the Activity Date Column. We do this after we already have
  218. * the result so that sorting on the date column stays pertinent to the numeric date value
  219. * @param $row
  220. */
  221. public function alterRow(&$row) {
  222. $row['activity_date'] = CRM_Utils_Date::customFormat($row['activity_date'], '%B %E%f, %Y %l:%M %P');
  223. $row['activity_type_id'] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_DAO_Activity', 'activity_type_id', $row['activity_type_id']);
  224. $row['activity_status_id'] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_DAO_Activity', 'activity_status_id', $row['activity_status_id']);
  225. }
  226. /**
  227. * Regular JOIN statements here to limit results to contacts who have activities.
  228. * @return string
  229. */
  230. public function from() {
  231. $this->buildACLClause('contact_a');
  232. $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
  233. $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
  234. $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
  235. $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
  236. $from = "
  237. civicrm_activity activity
  238. LEFT JOIN civicrm_activity_contact target
  239. ON activity.id = target.activity_id AND target.record_type_id = {$targetID}
  240. JOIN civicrm_contact contact_a
  241. ON contact_a.id = target.contact_id
  242. LEFT JOIN civicrm_activity_contact sourceContact
  243. ON activity.id = sourceContact.activity_id AND sourceContact.record_type_id = {$sourceID}
  244. JOIN civicrm_contact contact_b
  245. ON sourceContact.contact_id = contact_b.id
  246. LEFT JOIN civicrm_case_activity cca
  247. ON activity.id = cca.activity_id
  248. LEFT JOIN civicrm_activity_contact assignment
  249. ON activity.id = assignment.activity_id AND assignment.record_type_id = {$assigneeID}
  250. LEFT JOIN civicrm_contact contact_c
  251. ON assignment.contact_id = contact_c.id {$this->_aclFrom}";
  252. return $from;
  253. }
  254. /**
  255. * WHERE clause is an array built from any required JOINS plus conditional filters based on search criteria field values.
  256. *
  257. * @param bool $includeContactIDs
  258. *
  259. * @return string
  260. */
  261. public function where($includeContactIDs = FALSE) {
  262. $clauses = [];
  263. // add contact name search; search on primary name, source contact, assignee
  264. $contactname = $this->_formValues['sort_name'];
  265. if (!empty($contactname)) {
  266. $dao = new CRM_Core_DAO();
  267. $contactname = $dao->escape($contactname);
  268. $clauses[] = "(contact_a.sort_name LIKE '%{$contactname}%' OR
  269. contact_b.sort_name LIKE '%{$contactname}%' OR
  270. contact_c.display_name LIKE '%{$contactname}%')";
  271. }
  272. $subject = $this->_formValues['activity_subject'];
  273. if (!empty($this->_formValues['contact_type'])) {
  274. $clauses[] = "contact_a.contact_type LIKE '%{$this->_formValues['contact_type']}%'";
  275. }
  276. if (!empty($subject)) {
  277. $dao = new CRM_Core_DAO();
  278. $subject = $dao->escape($subject);
  279. $clauses[] = "activity.subject LIKE '%{$subject}%'";
  280. }
  281. if (!empty($this->_formValues['activity_status_id'])) {
  282. $clauses[] = "activity.status_id = {$this->_formValues['activity_status_id']}";
  283. }
  284. if (!empty($this->_formValues['activity_type_id'])) {
  285. $clauses[] = "activity.activity_type_id = {$this->_formValues['activity_type_id']}";
  286. }
  287. if (!empty($this->_formValues['start_date'])) {
  288. $clauses[] = "activity.activity_date_time >= '{$this->_formValues['start_date']} 00:00:00'";
  289. }
  290. if (!empty($this->_formValues['end_date'])) {
  291. $clauses[] = "activity.activity_date_time <= '{$this->_formValues['end_date']} 23:59:59'";
  292. }
  293. if ($includeContactIDs) {
  294. $contactIDs = [];
  295. foreach ($this->_formValues as $id => $value) {
  296. if ($value &&
  297. substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX
  298. ) {
  299. $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN);
  300. }
  301. }
  302. if (!empty($contactIDs)) {
  303. $contactIDs = implode(', ', $contactIDs);
  304. $clauses[] = "contact_a.id IN ( $contactIDs )";
  305. }
  306. }
  307. if ($this->_aclWhere) {
  308. $clauses[] = " {$this->_aclWhere} ";
  309. }
  310. return implode(' AND ', $clauses);
  311. }
  312. /*
  313. * Functions below generally don't need to be modified
  314. */
  315. /**
  316. * @inheritDoc
  317. *
  318. * @throws \CRM_Core_Exception
  319. */
  320. public function count() {
  321. $sql = $this->all();
  322. $dao = CRM_Core_DAO::executeQuery($sql);
  323. return $dao->N;
  324. }
  325. /**
  326. * @param int $offset
  327. * @param int $rowcount
  328. * @param null $sort
  329. * @param bool $returnSQL Not used; included for consistency with parent; SQL is always returned
  330. *
  331. * @return string
  332. */
  333. public function contactIDs($offset = 0, $rowcount = 0, $sort = NULL, $returnSQL = TRUE) {
  334. return $this->all($offset, $rowcount, $sort, FALSE, TRUE);
  335. }
  336. /**
  337. * @return array
  338. */
  339. public function &columns() {
  340. return $this->_columns;
  341. }
  342. /**
  343. * @return null
  344. */
  345. public function summary() {
  346. return NULL;
  347. }
  348. /**
  349. * @param string $tableAlias
  350. */
  351. public function buildACLClause($tableAlias = 'contact') {
  352. list($this->_aclFrom, $this->_aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause($tableAlias);
  353. }
  354. /**
  355. * Format saved search fields for this custom group.
  356. *
  357. * Note this is a function to facilitate the transition to jcalendar for
  358. * saved search groups. In time it can be stripped out again.
  359. *
  360. * @param array $formValues
  361. *
  362. * @return array
  363. */
  364. public static function formatSavedSearchFields($formValues) {
  365. $dateFields = [
  366. 'start_date',
  367. 'end_date',
  368. ];
  369. foreach ($formValues as $element => $value) {
  370. if (in_array($element, $dateFields) && !empty($value)) {
  371. $formValues[$element] = date('Y-m-d', strtotime($value));
  372. }
  373. }
  374. return $formValues;
  375. }
  376. }