3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2019
33 class CRM_Contact_Form_Search_Criteria
{
35 * @param CRM_Core_Form $form
37 public static function basic(&$form) {
38 self
::setBasicSearchFields($form);
39 $form->addElement('hidden', 'hidden_basic', 1);
41 if ($form->_searchOptions
['contactType']) {
42 $contactTypes = CRM_Contact_BAO_ContactType
::getSelectElements();
45 $form->add('select', 'contact_type', ts('Contact Type(s)'), $contactTypes, FALSE,
46 array('id' => 'contact_type', 'multiple' => 'multiple', 'class' => 'crm-select2', 'style' => 'width: 100%;')
51 if ($form->_searchOptions
['groups']) {
52 // multiselect for groups
54 // Arrange groups into hierarchical listing (child groups follow their parents and have indentation spacing in title)
55 $groupHierarchy = CRM_Contact_BAO_Group
::getGroupsHierarchy($form->_group
, NULL, ' ', TRUE);
57 $form->add('select', 'group', ts('Groups'), $groupHierarchy, FALSE,
58 array('id' => 'group', 'multiple' => 'multiple', 'class' => 'crm-select2')
60 $groupOptions = CRM_Core_BAO_OptionValue
::getOptionValuesAssocArrayFromName('group_type');
61 $form->add('select', 'group_type', ts('Group Types'), $groupOptions, FALSE,
62 array('id' => 'group_type', 'multiple' => 'multiple', 'class' => 'crm-select2')
64 $form->add('hidden', 'group_search_selected', 'group');
68 if ($form->_searchOptions
['tags']) {
69 // multiselect for categories
70 $contactTags = CRM_Core_BAO_Tag
::getTags();
73 $form->add('select', 'contact_tags', ts('Select Tag(s)'), $contactTags, FALSE,
74 array('id' => 'contact_tags', 'multiple' => 'multiple', 'class' => 'crm-select2', 'style' => 'width: 100%;')
78 $parentNames = CRM_Core_BAO_Tag
::getTagSet('civicrm_contact');
79 CRM_Core_Form_Tag
::buildQuickForm($form, $parentNames, 'civicrm_contact', NULL, TRUE, FALSE);
81 $used_for = CRM_Core_OptionGroup
::values('tag_used_for');
83 $showAllTagTypes = FALSE;
84 foreach ($used_for as $key => $value) {
85 //check tags for every type and find if there are any defined
86 $tags = CRM_Core_BAO_Tag
::getTagsUsedFor($key, FALSE, TRUE, NULL);
87 // check if there are tags other than contact type, if no - keep checkbox hidden on adv search
88 // we will hide searching contact by attachments tags until it will be implemented in core
89 if (count($tags) && $key != 'civicrm_file' && $key != 'civicrm_contact') {
90 //if tags exists then add type to display in adv search form help text
91 $tagsTypes[] = ts($value);
92 $showAllTagTypes = TRUE;
95 $tagTypesText = implode(" or ", $tagsTypes);
96 if ($showAllTagTypes) {
97 $form->add('checkbox', 'all_tag_types', ts('Include tags used for %1', array(1 => $tagTypesText)));
98 $form->add('hidden', 'tag_types_text', $tagTypesText);
102 // add text box for last name, first name, street name, city
103 $form->addElement('text', 'sort_name', ts('Complete OR Partial Name'), CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'sort_name'));
105 // add text box for last name, first name, street name, city
106 $form->add('text', 'email', ts('Complete OR Partial Email'), CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'sort_name'));
108 //added contact source
109 $form->add('text', 'contact_source', ts('Contact Source'), CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'contact_source'));
112 $form->addElement('text', 'job_title', ts('Job Title'), CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'job_title'));
115 $form->add('number', 'contact_id', ts('Contact ID'), CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'id') +
array('min' => 1));
116 $form->addRule('contact_id', ts('Please enter valid Contact ID'), 'positiveInteger');
119 $form->addElement('text', 'external_identifier', ts('External ID'), CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'external_identifier'));
121 if (CRM_Core_Permission
::check('access deleted contacts') and Civi
::settings()->get('contact_undelete')) {
122 $form->add('checkbox', 'deleted_contacts', ts('Search in Trash') . '<br />' . ts('(deleted contacts)'));
125 // add checkbox for cms users only
126 $form->addYesNo('uf_user', ts('CMS User?'), TRUE);
129 $form->add('text', 'tag_search', ts('All Tags'));
131 // add search profiles
133 // FIXME: This is probably a part of profiles - need to be
134 // FIXME: eradicated from here when profiles are reworked.
135 $types = array('Participant', 'Contribution', 'Membership');
137 // get component profiles
138 $componentProfiles = array();
139 $componentProfiles = CRM_Core_BAO_UFGroup
::getProfiles($types);
141 $ufGroups = CRM_Core_BAO_UFGroup
::getModuleUFGroup('Search Profile', 1);
142 $accessibleUfGroups = CRM_Core_Permission
::ufGroup(CRM_Core_Permission
::VIEW
);
144 $searchProfiles = array();
145 foreach ($ufGroups as $key => $var) {
146 if (!array_key_exists($key, $componentProfiles) && in_array($key, $accessibleUfGroups)) {
147 $searchProfiles[$key] = $var['title'];
153 ts('Views For Display Contacts'),
155 '0' => ts('- default view -'),
158 array('class' => 'crm-select2')
161 $componentModes = CRM_Contact_Form_Search
::getModeSelect();
162 $form->assign('component_mappings', json_encode(CRM_Contact_Form_Search
::getModeToComponentMapping()));
163 if (count($componentModes) > 1) {
166 ts('Display Results As'),
169 array('class' => 'crm-select2')
175 ts('Search Operator'),
177 CRM_Contact_BAO_Query
::SEARCH_OPERATOR_AND
=> ts('AND'),
178 CRM_Contact_BAO_Query
::SEARCH_OPERATOR_OR
=> ts('OR'),
180 array('allowClear' => FALSE)
183 // add the option to display relationships
184 $rTypes = CRM_Core_PseudoConstant
::relationshipType();
185 $rSelect = array('' => ts('- Select Relationship Type-'));
186 foreach ($rTypes as $rid => $rValue) {
187 if ($rValue['label_a_b'] == $rValue['label_b_a']) {
188 $rSelect[$rid] = $rValue['label_a_b'];
191 $rSelect["{$rid}_a_b"] = $rValue['label_a_b'];
192 $rSelect["{$rid}_b_a"] = $rValue['label_b_a'];
196 $form->addElement('select',
197 'display_relationship_type',
198 ts('Display Results as Relationship'),
200 array('class' => 'crm-select2')
203 // checkboxes for DO NOT phone, email, mail
204 // we take labels from SelectValues
205 $t = CRM_Core_SelectValues
::privacy();
212 'id' => 'privacy_options',
213 'multiple' => 'multiple',
214 'class' => 'crm-select2',
218 $form->addElement('select',
229 2 => ts('Include by Privacy Option(s)'),
231 $form->addRadio('privacy_toggle', ts('Privacy Options'), $options, array('allowClear' => FALSE));
233 // preferred communication method
234 if (Civi
::settings()->get('civimail_multiple_bulk_emails')) {
235 $form->addSelect('email_on_hold',
236 array('entity' => 'email', 'multiple' => 'multiple', 'label' => ts('Email On Hold'), 'options' => CRM_Core_PseudoConstant
::emailOnHoldOptions()));
239 $form->add('advcheckbox', 'email_on_hold', ts('Email On Hold'));
242 $form->addSelect('preferred_communication_method',
243 array('entity' => 'contact', 'multiple' => 'multiple', 'label' => ts('Preferred Communication Method'), 'option_url' => NULL, 'placeholder' => ts('- any -')));
245 //CRM-6138 Preferred Language
246 $form->addSelect('preferred_language', array('class' => 'twenty', 'context' => 'search'));
249 $form->addElement('text', 'phone_numeric', ts('Phone'), CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Phone', 'phone'));
250 $locationType = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Address', 'location_type_id');
251 $phoneType = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Phone', 'phone_type_id');
252 $form->add('select', 'phone_location_type_id', ts('Phone Location'), array('' => ts('- any -')) +
$locationType, FALSE, array('class' => 'crm-select2'));
253 $form->add('select', 'phone_phone_type_id', ts('Phone Type'), array('' => ts('- any -')) +
$phoneType, FALSE, array('class' => 'crm-select2'));
257 * Defines the fields that can be displayed for the basic search section.
259 * @param CRM_Core_Form $form
261 protected static function setBasicSearchFields($form) {
262 $userFramework = CRM_Core_Config
::singleton()->userFramework
;
264 $form->assign('basicSearchFields', [
265 'sort_name' => ['name' => 'sort_name'],
266 'email' => ['name' => 'email'],
267 'contact_type' => ['name' => 'contact_type'],
270 'template' => 'CRM/Contact/Form/Search/Criteria/Fields/group.tpl',
272 'contact_tags' => ['name' => 'contact_tags'],
273 'tag_types_text' => ['name' => 'tag_types_text'],
275 'name' => 'tag_search',
276 'help' => ['id' => 'id-all-tags'],
281 'template' => 'CRM/Contact/Form/Search/Criteria/Fields/tag_set.tpl',
284 'name' => 'all_tag_types',
285 'class' => 'search-field__span-3 search-field__checkbox',
286 'help' => ['id' => 'id-all-tag-types']
289 'name' => 'phone_numeric',
290 'description' => ts('Punctuation and spaces are ignored.'),
292 'phone_location_type_id' => ['name' => 'phone_location_type_id'],
293 'phone_phone_type_id' => ['name' => 'phone_phone_type_id'],
294 'privacy_toggle' => [
295 'name' => 'privacy_toggle',
296 'class' => 'search-field__span-2',
297 'template' => 'CRM/Contact/Form/Search/Criteria/Fields/privacy_toggle.tpl',
299 'preferred_communication_method' => [
300 'name' => 'preferred_communication_method',
301 'template' => 'CRM/Contact/Form/Search/Criteria/Fields/preferred_communication_method.tpl',
303 'contact_source' => [
304 'name' => 'contact_source',
305 'help' => ['id' => 'id-source', 'file' => 'CRM/Contact/Form/Contact'],
307 'job_title' => ['name' => 'job_title'],
308 'preferred_language' => ['name' => 'preferred_language'],
310 'name' => 'contact_id',
311 'help' => ['id' => 'id-contact-id', 'file' => 'CRM/Contact/Form/Contact'],
313 'external_identifier' => [
314 'name' => 'external_identifier',
315 'help' => ['id' => 'id-external-id', 'file' => 'CRM/Contact/Form/Contact'],
319 'description' => ts('Does the contact have a %1 Account?', [$userFramework]),
326 * @param CRM_Core_Form $form
328 public static function location(&$form) {
329 $config = CRM_Core_Config
::singleton();
330 // Build location criteria based on _submitValues if
331 // available; otherwise, use $form->_formValues.
332 $formValues = $form->_submitValues
;
334 if (empty($formValues) && !empty($form->_formValues
)) {
335 $formValues = $form->_formValues
;
338 $form->addElement('hidden', 'hidden_location', 1);
340 $addressOptions = CRM_Core_BAO_Setting
::valueOptions(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
,
341 'address_options', TRUE, NULL, TRUE
344 $attributes = CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Address');
347 'street_address' => array(ts('Street Address'), $attributes['street_address'], NULL, NULL),
348 'supplemental_address_1' => array(ts('Supplemental Address 1'), $attributes['supplemental_address_1'], NULL, NULL),
349 'supplemental_address_2' => array(ts('Supplemental Address 2'), $attributes['supplemental_address_2'], NULL, NULL),
350 'supplemental_address_3' => array(ts('Supplemental Address 3'), $attributes['supplemental_address_3'], NULL, NULL),
351 'city' => array(ts('City'), $attributes['city'], NULL, NULL),
352 'postal_code' => array(ts('Postal Code'), $attributes['postal_code'], NULL, NULL),
353 'country' => array(ts('Country'), $attributes['country_id'], 'country', FALSE),
354 'state_province' => array(ts('State/Province'), $attributes['state_province_id'], 'stateProvince', TRUE),
355 'county' => array(ts('County'), $attributes['county_id'], 'county', TRUE),
356 'address_name' => array(ts('Address Name'), $attributes['address_name'], NULL, NULL),
357 'street_number' => array(ts('Street Number'), $attributes['street_number'], NULL, NULL),
358 'street_name' => array(ts('Street Name'), $attributes['street_name'], NULL, NULL),
359 'street_unit' => array(ts('Apt/Unit/Suite'), $attributes['street_unit'], NULL, NULL),
362 $parseStreetAddress = CRM_Utils_Array
::value('street_address_parsing', $addressOptions, 0);
363 $form->assign('parseStreetAddress', $parseStreetAddress);
364 foreach ($elements as $name => $v) {
365 list($title, $attributes, $select, $multiSelect) = $v;
368 array('street_number', 'street_name', 'street_unit')
370 if (!$parseStreetAddress) {
374 elseif (!$addressOptions[$name]) {
379 $attributes = $attributes[$name];
383 if ($select == 'stateProvince' ||
$select == 'county') {
384 $element = $form->addChainSelect($name);
387 $selectElements = array('' => ts('- any -')) + CRM_Core_PseudoConstant
::$select();
388 $element = $form->add('select', $name, $title, $selectElements, FALSE, array('class' => 'crm-select2'));
391 $element->setMultiple(TRUE);
395 $form->addElement('text', $name, $title, $attributes);
398 if ($addressOptions['postal_code']) {
399 $attr = array('class' => 'six') +
(array) CRM_Utils_Array
::value('postal_code', $attributes);
400 $form->addElement('text', 'postal_code_low', NULL, $attr +
array('placeholder' => ts('From')));
401 $form->addElement('text', 'postal_code_high', NULL, $attr +
array('placeholder' => ts('To')));
405 // extend addresses with proximity search
406 if (CRM_Utils_GeocodeProvider
::getUsableClassName()) {
407 $form->addElement('text', 'prox_distance', ts('Find contacts within'), array('class' => 'six'));
408 $form->addElement('select', 'prox_distance_unit', NULL, array(
409 'miles' => ts('Miles'),
410 'kilos' => ts('Kilometers'),
412 $form->addRule('prox_distance', ts('Please enter positive number as a distance'), 'numeric');
415 $form->addSelect('world_region', array('entity' => 'address', 'context' => 'search'));
417 // select for location type
418 $locationType = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Address', 'location_type_id');
419 $form->add('select', 'location_type', ts('Address Location'), $locationType, FALSE, array(
421 'class' => 'crm-select2',
422 'placeholder' => ts('Primary'),
425 // custom data extending addresses
426 CRM_Core_BAO_Query
::addCustomFormFields($form, array('Address'));
430 * @param CRM_Core_Form $form
432 public static function activity(&$form) {
433 $form->add('hidden', 'hidden_activity', 1);
434 CRM_Activity_BAO_Query
::buildSearchForm($form);
438 * @param CRM_Core_Form $form
440 public static function changeLog(&$form) {
441 $form->add('hidden', 'hidden_changeLog', 1);
443 // block for change log
444 $form->addElement('text', 'changed_by', ts('Modified By'), NULL);
446 $dates = array(1 => ts('Added'), 2 => ts('Modified'));
447 $form->addRadio('log_date', NULL, $dates, array('allowClear' => TRUE));
449 CRM_Core_Form_Date
::buildDateRange($form, 'log_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE);
453 * @param CRM_Core_Form $form
455 public static function task(&$form) {
456 $form->add('hidden', 'hidden_task', 1);
462 public static function relationship(&$form) {
463 $form->add('hidden', 'hidden_relationship', 1);
465 $allRelationshipType = array();
466 $allRelationshipType = CRM_Contact_BAO_Relationship
::getContactRelationshipType(NULL, NULL, NULL, NULL, TRUE);
467 $form->add('select', 'relation_type_id', ts('Relationship Type'), array('' => ts('- select -')) +
$allRelationshipType, FALSE, array('multiple' => TRUE, 'class' => 'crm-select2'));
468 $form->addElement('text', 'relation_target_name', ts('Target Contact'), CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'sort_name'));
470 $relStatusOption = array(ts('Active'), ts('Inactive'), ts('All'));
471 $form->addRadio('relation_status', ts('Relationship Status'), $relStatusOption);
472 $form->setDefaults(array('relation_status' => 0));
473 // relation permission
474 $allRelationshipPermissions = CRM_Contact_BAO_Relationship
::buildOptions('is_permission_a_b');
475 $form->add('select', 'relation_permission', ts('Permissioned Relationship'),
476 array('' => ts('- select -')) +
$allRelationshipPermissions, FALSE, array('multiple' => TRUE, 'class' => 'crm-select2'));
478 //add the target group
480 $form->add('select', 'relation_target_group', ts('Target Contact(s) in Group'), $form->_group
, FALSE,
481 array('id' => 'relation_target_group', 'multiple' => 'multiple', 'class' => 'crm-select2')
484 CRM_Core_Form_Date
::buildDateRange($form, 'relation_start_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE);
485 CRM_Core_Form_Date
::buildDateRange($form, 'relation_end_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE);
487 CRM_Core_Form_Date
::buildDateRange($form, 'relation_active_period_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE);
489 // Add reltionship dates
490 CRM_Core_Form_Date
::buildDateRange($form, 'relation_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE);
492 // add all the custom searchable fields
493 CRM_Core_BAO_Query
::addCustomFormFields($form, array('Relationship'));
499 public static function demographics(&$form) {
500 $form->add('hidden', 'hidden_demographics', 1);
501 // radio button for gender
502 $genderOptions = array();
503 $gender = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'gender_id');
504 foreach ($gender as $key => $var) {
505 $genderOptions[$key] = $form->createElement('radio', NULL,
506 ts('Gender'), $var, $key,
507 array('id' => "civicrm_gender_{$var}_{$key}")
510 $form->addGroup($genderOptions, 'gender_id', ts('Gender'))->setAttribute('allowClear', TRUE);
512 $form->add('text', 'age_low', ts('Min Age'), array('size' => 6));
513 $form->addRule('age_low', ts('Please enter a positive integer'), 'positiveInteger');
514 $form->add('text', 'age_high', ts('Max Age'), array('size' => 6));
515 $form->addRule('age_high', ts('Please enter a positive integer'), 'positiveInteger');
516 $form->addDate('age_asof_date', ts('Age as of Date'), FALSE, array('formatType' => 'searchDate'));
518 CRM_Core_Form_Date
::buildDateRange($form, 'birth_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth');
520 CRM_Core_Form_Date
::buildDateRange($form, 'deceased_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth');
522 // radio button for is_deceased
523 $form->addYesNo('is_deceased', ts('Deceased'), TRUE);
529 public static function notes(&$form) {
530 $form->add('hidden', 'hidden_notes', 1);
533 2 => ts('Body Only'),
534 3 => ts('Subject Only'),
537 $form->addRadio('note_option', '', $options);
539 $form->addElement('text', 'note', ts('Note Text'), CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'sort_name'));
541 $form->setDefaults(array('note_option' => 6));
545 * Generate the custom Data Fields based for those with is_searchable = 1.
547 * @param CRM_Contact_Form_Search $form
549 public static function custom(&$form) {
550 $form->add('hidden', 'hidden_custom', 1);
551 $extends = array_merge(array('Contact', 'Individual', 'Household', 'Organization'),
552 CRM_Contact_BAO_ContactType
::subTypes()
554 $groupDetails = CRM_Core_BAO_CustomGroup
::getGroupDetail(NULL, TRUE,
558 $form->assign('groupTree', $groupDetails);
560 foreach ($groupDetails as $key => $group) {
561 $_groupTitle[$key] = $group['name'];
562 CRM_Core_ShowHideBlocks
::links($form, $group['name'], '', '');
564 foreach ($group['fields'] as $field) {
565 $fieldId = $field['id'];
566 $elementName = 'custom_' . $fieldId;
567 if ($field['data_type'] == 'Date' && $field['is_search_range']) {
568 CRM_Core_Form_Date
::buildDateRange($form, $elementName, 1, '_from', '_to', ts('From:'), FALSE);
571 CRM_Core_BAO_CustomField
::addQuickFormElement($form, $elementName, $fieldId, FALSE, TRUE);
580 public static function CiviCase(&$form) {
581 //Looks like obsolete code, since CiviCase is a component, but might be used by HRD
582 $form->add('hidden', 'hidden_CiviCase', 1);
583 CRM_Case_BAO_Query
::buildSearchForm($form);