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 TO |
185 | $searchContext = CRM_Utils_Array::value($context, self::validContext()); |
186 | return $searchContext ? TRUE : FALSE; | |
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) { | |
367 | $taskParams['deletedContacts'] = CRM_Utils_Array::value('deleted_contacts', $this->_formValues); | |
7a3978aa | 368 | } |
eda34f9b MW |
369 | $className = $this->_modeValue['taskClassName']; |
370 | $taskParams['ssID'] = isset($this->_ssID) ? $this->_ssID : NULL; | |
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 | |
401 | $formQFKey = CRM_Utils_Array::value('qfKey', $this->_formValues); | |
402 | $getQFKey = CRM_Utils_Array::value('qfKey', $_GET); | |
403 | $postQFKey = CRM_Utils_Array::value('qfKey', $_POST); | |
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); |
be2fb01f CW |
471 | $this->add('submit', $this->_actionButtonName, ts('Add Contacts to %1', [1 => $this->_group[$this->_amtgID]]), |
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 = []; |
2ebb21f0 CW |
484 | $qfKeyParam = CRM_Utils_Array::value('qfKey', $this->_formValues); |
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. |
6a488035 | 505 | */ |
00be9182 | 506 | public function preProcess() { |
6a488035 TO |
507 | // set the various class variables |
508 | ||
509 | $this->_group = CRM_Core_PseudoConstant::group(); | |
510 | ||
6a488035 TO |
511 | $this->_tag = CRM_Core_BAO_Tag::getTags(); |
512 | $this->_done = FALSE; | |
513 | ||
514 | /* | |
deb50ba3 CW |
515 | * we allow the controller to set force/reset externally, useful when we are being |
516 | * driven by the wizard framework | |
517 | */ | |
6a488035 | 518 | |
8d53ca1d TO |
519 | $this->_reset = CRM_Utils_Request::retrieve('reset', 'Boolean'); |
520 | ||
521 | $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean'); | |
6a488035 TO |
522 | $this->_groupID = CRM_Utils_Request::retrieve('gid', 'Positive', $this); |
523 | $this->_amtgID = CRM_Utils_Request::retrieve('amtgID', 'Positive', $this); | |
8d53ca1d | 524 | $this->_ssID = CRM_Utils_Request::retrieve('ssID', 'Positive', $this); |
6a488035 TO |
525 | $this->_sortByCharacter = CRM_Utils_Request::retrieve('sortByCharacter', 'String', $this); |
526 | $this->_ufGroupID = CRM_Utils_Request::retrieve('id', 'Positive', $this); | |
eda34f9b MW |
527 | $this->_componentMode = CRM_Utils_Request::retrieve('component_mode', 'Positive', $this, FALSE, CRM_Contact_BAO_Query::MODE_CONTACTS, $_REQUEST); |
528 | $this->_operator = CRM_Utils_Request::retrieve('operator', 'String', $this, FALSE, CRM_Contact_BAO_Query::SEARCH_OPERATOR_AND, 'REQUEST'); | |
6a488035 TO |
529 | |
530 | /** | |
531 | * set the button names | |
532 | */ | |
533 | $this->_searchButtonName = $this->getButtonName('refresh'); | |
6a488035 TO |
534 | $this->_actionButtonName = $this->getButtonName('next', 'action'); |
535 | ||
6a488035 TO |
536 | $this->assign('actionButtonName', $this->_actionButtonName); |
537 | ||
6a488035 TO |
538 | // if we dont get this from the url, use default if one exsts |
539 | $config = CRM_Core_Config::singleton(); | |
540 | if ($this->_ufGroupID == NULL && | |
541 | $config->defaultSearchProfileID != NULL | |
542 | ) { | |
543 | $this->_ufGroupID = $config->defaultSearchProfileID; | |
544 | } | |
545 | ||
546 | // assign context to drive the template display, make sure context is valid | |
8d53ca1d | 547 | $this->_context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this, FALSE, 'search'); |
6a488035 TO |
548 | if (!CRM_Utils_Array::value($this->_context, self::validContext())) { |
549 | $this->_context = 'search'; | |
550 | } | |
551 | $this->set('context', $this->_context); | |
552 | $this->assign('context', $this->_context); | |
553 | ||
554 | $this->_modeValue = self::getModeValue($this->_componentMode); | |
555 | $this->assign($this->_modeValue); | |
556 | ||
557 | $this->set('selectorName', self::$_selectorName); | |
558 | ||
559 | // get user submitted values | |
560 | // get it from controller only if form has been submitted, else preProcess has set this | |
4eeb9a5b TO |
561 | // $this->controller->isModal( ) returns TRUE if page is |
562 | // valid, i.e all the validations are TRUE | |
6a488035 TO |
563 | |
564 | if (!empty($_POST) && !$this->controller->isModal()) { | |
565 | $this->_formValues = $this->controller->exportValues($this->_name); | |
566 | ||
567 | $this->normalizeFormValues(); | |
90c13aa2 | 568 | $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues, 0, FALSE, NULL, $this->entityReferenceFields); |
6a488035 TO |
569 | $this->_returnProperties = &$this->returnProperties(); |
570 | ||
571 | // also get the uf group id directly from the post value | |
572 | $this->_ufGroupID = CRM_Utils_Array::value('uf_group_id', $_POST, $this->_ufGroupID); | |
573 | $this->_formValues['uf_group_id'] = $this->_ufGroupID; | |
574 | $this->set('id', $this->_ufGroupID); | |
575 | ||
576 | // also get the object mode directly from the post value | |
577 | $this->_componentMode = CRM_Utils_Array::value('component_mode', $_POST, $this->_componentMode); | |
578 | ||
579 | // also get the operator from the post value if set | |
580 | $this->_operator = CRM_Utils_Array::value('operator', $_POST, $this->_operator); | |
581 | $this->_formValues['operator'] = $this->_operator; | |
582 | $this->set('operator', $this->_operator); | |
583 | } | |
584 | else { | |
585 | $this->_formValues = $this->get('formValues'); | |
90c13aa2 | 586 | $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues, 0, FALSE, NULL, $this->entityReferenceFields); |
6a488035 TO |
587 | $this->_returnProperties = &$this->returnProperties(); |
588 | if (!empty($this->_ufGroupID)) { | |
589 | $this->set('id', $this->_ufGroupID); | |
590 | } | |
591 | } | |
592 | ||
593 | if (empty($this->_formValues)) { | |
594 | //check if group is a smart group (fix for CRM-1255) | |
595 | if ($this->_groupID) { | |
596 | if ($ssId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_groupID, 'saved_search_id')) { | |
597 | $this->_ssID = $ssId; | |
598 | } | |
599 | } | |
600 | ||
601 | // fix for CRM-1907 | |
602 | if (isset($this->_ssID) && $this->_context != 'smog') { | |
603 | // we only retrieve the saved search values if out current values are null | |
604 | $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); | |
605 | ||
606 | //fix for CRM-1505 | |
607 | if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $this->_ssID, 'mapping_id')) { | |
608 | $this->_params = CRM_Contact_BAO_SavedSearch::getSearchParams($this->_ssID); | |
609 | } | |
610 | else { | |
611 | $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); | |
612 | } | |
613 | $this->_returnProperties = &$this->returnProperties(); | |
614 | } | |
615 | else { | |
616 | if (isset($this->_ufGroupID)) { | |
617 | // also set the uf group id if not already present | |
618 | $this->_formValues['uf_group_id'] = $this->_ufGroupID; | |
619 | } | |
620 | if (isset($this->_componentMode)) { | |
621 | $this->_formValues['component_mode'] = $this->_componentMode; | |
622 | } | |
623 | if (isset($this->_operator)) { | |
624 | $this->_formValues['operator'] = $this->_operator; | |
625 | } | |
626 | ||
627 | // FIXME: we should generalise in a way that components could inject url-filters | |
628 | // just like they build their own form elements | |
be2fb01f | 629 | foreach ([ |
69078420 SL |
630 | 'mailing_id', |
631 | 'mailing_delivery_status', | |
632 | 'mailing_open_status', | |
633 | 'mailing_click_status', | |
634 | 'mailing_reply_status', | |
635 | 'mailing_optout', | |
636 | 'mailing_forward', | |
637 | 'mailing_unsubscribe', | |
638 | 'mailing_date_low', | |
639 | 'mailing_date_high', | |
0058ef3f SL |
640 | 'mailing_job_start_date_low', |
641 | 'mailing_job_start_date_high', | |
642 | 'mailing_job_start_date_relative', | |
69078420 | 643 | ] as $mailingFilter) { |
6a488035 TO |
644 | $type = 'String'; |
645 | if ($mailingFilter == 'mailing_id' && | |
646 | $filterVal = CRM_Utils_Request::retrieve('mailing_id', 'Positive', $this) | |
647 | ) { | |
be2fb01f | 648 | $this->_formValues[$mailingFilter] = [$filterVal]; |
6a488035 TO |
649 | } |
650 | elseif ($filterVal = CRM_Utils_Request::retrieve($mailingFilter, $type, $this)) { | |
651 | $this->_formValues[$mailingFilter] = $filterVal; | |
652 | } | |
653 | if ($filterVal) { | |
654 | $this->_openedPanes['Mailings'] = 1; | |
655 | $this->_formValues['hidden_CiviMail'] = 1; | |
656 | } | |
657 | } | |
658 | } | |
659 | } | |
660 | $this->assign('id', | |
661 | CRM_Utils_Array::value('uf_group_id', $this->_formValues) | |
662 | ); | |
eda34f9b | 663 | $operator = CRM_Utils_Array::value('operator', $this->_formValues, CRM_Contact_BAO_Query::SEARCH_OPERATOR_AND); |
6a488035 | 664 | $this->set('queryOperator', $operator); |
eda34f9b | 665 | if ($operator == CRM_Contact_BAO_Query::SEARCH_OPERATOR_OR) { |
6a488035 TO |
666 | $this->assign('operator', ts('OR')); |
667 | } | |
668 | else { | |
669 | $this->assign('operator', ts('AND')); | |
670 | } | |
671 | ||
672 | // show the context menu only when we’re not searching for deleted contacts; CRM-5673 | |
a7488080 | 673 | if (empty($this->_formValues['deleted_contacts'])) { |
6a488035 | 674 | $menuItems = CRM_Contact_BAO_Contact::contextMenu(); |
be2fb01f CW |
675 | $primaryActions = CRM_Utils_Array::value('primaryActions', $menuItems, []); |
676 | $this->_contextMenu = CRM_Utils_Array::value('moreActions', $menuItems, []); | |
6a488035 TO |
677 | $this->assign('contextMenu', $primaryActions + $this->_contextMenu); |
678 | } | |
679 | ||
680 | if (!isset($this->_componentMode)) { | |
681 | $this->_componentMode = CRM_Contact_BAO_Query::MODE_CONTACTS; | |
682 | } | |
6a488035 | 683 | self::$_selectorName = $this->_modeValue['selectorName']; |
a6c6c64f | 684 | self::setModeValues(); |
6a488035 TO |
685 | |
686 | $setDynamic = FALSE; | |
687 | if (strpos(self::$_selectorName, 'CRM_Contact_Selector') !== FALSE) { | |
688 | $selector = new self::$_selectorName( | |
689 | $this->_customSearchClass, | |
690 | $this->_formValues, | |
691 | $this->_params, | |
692 | $this->_returnProperties, | |
693 | $this->_action, | |
ab8a593e | 694 | FALSE, TRUE, |
6a488035 TO |
695 | $this->_context, |
696 | $this->_contextMenu | |
697 | ); | |
698 | $setDynamic = TRUE; | |
699 | } | |
700 | else { | |
701 | $selector = new self::$_selectorName( | |
702 | $this->_params, | |
703 | $this->_action, | |
ab8a593e | 704 | NULL, FALSE, NULL, |
6a488035 TO |
705 | "search", "advanced" |
706 | ); | |
707 | } | |
708 | ||
709 | $selector->setKey($this->controller->_key); | |
710 | ||
711 | $controller = new CRM_Contact_Selector_Controller($selector, | |
712 | $this->get(CRM_Utils_Pager::PAGE_ID), | |
713 | $this->get(CRM_Utils_Sort::SORT_ID), | |
714 | CRM_Core_Action::VIEW, | |
715 | $this, | |
716 | CRM_Core_Selector_Controller::TRANSFER | |
717 | ); | |
718 | $controller->setEmbedded(TRUE); | |
719 | $controller->setDynamicAction($setDynamic); | |
720 | ||
721 | if ($this->_force) { | |
f90f8d32 | 722 | $this->loadMetadata(); |
6a488035 TO |
723 | $this->postProcess(); |
724 | ||
725 | /* | |
deb50ba3 CW |
726 | * Note that we repeat this, since the search creates and stores |
727 | * values that potentially change the controller behavior. i.e. things | |
728 | * like totalCount etc | |
729 | */ | |
6a488035 TO |
730 | $sortID = NULL; |
731 | if ($this->get(CRM_Utils_Sort::SORT_ID)) { | |
732 | $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), | |
733 | $this->get(CRM_Utils_Sort::SORT_DIRECTION) | |
734 | ); | |
735 | } | |
736 | $controller = new CRM_Contact_Selector_Controller($selector, | |
737 | $this->get(CRM_Utils_Pager::PAGE_ID), | |
738 | $sortID, | |
739 | CRM_Core_Action::VIEW, $this, CRM_Core_Selector_Controller::TRANSFER | |
740 | ); | |
741 | $controller->setEmbedded(TRUE); | |
742 | $controller->setDynamicAction($setDynamic); | |
743 | } | |
744 | ||
745 | $controller->moveFromSessionToTemplate(); | |
746 | } | |
747 | ||
6a488035 | 748 | /** |
fe482240 | 749 | * Common post processing. |
6a488035 | 750 | */ |
00be9182 | 751 | public function postProcess() { |
6a488035 TO |
752 | /* |
753 | * sometime we do a postProcess early on, so we dont need to repeat it | |
754 | * this will most likely introduce some more bugs :( | |
755 | */ | |
756 | ||
757 | if ($this->_done) { | |
758 | return; | |
759 | } | |
760 | $this->_done = TRUE; | |
761 | ||
762 | //for prev/next pagination | |
a3d827a7 | 763 | $crmPID = CRM_Utils_Request::retrieve('crmPID', 'Integer'); |
6a488035 | 764 | |
6a488035 TO |
765 | //get the button name |
766 | $buttonName = $this->controller->getButtonName(); | |
767 | ||
8cc574cf | 768 | if (isset($this->_ufGroupID) && empty($this->_formValues['uf_group_id'])) { |
6a488035 TO |
769 | $this->_formValues['uf_group_id'] = $this->_ufGroupID; |
770 | } | |
771 | ||
8cc574cf | 772 | if (isset($this->_componentMode) && empty($this->_formValues['component_mode'])) { |
6a488035 TO |
773 | $this->_formValues['component_mode'] = $this->_componentMode; |
774 | } | |
775 | ||
8cc574cf | 776 | if (isset($this->_operator) && empty($this->_formValues['operator'])) { |
6a488035 TO |
777 | $this->_formValues['operator'] = $this->_operator; |
778 | } | |
779 | ||
a7488080 | 780 | if (empty($this->_formValues['qfKey'])) { |
6a488035 TO |
781 | $this->_formValues['qfKey'] = $this->controller->_key; |
782 | } | |
783 | ||
784 | if (!CRM_Core_Permission::check('access deleted contacts')) { | |
785 | unset($this->_formValues['deleted_contacts']); | |
786 | } | |
787 | ||
788 | $this->set('type', $this->_action); | |
789 | $this->set('formValues', $this->_formValues); | |
790 | $this->set('queryParams', $this->_params); | |
791 | $this->set('returnProperties', $this->_returnProperties); | |
792 | ||
e341bbee | 793 | if ($buttonName == $this->_actionButtonName) { |
6a488035 TO |
794 | // check actionName and if next, then do not repeat a search, since we are going to the next page |
795 | // hack, make sure we reset the task values | |
796 | $stateMachine = $this->controller->getStateMachine(); | |
797 | $formName = $stateMachine->getTaskFormName(); | |
798 | $this->controller->resetPage($formName); | |
799 | return; | |
800 | } | |
801 | else { | |
af7e94a6 | 802 | if (array_key_exists($this->_searchButtonName, $_POST) || |
803 | ($this->_force && !$crmPID) | |
804 | ) { | |
805 | //reset the cache table for new search | |
806 | $cacheKey = "civicrm search {$this->controller->_key}"; | |
807 | Civi::service('prevnext')->deleteItem(NULL, $cacheKey); | |
808 | } | |
6a488035 TO |
809 | $output = CRM_Core_Selector_Controller::SESSION; |
810 | ||
811 | // create the selector, controller and run - store results in session | |
812 | $searchChildGroups = TRUE; | |
813 | if ($this->get('isAdvanced')) { | |
814 | $searchChildGroups = FALSE; | |
815 | } | |
816 | ||
817 | $setDynamic = FALSE; | |
818 | ||
819 | if (strpos(self::$_selectorName, 'CRM_Contact_Selector') !== FALSE) { | |
79d7553f | 820 | $selector = new self::$_selectorName( |
6a488035 TO |
821 | $this->_customSearchClass, |
822 | $this->_formValues, | |
823 | $this->_params, | |
824 | $this->_returnProperties, | |
825 | $this->_action, | |
ab8a593e | 826 | FALSE, |
6a488035 TO |
827 | $searchChildGroups, |
828 | $this->_context, | |
829 | $this->_contextMenu | |
830 | ); | |
831 | $setDynamic = TRUE; | |
832 | } | |
833 | else { | |
d3e86119 | 834 | $selector = new self::$_selectorName( |
6a488035 TO |
835 | $this->_params, |
836 | $this->_action, | |
e60f24eb | 837 | NULL, |
ab8a593e | 838 | FALSE, |
e60f24eb | 839 | NULL, |
6a488035 TO |
840 | "search", |
841 | "advanced" | |
842 | ); | |
843 | } | |
844 | ||
845 | $selector->setKey($this->controller->_key); | |
846 | ||
847 | // added the sorting character to the form array | |
6a488035 TO |
848 | $config = CRM_Core_Config::singleton(); |
849 | // do this only for contact search | |
850 | if ($setDynamic && $config->includeAlphabeticalPager) { | |
e166ff79 CW |
851 | // Don't recompute if we are just paging/sorting |
852 | if ($this->_reset || (empty($_GET['crmPID']) && empty($_GET['crmSID']) && !$this->_sortByCharacter)) { | |
6a488035 TO |
853 | $aToZBar = CRM_Utils_PagerAToZ::getAToZBar($selector, $this->_sortByCharacter); |
854 | $this->set('AToZBar', $aToZBar); | |
855 | } | |
856 | } | |
857 | ||
858 | $sortID = NULL; | |
859 | if ($this->get(CRM_Utils_Sort::SORT_ID)) { | |
860 | $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), | |
861 | $this->get(CRM_Utils_Sort::SORT_DIRECTION) | |
862 | ); | |
863 | } | |
864 | $controller = new CRM_Contact_Selector_Controller($selector, | |
865 | $this->get(CRM_Utils_Pager::PAGE_ID), | |
866 | $sortID, | |
867 | CRM_Core_Action::VIEW, | |
868 | $this, | |
869 | $output | |
870 | ); | |
871 | $controller->setEmbedded(TRUE); | |
872 | $controller->setDynamicAction($setDynamic); | |
873 | $controller->run(); | |
874 | } | |
875 | } | |
876 | ||
86538308 | 877 | /** |
e60f24eb | 878 | * @return NULL |
86538308 | 879 | */ |
00be9182 | 880 | public function &returnProperties() { |
6a488035 TO |
881 | return CRM_Core_DAO::$_nullObject; |
882 | } | |
883 | ||
884 | /** | |
885 | * Return a descriptive name for the page, used in wizard header | |
886 | * | |
887 | * @return string | |
6a488035 | 888 | */ |
00be9182 | 889 | public function getTitle() { |
6a488035 TO |
890 | return ts('Search'); |
891 | } | |
96025800 | 892 | |
f90f8d32 | 893 | /** |
894 | * Load metadata for fields on the form. | |
895 | * | |
896 | * @throws \CiviCRM_API3_Exception | |
897 | */ | |
898 | protected function loadMetadata() { | |
899 | // @todo - check what happens if the person does not have 'access civicontribute' - make sure they | |
900 | // can't by pass acls by passing search criteria in the url. | |
901 | $this->addSearchFieldMetadata(['Contribution' => CRM_Contribute_BAO_Query::getSearchFieldMetadata()]); | |
902 | $this->addSearchFieldMetadata(['ContributionRecur' => CRM_Contribute_BAO_ContributionRecur::getContributionRecurSearchFieldMetadata()]); | |
e07ecf6f | 903 | $this->addSearchFieldMetadata(['Participant' => CRM_Event_BAO_Query::getSearchFieldMetadata()]); |
64486a6f SL |
904 | $this->addSearchFieldMetadata(['Membership' => CRM_Member_BAO_Query::getSearchFieldMetadata()]); |
905 | $this->addSearchFieldMetadata(['Pledge' => CRM_Pledge_BAO_Query::getSearchFieldMetadata()]); | |
906 | $this->addSearchFieldMetadata(['PledgePayment' => CRM_Pledge_BAO_Query::getPledgePaymentSearchFieldMetadata()]); | |
907 | $this->addSearchFieldMetadata(['Grant' => CRM_Grant_BAO_Query::getSearchFieldMetadata()]); | |
5e0866cd | 908 | $this->addSearchFieldMetadata(['Case' => CRM_Case_BAO_Query::getSearchFieldMetadata()]); |
f90f8d32 | 909 | } |
910 | ||
6a488035 | 911 | } |