Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
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 | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
16 | */ |
17 | ||
18 | /** | |
19 | * Base Search / View form for *all* listing of multiple | |
20 | * contacts | |
21 | */ | |
3efb5b86 | 22 | class CRM_Contact_Form_Search extends CRM_Core_Form_Search { |
6a488035 | 23 | |
d424ffde | 24 | /** |
fe482240 | 25 | * list of valid contexts. |
6a488035 TO |
26 | * |
27 | * @var array | |
6a488035 | 28 | */ |
69078420 | 29 | public static $_validContext = NULL; |
6a488035 TO |
30 | |
31 | /** | |
fe482240 | 32 | * List of values used when we want to display other objects. |
6a488035 TO |
33 | * |
34 | * @var array | |
6a488035 | 35 | */ |
69078420 | 36 | public static $_modeValues = NULL; |
6a488035 | 37 | |
6a488035 | 38 | /** |
fe482240 | 39 | * The contextMenu. |
6a488035 TO |
40 | * |
41 | * @var array | |
6a488035 TO |
42 | */ |
43 | protected $_contextMenu; | |
44 | ||
45 | /** | |
fe482240 | 46 | * The groupId retrieved from the GET vars. |
6a488035 TO |
47 | * |
48 | * @var int | |
6a488035 TO |
49 | */ |
50 | public $_groupID; | |
51 | ||
52 | /** | |
fe482240 | 53 | * The Group ID belonging to Add Member to group ID. |
6a488035 TO |
54 | * retrieved from the GET vars |
55 | * | |
56 | * @var int | |
6a488035 TO |
57 | */ |
58 | protected $_amtgID; | |
59 | ||
60 | /** | |
fe482240 | 61 | * The saved search ID retrieved from the GET vars. |
6a488035 TO |
62 | * |
63 | * @var int | |
6a488035 TO |
64 | */ |
65 | protected $_ssID; | |
66 | ||
6a488035 | 67 | /** |
fe482240 | 68 | * The group elements. |
6a488035 TO |
69 | * |
70 | * @var array | |
6a488035 TO |
71 | */ |
72 | public $_group; | |
73 | public $_groupElement; | |
6a488035 TO |
74 | |
75 | /** | |
fe482240 | 76 | * The tag elements. |
6a488035 TO |
77 | * |
78 | * @var array | |
6a488035 TO |
79 | */ |
80 | public $_tag; | |
81 | public $_tagElement; | |
82 | ||
6a488035 | 83 | /** |
fe482240 | 84 | * The params used for search. |
6a488035 TO |
85 | * |
86 | * @var array | |
6a488035 TO |
87 | */ |
88 | protected $_params; | |
89 | ||
90 | /** | |
fe482240 | 91 | * The return properties used for search. |
6a488035 TO |
92 | * |
93 | * @var array | |
6a488035 TO |
94 | */ |
95 | protected $_returnProperties; | |
96 | ||
97 | /** | |
fe482240 | 98 | * The sort by character. |
6a488035 TO |
99 | * |
100 | * @var string | |
6a488035 TO |
101 | */ |
102 | protected $_sortByCharacter; | |
103 | ||
104 | /** | |
fe482240 | 105 | * The profile group id used for display. |
6a488035 | 106 | * |
9f266042 | 107 | * @var int |
6a488035 TO |
108 | */ |
109 | protected $_ufGroupID; | |
110 | ||
c490a46a | 111 | /** |
100fef9d | 112 | * Csv - common search values |
c490a46a CW |
113 | * |
114 | * @var array | |
c490a46a | 115 | */ |
69078420 | 116 | public static $csv = ['contact_type', 'group', 'tag']; |
6a488035 TO |
117 | |
118 | /** | |
9f266042 | 119 | * How to display the results. Should we display as contributons, members, cases etc. |
120 | * | |
121 | * @var string | |
6a488035 TO |
122 | */ |
123 | protected $_componentMode; | |
124 | ||
125 | /** | |
9f266042 | 126 | * What operator should we use, AND or OR. |
127 | * | |
128 | * @var string | |
6a488035 TO |
129 | */ |
130 | protected $_operator; | |
131 | ||
132 | protected $_modeValue; | |
133 | ||
90c13aa2 SL |
134 | /** |
135 | * Declare entity reference fields as they will need to be converted to using 'IN'. | |
136 | * | |
137 | * @var array | |
138 | */ | |
be2fb01f | 139 | protected $entityReferenceFields = ['event_id', 'membership_type_id']; |
90c13aa2 | 140 | |
6a488035 | 141 | /** |
fe482240 | 142 | * Name of the selector to use. |
69078420 | 143 | * @var string |
6a488035 | 144 | */ |
69078420 | 145 | public static $_selectorName = 'CRM_Contact_Selector'; |
6a488035 TO |
146 | protected $_customSearchID = NULL; |
147 | protected $_customSearchClass = NULL; | |
148 | ||
be2fb01f | 149 | protected $_openedPanes = []; |
d5965a37 | 150 | |
6e62b28c TM |
151 | /** |
152 | * Explicitly declare the entity api name. | |
153 | */ | |
154 | public function getDefaultEntity() { | |
155 | return 'Contact'; | |
156 | } | |
6a488035 TO |
157 | |
158 | /** | |
fe482240 | 159 | * Define the set of valid contexts that the search form operates on. |
6a488035 | 160 | * |
a6c01b45 CW |
161 | * @return array |
162 | * the valid context set and the titles | |
6a488035 | 163 | */ |
00be9182 | 164 | public static function &validContext() { |
6a488035 | 165 | if (!(self::$_validContext)) { |
be2fb01f | 166 | self::$_validContext = [ |
6a488035 TO |
167 | 'smog' => 'Show members of group', |
168 | 'amtg' => 'Add members to group', | |
169 | 'basic' => 'Basic Search', | |
170 | 'search' => 'Search', | |
171 | 'builder' => 'Search Builder', | |
172 | 'advanced' => 'Advanced Search', | |
173 | 'custom' => 'Custom Search', | |
be2fb01f | 174 | ]; |
6a488035 TO |
175 | } |
176 | return self::$_validContext; | |
177 | } | |
178 | ||
86538308 EM |
179 | /** |
180 | * @param $context | |
181 | * | |
182 | * @return bool | |
183 | */ | |
00be9182 | 184 | public static function isSearchContext($context) { |
6a488035 | 185 | $searchContext = CRM_Utils_Array::value($context, self::validContext()); |
dc0aa487 | 186 | return (bool) $searchContext; |
6a488035 TO |
187 | } |
188 | ||
00be9182 | 189 | public static function setModeValues() { |
be2fb01f CW |
190 | self::$_modeValues = [ |
191 | CRM_Contact_BAO_Query::MODE_CONTACTS => [ | |
a6c6c64f JP |
192 | 'selectorName' => self::$_selectorName, |
193 | 'selectorLabel' => ts('Contacts'), | |
194 | 'taskFile' => 'CRM/Contact/Form/Search/ResultTasks.tpl', | |
195 | 'taskContext' => NULL, | |
196 | 'resultFile' => 'CRM/Contact/Form/Selector.tpl', | |
197 | 'resultContext' => NULL, | |
198 | 'taskClassName' => 'CRM_Contact_Task', | |
199 | 'component' => '', | |
be2fb01f CW |
200 | ], |
201 | CRM_Contact_BAO_Query::MODE_CONTRIBUTE => [ | |
a6c6c64f JP |
202 | 'selectorName' => 'CRM_Contribute_Selector_Search', |
203 | 'selectorLabel' => ts('Contributions'), | |
204 | 'taskFile' => 'CRM/common/searchResultTasks.tpl', | |
205 | 'taskContext' => 'Contribution', | |
206 | 'resultFile' => 'CRM/Contribute/Form/Selector.tpl', | |
207 | 'resultContext' => 'Search', | |
208 | 'taskClassName' => 'CRM_Contribute_Task', | |
209 | 'component' => 'CiviContribute', | |
be2fb01f CW |
210 | ], |
211 | CRM_Contact_BAO_Query::MODE_EVENT => [ | |
a6c6c64f JP |
212 | 'selectorName' => 'CRM_Event_Selector_Search', |
213 | 'selectorLabel' => ts('Event Participants'), | |
214 | 'taskFile' => 'CRM/common/searchResultTasks.tpl', | |
215 | 'taskContext' => NULL, | |
216 | 'resultFile' => 'CRM/Event/Form/Selector.tpl', | |
217 | 'resultContext' => 'Search', | |
218 | 'taskClassName' => 'CRM_Event_Task', | |
219 | 'component' => 'CiviEvent', | |
be2fb01f CW |
220 | ], |
221 | CRM_Contact_BAO_Query::MODE_ACTIVITY => [ | |
a6c6c64f JP |
222 | 'selectorName' => 'CRM_Activity_Selector_Search', |
223 | 'selectorLabel' => ts('Activities'), | |
224 | 'taskFile' => 'CRM/common/searchResultTasks.tpl', | |
225 | 'taskContext' => NULL, | |
226 | 'resultFile' => 'CRM/Activity/Form/Selector.tpl', | |
227 | 'resultContext' => 'Search', | |
228 | 'taskClassName' => 'CRM_Activity_Task', | |
229 | 'component' => 'activity', | |
be2fb01f CW |
230 | ], |
231 | CRM_Contact_BAO_Query::MODE_MEMBER => [ | |
a6c6c64f JP |
232 | 'selectorName' => 'CRM_Member_Selector_Search', |
233 | 'selectorLabel' => ts('Memberships'), | |
234 | 'taskFile' => "CRM/common/searchResultTasks.tpl", | |
235 | 'taskContext' => NULL, | |
236 | 'resultFile' => 'CRM/Member/Form/Selector.tpl', | |
237 | 'resultContext' => 'Search', | |
238 | 'taskClassName' => 'CRM_Member_Task', | |
239 | 'component' => 'CiviMember', | |
be2fb01f CW |
240 | ], |
241 | CRM_Contact_BAO_Query::MODE_CASE => [ | |
a6c6c64f JP |
242 | 'selectorName' => 'CRM_Case_Selector_Search', |
243 | 'selectorLabel' => ts('Cases'), | |
244 | 'taskFile' => "CRM/common/searchResultTasks.tpl", | |
245 | 'taskContext' => NULL, | |
246 | 'resultFile' => 'CRM/Case/Form/Selector.tpl', | |
247 | 'resultContext' => 'Search', | |
248 | 'taskClassName' => 'CRM_Case_Task', | |
249 | 'component' => 'CiviCase', | |
be2fb01f CW |
250 | ], |
251 | CRM_Contact_BAO_Query::MODE_CONTACTSRELATED => [ | |
a6c6c64f JP |
252 | 'selectorName' => self::$_selectorName, |
253 | 'selectorLabel' => ts('Related Contacts'), | |
254 | 'taskFile' => 'CRM/Contact/Form/Search/ResultTasks.tpl', | |
255 | 'taskContext' => NULL, | |
256 | 'resultFile' => 'CRM/Contact/Form/Selector.tpl', | |
257 | 'resultContext' => NULL, | |
258 | 'taskClassName' => 'CRM_Contact_Task', | |
259 | 'component' => 'related_contact', | |
be2fb01f CW |
260 | ], |
261 | CRM_Contact_BAO_Query::MODE_MAILING => [ | |
a6c6c64f JP |
262 | 'selectorName' => 'CRM_Mailing_Selector_Search', |
263 | 'selectorLabel' => ts('Mailings'), | |
264 | 'taskFile' => "CRM/common/searchResultTasks.tpl", | |
265 | 'taskContext' => NULL, | |
266 | 'resultFile' => 'CRM/Mailing/Form/Selector.tpl', | |
267 | 'resultContext' => 'Search', | |
268 | 'taskClassName' => 'CRM_Mailing_Task', | |
269 | 'component' => 'CiviMail', | |
be2fb01f CW |
270 | ], |
271 | ]; | |
6a488035 TO |
272 | } |
273 | ||
86538308 | 274 | /** |
a6c6c64f JP |
275 | * Get the metadata for the query mode (this includes task class names) |
276 | * | |
86538308 EM |
277 | * @param int $mode |
278 | * | |
a6c6c64f JP |
279 | * @return array |
280 | * @throws \CRM_Core_Exception | |
86538308 | 281 | */ |
eda34f9b | 282 | public static function getModeValue($mode = CRM_Contact_BAO_Query::MODE_CONTACTS) { |
a6c6c64f JP |
283 | $searchPane = CRM_Utils_Request::retrieve('searchPane', 'String'); |
284 | if (!empty($searchPane)) { | |
285 | $mode = array_search($searchPane, self::getModeToComponentMapping()); | |
286 | } | |
6a488035 | 287 | |
a6c6c64f | 288 | self::setModeValues(); |
48016b17 D |
289 | // Note $mode might === FALSE because array_search above failed, e.g. for searchPane='location' |
290 | if (empty(self::$_modeValues[$mode])) { | |
eda34f9b | 291 | $mode = CRM_Contact_BAO_Query::MODE_CONTACTS; |
6a488035 TO |
292 | } |
293 | ||
294 | return self::$_modeValues[$mode]; | |
295 | } | |
296 | ||
e30af20d | 297 | /** |
298 | * Get a mapping of modes to components. | |
299 | * | |
300 | * This will map the integers to the components. Contact has an empty component | |
301 | * an pseudo-components exist for activity & related_contact. | |
302 | * | |
303 | * @return array | |
304 | */ | |
305 | public static function getModeToComponentMapping() { | |
306 | $mapping = []; | |
307 | self::setModeValues(); | |
308 | ||
309 | foreach (self::$_modeValues as $id => $metadata) { | |
310 | $mapping[$id] = $metadata['component']; | |
311 | } | |
312 | return $mapping; | |
313 | } | |
314 | ||
86538308 EM |
315 | /** |
316 | * @return array | |
317 | */ | |
00be9182 | 318 | public static function getModeSelect() { |
6a488035 TO |
319 | self::setModeValues(); |
320 | ||
8424571d | 321 | $enabledComponents = CRM_Core_Component::getEnabledComponents(); |
be2fb01f | 322 | $componentModes = []; |
6a488035 | 323 | foreach (self::$_modeValues as $id => & $value) { |
8424571d PN |
324 | if (strpos($value['component'], 'Civi') !== FALSE |
325 | && !array_key_exists($value['component'], $enabledComponents) | |
326 | ) { | |
327 | continue; | |
328 | } | |
eda34f9b | 329 | $componentModes[$id] = $value['selectorLabel']; |
6a488035 TO |
330 | } |
331 | ||
eda34f9b MW |
332 | // unset disabled components |
333 | if (!array_key_exists('CiviMail', $enabledComponents)) { | |
334 | unset($componentModes[CRM_Contact_BAO_Query::MODE_MAILING]); | |
335 | } | |
336 | ||
337 | // unset contributions or participants if user does not have permission on them | |
6a488035 | 338 | if (!CRM_Core_Permission::access('CiviContribute')) { |
eda34f9b | 339 | unset($componentModes[CRM_Contact_BAO_Query::MODE_CONTRIBUTE]); |
6a488035 TO |
340 | } |
341 | ||
342 | if (!CRM_Core_Permission::access('CiviEvent')) { | |
eda34f9b MW |
343 | unset($componentModes[CRM_Contact_BAO_Query::MODE_EVENT]); |
344 | } | |
345 | ||
346 | if (!CRM_Core_Permission::access('CiviMember')) { | |
347 | unset($componentModes[CRM_Contact_BAO_Query::MODE_MEMBER]); | |
6a488035 TO |
348 | } |
349 | ||
350 | if (!CRM_Core_Permission::check('view all activities')) { | |
eda34f9b | 351 | unset($componentModes[CRM_Contact_BAO_Query::MODE_ACTIVITY]); |
6a488035 | 352 | } |
eda34f9b MW |
353 | |
354 | return $componentModes; | |
6a488035 TO |
355 | } |
356 | ||
357 | /** | |
32795e82 | 358 | * Builds the list of tasks or actions that a searcher can perform on a result set. |
6a488035 | 359 | * |
32795e82 | 360 | * @return array |
6a488035 | 361 | */ |
e98a9804 | 362 | public function buildTaskList() { |
eda34f9b | 363 | // amtg = 'Add members to group' |
7a3978aa | 364 | if ($this->_context !== 'amtg') { |
eda34f9b MW |
365 | $taskParams['deletedContacts'] = FALSE; |
366 | if ($this->_componentMode == CRM_Contact_BAO_Query::MODE_CONTACTS || $this->_componentMode == CRM_Contact_BAO_Query::MODE_CONTACTSRELATED) { | |
9c1bc317 | 367 | $taskParams['deletedContacts'] = $this->_formValues['deleted_contacts'] ?? NULL; |
7a3978aa | 368 | } |
eda34f9b | 369 | $className = $this->_modeValue['taskClassName']; |
2e1f50d6 | 370 | $taskParams['ssID'] = $this->_ssID ?? NULL; |
eda34f9b | 371 | $this->_taskList += $className::permissionedTaskTitles(CRM_Core_Permission::getPermission(), $taskParams); |
32795e82 FG |
372 | } |
373 | ||
7a3978aa | 374 | return $this->_taskList; |
32795e82 | 375 | } |
6a488035 | 376 | |
32795e82 FG |
377 | /** |
378 | * Build the common elements between the search/advanced form. | |
6a488035 | 379 | */ |
00be9182 | 380 | public function buildQuickForm() { |
3efb5b86 | 381 | parent::buildQuickForm(); |
eda34f9b | 382 | |
6a488035 | 383 | // some tasks.. what do we want to do with the selected contacts ? |
eda34f9b | 384 | $this->_taskList = $this->buildTaskList(); |
6a488035 TO |
385 | |
386 | if (isset($this->_ssID)) { | |
79d7553f | 387 | $search_custom_id |
388 | = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $this->_ssID, 'search_custom_id'); | |
6a488035 | 389 | |
be2fb01f | 390 | $savedSearchValues = [ |
6a488035 TO |
391 | 'id' => $this->_ssID, |
392 | 'name' => CRM_Contact_BAO_SavedSearch::getName($this->_ssID, 'title'), | |
393 | 'search_custom_id' => $search_custom_id, | |
be2fb01f | 394 | ]; |
6a488035 TO |
395 | $this->assign_by_ref('savedSearch', $savedSearchValues); |
396 | $this->assign('ssID', $this->_ssID); | |
397 | } | |
398 | ||
399 | if ($this->_context === 'smog') { | |
400 | // CRM-11788, we might want to do this for all of search where force=1 | |
9c1bc317 CW |
401 | $formQFKey = $this->_formValues['qfKey'] ?? NULL; |
402 | $getQFKey = $_GET['qfKey'] ?? NULL; | |
403 | $postQFKey = $_POST['qfKey'] ?? NULL; | |
6a488035 TO |
404 | if ($formQFKey && empty($getQFKey) && empty($postQFKey)) { |
405 | $url = CRM_Utils_System::makeURL('qfKey') . $formQFKey; | |
406 | CRM_Utils_System::redirect($url); | |
407 | } | |
838d0ff6 | 408 | $permissionForGroup = FALSE; |
6a488035 TO |
409 | |
410 | if (!empty($this->_groupID)) { | |
6a488035 TO |
411 | // check if user has permission to edit members of this group |
412 | $permission = CRM_Contact_BAO_Group::checkPermission($this->_groupID); | |
413 | if ($permission && in_array(CRM_Core_Permission::EDIT, $permission)) { | |
414 | $permissionForGroup = TRUE; | |
415 | } | |
416 | ||
417 | // check if _groupID exists, it might not if | |
418 | // we are displaying a hidden group | |
419 | if (!isset($this->_group[$this->_groupID])) { | |
79d7553f | 420 | $this->_group[$this->_groupID] |
421 | = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_groupID, 'title'); | |
6a488035 TO |
422 | } |
423 | ||
6a488035 | 424 | // set the group title |
be2fb01f | 425 | $groupValues = ['id' => $this->_groupID, 'title' => $this->_group[$this->_groupID]]; |
6a488035 TO |
426 | $this->assign_by_ref('group', $groupValues); |
427 | ||
428 | // also set ssID if this is a saved search | |
429 | $ssID = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_groupID, 'saved_search_id'); | |
430 | $this->assign('ssID', $ssID); | |
431 | ||
432 | //get the saved search mapping id | |
433 | if ($ssID) { | |
434 | $this->_ssID = $ssID; | |
435 | $ssMappingId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $ssID, 'mapping_id'); | |
436 | $this->assign('ssMappingID', $ssMappingId); | |
437 | } | |
438 | ||
439 | // Set dynamic page title for 'Show Members of Group' | |
be2fb01f | 440 | CRM_Utils_System::setTitle(ts('Contacts in Group: %1', [1 => $this->_group[$this->_groupID]])); |
6a488035 TO |
441 | } |
442 | ||
be2fb01f | 443 | $group_contact_status = []; |
6a488035 TO |
444 | foreach (CRM_Core_SelectValues::groupContactStatus() as $k => $v) { |
445 | if (!empty($k)) { | |
446 | $group_contact_status[] = $this->createElement('checkbox', $k, NULL, $v); | |
447 | } | |
448 | } | |
449 | $this->addGroup($group_contact_status, | |
450 | 'group_contact_status', ts('Group Status') | |
451 | ); | |
452 | ||
838d0ff6 | 453 | $this->assign('permissionedForGroup', $permissionForGroup); |
6a488035 TO |
454 | } |
455 | ||
456 | // add the go button for the action form, note it is of type 'next' rather than of type 'submit' | |
457 | if ($this->_context === 'amtg') { | |
353ffa53 TO |
458 | // check if _groupID exists, it might not if |
459 | // we are displaying a hidden group | |
6a488035 TO |
460 | if (!isset($this->_group[$this->_amtgID])) { |
461 | $this->assign('permissionedForGroup', FALSE); | |
79d7553f | 462 | $this->_group[$this->_amtgID] |
463 | = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_amtgID, 'title'); | |
6a488035 TO |
464 | } |
465 | ||
466 | // Set dynamic page title for 'Add Members Group' | |
be2fb01f | 467 | CRM_Utils_System::setTitle(ts('Add to Group: %1', [1 => $this->_group[$this->_amtgID]])); |
6a488035 | 468 | // also set the group title and freeze the action task with Add Members to Group |
be2fb01f | 469 | $groupValues = ['id' => $this->_amtgID, 'title' => $this->_group[$this->_amtgID]]; |
6a488035 | 470 | $this->assign_by_ref('group', $groupValues); |
9d30c8d1 | 471 | $this->add('submit', $this->_actionButtonName, ts('Add Contacts to %1', [1 => $this->_group[$this->_amtgID]]), |
be2fb01f | 472 | [ |
97e557d7 | 473 | 'class' => 'crm-form-submit', |
be2fb01f | 474 | ] |
6a488035 | 475 | ); |
eda34f9b | 476 | $this->add('hidden', 'task', CRM_Contact_Task::GROUP_ADD); |
be2fb01f | 477 | $selectedRowsRadio = $this->addElement('radio', 'radio_ts', NULL, '', 'ts_sel', ['checked' => 'checked']); |
c2d91642 | 478 | $allRowsRadio = $this->addElement('radio', 'radio_ts', NULL, '', 'ts_all'); |
479 | $this->assign('ts_sel_id', $selectedRowsRadio->_attributes['id']); | |
480 | $this->assign('ts_all_id', $allRowsRadio->_attributes['id']); | |
6a488035 | 481 | } |
6a488035 | 482 | |
be2fb01f | 483 | $selectedContactIds = []; |
9c1bc317 | 484 | $qfKeyParam = $this->_formValues['qfKey'] ?? NULL; |
2ebb21f0 | 485 | // We use ajax to handle selections only if the search results component_mode is set to "contacts" |
eda34f9b | 486 | if ($qfKeyParam && ($this->get('component_mode') <= CRM_Contact_BAO_Query::MODE_CONTACTS || $this->get('component_mode') == CRM_Contact_BAO_Query::MODE_CONTACTSRELATED)) { |
2ebb21f0 | 487 | $this->addClass('crm-ajax-selection-form'); |
6a488035 | 488 | $qfKeyParam = "civicrm search {$qfKeyParam}"; |
b7994703 | 489 | $selectedContactIdsArr = Civi::service('prevnext')->getSelection($qfKeyParam); |
6a488035 TO |
490 | $selectedContactIds = array_keys($selectedContactIdsArr[$qfKeyParam]); |
491 | } | |
492 | ||
493 | $this->assign_by_ref('selectedContactIds', $selectedContactIds); | |
494 | ||
6a488035 TO |
495 | $rows = $this->get('rows'); |
496 | ||
497 | if (is_array($rows)) { | |
6e8d1c11 | 498 | $this->addRowSelectors($rows); |
6a488035 TO |
499 | } |
500 | ||
6a488035 TO |
501 | } |
502 | ||
503 | /** | |
fe482240 | 504 | * Processing needed for buildForm and later. |
86f20cc1 | 505 | * |
506 | * @throws \CRM_Core_Exception | |
6a488035 | 507 | */ |
00be9182 | 508 | public function preProcess() { |
6a488035 TO |
509 | // set the various class variables |
510 | ||
511 | $this->_group = CRM_Core_PseudoConstant::group(); | |
512 | ||
6a488035 TO |
513 | $this->_tag = CRM_Core_BAO_Tag::getTags(); |
514 | $this->_done = FALSE; | |
515 | ||
516 | /* | |
deb50ba3 CW |
517 | * we allow the controller to set force/reset externally, useful when we are being |
518 | * driven by the wizard framework | |
519 | */ | |
6a488035 | 520 | |
8d53ca1d TO |
521 | $this->_reset = CRM_Utils_Request::retrieve('reset', 'Boolean'); |
522 | ||
523 | $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean'); | |
6a488035 TO |
524 | $this->_groupID = CRM_Utils_Request::retrieve('gid', 'Positive', $this); |
525 | $this->_amtgID = CRM_Utils_Request::retrieve('amtgID', 'Positive', $this); | |
8d53ca1d | 526 | $this->_ssID = CRM_Utils_Request::retrieve('ssID', 'Positive', $this); |
6a488035 TO |
527 | $this->_sortByCharacter = CRM_Utils_Request::retrieve('sortByCharacter', 'String', $this); |
528 | $this->_ufGroupID = CRM_Utils_Request::retrieve('id', 'Positive', $this); | |
eda34f9b MW |
529 | $this->_componentMode = CRM_Utils_Request::retrieve('component_mode', 'Positive', $this, FALSE, CRM_Contact_BAO_Query::MODE_CONTACTS, $_REQUEST); |
530 | $this->_operator = CRM_Utils_Request::retrieve('operator', 'String', $this, FALSE, CRM_Contact_BAO_Query::SEARCH_OPERATOR_AND, 'REQUEST'); | |
6a488035 | 531 | |
96db3ecb SL |
532 | if (!empty($this->_ssID) && !CRM_Core_Permission::check('edit groups')) { |
533 | CRM_Core_Error::statusBounce(ts('You do not have permission to modify smart groups')); | |
534 | } | |
535 | ||
6a488035 TO |
536 | /** |
537 | * set the button names | |
538 | */ | |
6a488035 TO |
539 | $this->_actionButtonName = $this->getButtonName('next', 'action'); |
540 | ||
6a488035 TO |
541 | $this->assign('actionButtonName', $this->_actionButtonName); |
542 | ||
6a488035 TO |
543 | // if we dont get this from the url, use default if one exsts |
544 | $config = CRM_Core_Config::singleton(); | |
545 | if ($this->_ufGroupID == NULL && | |
546 | $config->defaultSearchProfileID != NULL | |
547 | ) { | |
548 | $this->_ufGroupID = $config->defaultSearchProfileID; | |
549 | } | |
550 | ||
551 | // assign context to drive the template display, make sure context is valid | |
8d53ca1d | 552 | $this->_context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this, FALSE, 'search'); |
f3acfdd9 | 553 | if (!array_key_exists($this->_context, self::validContext())) { |
6a488035 TO |
554 | $this->_context = 'search'; |
555 | } | |
556 | $this->set('context', $this->_context); | |
557 | $this->assign('context', $this->_context); | |
558 | ||
559 | $this->_modeValue = self::getModeValue($this->_componentMode); | |
560 | $this->assign($this->_modeValue); | |
561 | ||
562 | $this->set('selectorName', self::$_selectorName); | |
563 | ||
564 | // get user submitted values | |
565 | // get it from controller only if form has been submitted, else preProcess has set this | |
4eeb9a5b TO |
566 | // $this->controller->isModal( ) returns TRUE if page is |
567 | // valid, i.e all the validations are TRUE | |
6a488035 TO |
568 | |
569 | if (!empty($_POST) && !$this->controller->isModal()) { | |
570 | $this->_formValues = $this->controller->exportValues($this->_name); | |
571 | ||
572 | $this->normalizeFormValues(); | |
90c13aa2 | 573 | $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues, 0, FALSE, NULL, $this->entityReferenceFields); |
6a488035 TO |
574 | $this->_returnProperties = &$this->returnProperties(); |
575 | ||
576 | // also get the uf group id directly from the post value | |
577 | $this->_ufGroupID = CRM_Utils_Array::value('uf_group_id', $_POST, $this->_ufGroupID); | |
578 | $this->_formValues['uf_group_id'] = $this->_ufGroupID; | |
579 | $this->set('id', $this->_ufGroupID); | |
580 | ||
581 | // also get the object mode directly from the post value | |
582 | $this->_componentMode = CRM_Utils_Array::value('component_mode', $_POST, $this->_componentMode); | |
583 | ||
584 | // also get the operator from the post value if set | |
585 | $this->_operator = CRM_Utils_Array::value('operator', $_POST, $this->_operator); | |
586 | $this->_formValues['operator'] = $this->_operator; | |
587 | $this->set('operator', $this->_operator); | |
588 | } | |
589 | else { | |
590 | $this->_formValues = $this->get('formValues'); | |
90c13aa2 | 591 | $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues, 0, FALSE, NULL, $this->entityReferenceFields); |
6a488035 TO |
592 | $this->_returnProperties = &$this->returnProperties(); |
593 | if (!empty($this->_ufGroupID)) { | |
594 | $this->set('id', $this->_ufGroupID); | |
595 | } | |
596 | } | |
597 | ||
598 | if (empty($this->_formValues)) { | |
599 | //check if group is a smart group (fix for CRM-1255) | |
600 | if ($this->_groupID) { | |
601 | if ($ssId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_groupID, 'saved_search_id')) { | |
602 | $this->_ssID = $ssId; | |
603 | } | |
604 | } | |
605 | ||
606 | // fix for CRM-1907 | |
86f20cc1 | 607 | if (isset($this->_ssID) && $this->_context !== 'smog') { |
6a488035 TO |
608 | // we only retrieve the saved search values if out current values are null |
609 | $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); | |
610 | ||
611 | //fix for CRM-1505 | |
612 | if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $this->_ssID, 'mapping_id')) { | |
613 | $this->_params = CRM_Contact_BAO_SavedSearch::getSearchParams($this->_ssID); | |
614 | } | |
615 | else { | |
616 | $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); | |
617 | } | |
618 | $this->_returnProperties = &$this->returnProperties(); | |
619 | } | |
620 | else { | |
621 | if (isset($this->_ufGroupID)) { | |
622 | // also set the uf group id if not already present | |
623 | $this->_formValues['uf_group_id'] = $this->_ufGroupID; | |
624 | } | |
625 | if (isset($this->_componentMode)) { | |
626 | $this->_formValues['component_mode'] = $this->_componentMode; | |
627 | } | |
628 | if (isset($this->_operator)) { | |
629 | $this->_formValues['operator'] = $this->_operator; | |
630 | } | |
631 | ||
632 | // FIXME: we should generalise in a way that components could inject url-filters | |
633 | // just like they build their own form elements | |
be2fb01f | 634 | foreach ([ |
69078420 SL |
635 | 'mailing_id', |
636 | 'mailing_delivery_status', | |
637 | 'mailing_open_status', | |
638 | 'mailing_click_status', | |
639 | 'mailing_reply_status', | |
640 | 'mailing_optout', | |
641 | 'mailing_forward', | |
642 | 'mailing_unsubscribe', | |
643 | 'mailing_date_low', | |
644 | 'mailing_date_high', | |
0058ef3f SL |
645 | 'mailing_job_start_date_low', |
646 | 'mailing_job_start_date_high', | |
647 | 'mailing_job_start_date_relative', | |
69078420 | 648 | ] as $mailingFilter) { |
6a488035 TO |
649 | $type = 'String'; |
650 | if ($mailingFilter == 'mailing_id' && | |
651 | $filterVal = CRM_Utils_Request::retrieve('mailing_id', 'Positive', $this) | |
652 | ) { | |
be2fb01f | 653 | $this->_formValues[$mailingFilter] = [$filterVal]; |
6a488035 TO |
654 | } |
655 | elseif ($filterVal = CRM_Utils_Request::retrieve($mailingFilter, $type, $this)) { | |
656 | $this->_formValues[$mailingFilter] = $filterVal; | |
657 | } | |
658 | if ($filterVal) { | |
659 | $this->_openedPanes['Mailings'] = 1; | |
660 | $this->_formValues['hidden_CiviMail'] = 1; | |
661 | } | |
662 | } | |
663 | } | |
664 | } | |
665 | $this->assign('id', | |
666 | CRM_Utils_Array::value('uf_group_id', $this->_formValues) | |
667 | ); | |
eda34f9b | 668 | $operator = CRM_Utils_Array::value('operator', $this->_formValues, CRM_Contact_BAO_Query::SEARCH_OPERATOR_AND); |
6a488035 | 669 | $this->set('queryOperator', $operator); |
eda34f9b | 670 | if ($operator == CRM_Contact_BAO_Query::SEARCH_OPERATOR_OR) { |
6a488035 TO |
671 | $this->assign('operator', ts('OR')); |
672 | } | |
673 | else { | |
674 | $this->assign('operator', ts('AND')); | |
675 | } | |
676 | ||
677 | // show the context menu only when we’re not searching for deleted contacts; CRM-5673 | |
a7488080 | 678 | if (empty($this->_formValues['deleted_contacts'])) { |
6a488035 | 679 | $menuItems = CRM_Contact_BAO_Contact::contextMenu(); |
be2fb01f CW |
680 | $primaryActions = CRM_Utils_Array::value('primaryActions', $menuItems, []); |
681 | $this->_contextMenu = CRM_Utils_Array::value('moreActions', $menuItems, []); | |
6a488035 TO |
682 | $this->assign('contextMenu', $primaryActions + $this->_contextMenu); |
683 | } | |
684 | ||
685 | if (!isset($this->_componentMode)) { | |
686 | $this->_componentMode = CRM_Contact_BAO_Query::MODE_CONTACTS; | |
687 | } | |
6a488035 | 688 | self::$_selectorName = $this->_modeValue['selectorName']; |
a6c6c64f | 689 | self::setModeValues(); |
6a488035 TO |
690 | |
691 | $setDynamic = FALSE; | |
692 | if (strpos(self::$_selectorName, 'CRM_Contact_Selector') !== FALSE) { | |
693 | $selector = new self::$_selectorName( | |
694 | $this->_customSearchClass, | |
695 | $this->_formValues, | |
696 | $this->_params, | |
697 | $this->_returnProperties, | |
698 | $this->_action, | |
ab8a593e | 699 | FALSE, TRUE, |
6a488035 TO |
700 | $this->_context, |
701 | $this->_contextMenu | |
702 | ); | |
703 | $setDynamic = TRUE; | |
704 | } | |
705 | else { | |
706 | $selector = new self::$_selectorName( | |
707 | $this->_params, | |
708 | $this->_action, | |
ab8a593e | 709 | NULL, FALSE, NULL, |
6a488035 TO |
710 | "search", "advanced" |
711 | ); | |
712 | } | |
713 | ||
714 | $selector->setKey($this->controller->_key); | |
715 | ||
716 | $controller = new CRM_Contact_Selector_Controller($selector, | |
717 | $this->get(CRM_Utils_Pager::PAGE_ID), | |
718 | $this->get(CRM_Utils_Sort::SORT_ID), | |
719 | CRM_Core_Action::VIEW, | |
720 | $this, | |
721 | CRM_Core_Selector_Controller::TRANSFER | |
722 | ); | |
723 | $controller->setEmbedded(TRUE); | |
724 | $controller->setDynamicAction($setDynamic); | |
725 | ||
726 | if ($this->_force) { | |
f90f8d32 | 727 | $this->loadMetadata(); |
6a488035 TO |
728 | $this->postProcess(); |
729 | ||
730 | /* | |
deb50ba3 CW |
731 | * Note that we repeat this, since the search creates and stores |
732 | * values that potentially change the controller behavior. i.e. things | |
733 | * like totalCount etc | |
734 | */ | |
6a488035 TO |
735 | $controller = new CRM_Contact_Selector_Controller($selector, |
736 | $this->get(CRM_Utils_Pager::PAGE_ID), | |
590084ae | 737 | $this->getSortID(), |
6a488035 TO |
738 | CRM_Core_Action::VIEW, $this, CRM_Core_Selector_Controller::TRANSFER |
739 | ); | |
740 | $controller->setEmbedded(TRUE); | |
741 | $controller->setDynamicAction($setDynamic); | |
742 | } | |
743 | ||
744 | $controller->moveFromSessionToTemplate(); | |
745 | } | |
746 | ||
6a488035 | 747 | /** |
fe482240 | 748 | * Common post processing. |
6a488035 | 749 | */ |
00be9182 | 750 | public function postProcess() { |
6a488035 TO |
751 | /* |
752 | * sometime we do a postProcess early on, so we dont need to repeat it | |
753 | * this will most likely introduce some more bugs :( | |
754 | */ | |
755 | ||
756 | if ($this->_done) { | |
757 | return; | |
758 | } | |
759 | $this->_done = TRUE; | |
760 | ||
761 | //for prev/next pagination | |
a3d827a7 | 762 | $crmPID = CRM_Utils_Request::retrieve('crmPID', 'Integer'); |
6a488035 | 763 | |
6a488035 TO |
764 | //get the button name |
765 | $buttonName = $this->controller->getButtonName(); | |
766 | ||
8cc574cf | 767 | if (isset($this->_ufGroupID) && empty($this->_formValues['uf_group_id'])) { |
6a488035 TO |
768 | $this->_formValues['uf_group_id'] = $this->_ufGroupID; |
769 | } | |
770 | ||
8cc574cf | 771 | if (isset($this->_componentMode) && empty($this->_formValues['component_mode'])) { |
6a488035 TO |
772 | $this->_formValues['component_mode'] = $this->_componentMode; |
773 | } | |
774 | ||
8cc574cf | 775 | if (isset($this->_operator) && empty($this->_formValues['operator'])) { |
6a488035 TO |
776 | $this->_formValues['operator'] = $this->_operator; |
777 | } | |
778 | ||
a7488080 | 779 | if (empty($this->_formValues['qfKey'])) { |
6a488035 TO |
780 | $this->_formValues['qfKey'] = $this->controller->_key; |
781 | } | |
782 | ||
783 | if (!CRM_Core_Permission::check('access deleted contacts')) { | |
784 | unset($this->_formValues['deleted_contacts']); | |
785 | } | |
786 | ||
787 | $this->set('type', $this->_action); | |
788 | $this->set('formValues', $this->_formValues); | |
789 | $this->set('queryParams', $this->_params); | |
790 | $this->set('returnProperties', $this->_returnProperties); | |
791 | ||
e341bbee | 792 | if ($buttonName == $this->_actionButtonName) { |
6a488035 TO |
793 | // check actionName and if next, then do not repeat a search, since we are going to the next page |
794 | // hack, make sure we reset the task values | |
795 | $stateMachine = $this->controller->getStateMachine(); | |
796 | $formName = $stateMachine->getTaskFormName(); | |
797 | $this->controller->resetPage($formName); | |
798 | return; | |
799 | } | |
800 | else { | |
804beb78 | 801 | if (array_key_exists($this->getButtonName('refresh'), $_POST) || |
af7e94a6 | 802 | ($this->_force && !$crmPID) |
803 | ) { | |
804 | //reset the cache table for new search | |
805 | $cacheKey = "civicrm search {$this->controller->_key}"; | |
806 | Civi::service('prevnext')->deleteItem(NULL, $cacheKey); | |
807 | } | |
6a488035 TO |
808 | $output = CRM_Core_Selector_Controller::SESSION; |
809 | ||
810 | // create the selector, controller and run - store results in session | |
811 | $searchChildGroups = TRUE; | |
812 | if ($this->get('isAdvanced')) { | |
813 | $searchChildGroups = FALSE; | |
814 | } | |
815 | ||
816 | $setDynamic = FALSE; | |
817 | ||
818 | if (strpos(self::$_selectorName, 'CRM_Contact_Selector') !== FALSE) { | |
79d7553f | 819 | $selector = new self::$_selectorName( |
6a488035 TO |
820 | $this->_customSearchClass, |
821 | $this->_formValues, | |
822 | $this->_params, | |
823 | $this->_returnProperties, | |
824 | $this->_action, | |
ab8a593e | 825 | FALSE, |
6a488035 TO |
826 | $searchChildGroups, |
827 | $this->_context, | |
828 | $this->_contextMenu | |
829 | ); | |
830 | $setDynamic = TRUE; | |
831 | } | |
832 | else { | |
d3e86119 | 833 | $selector = new self::$_selectorName( |
6a488035 TO |
834 | $this->_params, |
835 | $this->_action, | |
e60f24eb | 836 | NULL, |
ab8a593e | 837 | FALSE, |
e60f24eb | 838 | NULL, |
6a488035 TO |
839 | "search", |
840 | "advanced" | |
841 | ); | |
842 | } | |
843 | ||
844 | $selector->setKey($this->controller->_key); | |
845 | ||
846 | // added the sorting character to the form array | |
6a488035 TO |
847 | $config = CRM_Core_Config::singleton(); |
848 | // do this only for contact search | |
849 | if ($setDynamic && $config->includeAlphabeticalPager) { | |
e166ff79 CW |
850 | // Don't recompute if we are just paging/sorting |
851 | if ($this->_reset || (empty($_GET['crmPID']) && empty($_GET['crmSID']) && !$this->_sortByCharacter)) { | |
6a488035 TO |
852 | $aToZBar = CRM_Utils_PagerAToZ::getAToZBar($selector, $this->_sortByCharacter); |
853 | $this->set('AToZBar', $aToZBar); | |
854 | } | |
855 | } | |
856 | ||
6a488035 TO |
857 | $controller = new CRM_Contact_Selector_Controller($selector, |
858 | $this->get(CRM_Utils_Pager::PAGE_ID), | |
590084ae | 859 | $this->getSortID(), |
6a488035 TO |
860 | CRM_Core_Action::VIEW, |
861 | $this, | |
862 | $output | |
863 | ); | |
864 | $controller->setEmbedded(TRUE); | |
865 | $controller->setDynamicAction($setDynamic); | |
866 | $controller->run(); | |
867 | } | |
868 | } | |
869 | ||
86538308 | 870 | /** |
e60f24eb | 871 | * @return NULL |
86538308 | 872 | */ |
00be9182 | 873 | public function &returnProperties() { |
6a488035 TO |
874 | return CRM_Core_DAO::$_nullObject; |
875 | } | |
876 | ||
877 | /** | |
878 | * Return a descriptive name for the page, used in wizard header | |
879 | * | |
880 | * @return string | |
6a488035 | 881 | */ |
00be9182 | 882 | public function getTitle() { |
6a488035 TO |
883 | return ts('Search'); |
884 | } | |
96025800 | 885 | |
e26bc72e SL |
886 | /** |
887 | * Check Access for a component | |
888 | * @param string $component | |
889 | * @return bool | |
890 | */ | |
891 | protected static function checkComponentAccess($component) { | |
892 | $enabledComponents = CRM_Core_Component::getEnabledComponents(); | |
893 | if (!array_key_exists($component, $enabledComponents)) { | |
894 | return FALSE; | |
895 | } | |
896 | return CRM_Core_Permission::access($component); | |
897 | } | |
898 | ||
f90f8d32 | 899 | /** |
900 | * Load metadata for fields on the form. | |
901 | * | |
902 | * @throws \CiviCRM_API3_Exception | |
903 | */ | |
904 | protected function loadMetadata() { | |
f90f8d32 | 905 | // can't by pass acls by passing search criteria in the url. |
e26bc72e SL |
906 | if (self::checkComponentAccess('CiviContribute')) { |
907 | $this->addSearchFieldMetadata(['Contribution' => CRM_Contribute_BAO_Query::getSearchFieldMetadata()]); | |
908 | $this->addSearchFieldMetadata(['ContributionRecur' => CRM_Contribute_BAO_ContributionRecur::getContributionRecurSearchFieldMetadata()]); | |
909 | } | |
50cdce00 SL |
910 | if (self::checkComponentAccess('CiviPledge')) { |
911 | $this->addSearchFieldMetadata(['Pledge' => CRM_Pledge_BAO_Query::getSearchFieldMetadata()]); | |
912 | $this->addSearchFieldMetadata(['PledgePayment' => CRM_Pledge_BAO_Query::getPledgePaymentSearchFieldMetadata()]); | |
913 | } | |
914 | if (self::checkComponentAccess('CiviEvent')) { | |
915 | $this->addSearchFieldMetadata(['Participant' => CRM_Event_BAO_Query::getSearchFieldMetadata()]); | |
916 | } | |
917 | if (self::checkComponentAccess('CiviMember')) { | |
918 | $this->addSearchFieldMetadata(['Membership' => CRM_Member_BAO_Query::getSearchFieldMetadata()]); | |
919 | } | |
920 | if (self::checkComponentAccess('CiviGrant')) { | |
921 | $this->addSearchFieldMetadata(['Grant' => CRM_Grant_BAO_Query::getSearchFieldMetadata()]); | |
922 | } | |
923 | if (self::checkComponentAccess('CiviCase')) { | |
924 | $this->addSearchFieldMetadata(['Case' => CRM_Case_BAO_Query::getSearchFieldMetadata()]); | |
925 | } | |
f90f8d32 | 926 | } |
927 | ||
6a488035 | 928 | } |