From 1f8ac3d2014fdc76e4235978b4014a7edd22cdae Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Wed, 31 Oct 2018 15:48:02 -0400 Subject: [PATCH] Support custom fields with option lists in quicksearch --- CRM/Core/BAO/CustomField.php | 25 ++++++++++++++++++++ CRM/Core/SelectValues.php | 5 ++-- api/v3/Contact.php | 45 ++++++++++++++++++++++++------------ 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php index 1434ead03e..2e7e231142 100644 --- a/CRM/Core/BAO/CustomField.php +++ b/CRM/Core/BAO/CustomField.php @@ -2429,6 +2429,31 @@ WHERE cf.id = %1 AND cg.is_multiple = 1"; return $isMultipleWithGid; } + /** + * Does this field type have any select options? + * + * @param array $field + * + * @return bool + */ + public static function hasOptions($field) { + // Fields retrieved via api are an array, or from the dao are an object. We'll accept either. + $field = (array) $field; + // This will include boolean fields with Yes/No options. + if (in_array($field['html_type'], ['Radio', 'CheckBox'])) { + return TRUE; + } + // Do this before the "Select" string search because date fields have a "Select Date" html_type + // and contactRef fields have an "Autocomplete-Select" html_type - contacts are an FK not an option list. + if (in_array($field['data_type'], ['ContactReference', 'Date'])) { + return FALSE; + } + if (strpos($field['html_type'], 'Select') !== FALSE) { + return TRUE; + } + return !empty($field['option_group_id']); + } + /** * Does this field store a serialized string? * diff --git a/CRM/Core/SelectValues.php b/CRM/Core/SelectValues.php index f5f0de0492..3c0eff439f 100644 --- a/CRM/Core/SelectValues.php +++ b/CRM/Core/SelectValues.php @@ -1145,8 +1145,9 @@ class CRM_Core_SelectValues { 'job_title' => ts('Job Title'), ]; $custom = civicrm_api3('CustomField', 'get', [ - 'return' => ["name", "label", "custom_group_id.title"], - 'custom_group_id.extends' => ['IN' => ["Contact", "Individual", "Organization", "Household"]], + 'return' => ['name', 'label', 'custom_group_id.title'], + 'custom_group_id.extends' => ['IN' => ['Contact', 'Individual', 'Organization', 'Household']], + 'data_type' => ['NOT IN' => ['ContactReference', 'Date', 'File']], 'custom_group_id.is_active' => 1, 'is_active' => 1, 'is_searchable' => 1, diff --git a/api/v3/Contact.php b/api/v3/Contact.php index 6c8901b56b..5e2dddc1b2 100644 --- a/api/v3/Contact.php +++ b/api/v3/Contact.php @@ -786,13 +786,24 @@ function civicrm_api3_contact_getquick($params) { $table_name = $table_names[$field_name]; } elseif (strpos($field_name, 'custom_') === 0) { - $customInfo = civicrm_api3('CustomField', 'getsingle', [ - 'return' => ["custom_group_id.table_name", "column_name"], + $customField = civicrm_api3('CustomField', 'getsingle', [ 'id' => substr($field_name, 7), + 'return' => ['custom_group_id.table_name', 'column_name', 'data_type', 'option_group_id', 'html_type'], ]); - $field_name = $customInfo['column_name']; - $table_name = CRM_Utils_String::munge($customInfo['custom_group_id.table_name']); + $field_name = $customField['column_name']; + $table_name = CRM_Utils_String::munge($customField['custom_group_id.table_name']); $from[$field_name] = "LEFT JOIN `$table_name` ON cc.id = `$table_name`.entity_id"; + if (CRM_Core_BAO_CustomField::hasOptions($customField)) { + $customOptionsWhere = []; + $customFieldOptions = CRM_Contact_BAO_Contact::buildOptions('custom_' . $customField['id'], 'search'); + $isMultivalueField = CRM_Core_BAO_CustomField::isSerialized($customField); + $sep = CRM_Core_DAO::VALUE_SEPARATOR; + foreach ($customFieldOptions as $optionKey => $optionLabel) { + if (mb_stripos($optionLabel, $name) !== FALSE) { + $customOptionsWhere[$optionKey] = "$table_name.$field_name " . ($isMultivalueField ? "LIKE '%{$sep}{$optionKey}{$sep}%'" : "= '$optionKey'"); + } + } + } } // phone_numeric should be phone $searchField = str_replace('_numeric', '', $field_name); @@ -857,12 +868,6 @@ function civicrm_api3_contact_getquick($params) { $select = ", $select"; } $actualSelectElements = implode(', ', $actualSelectElements); - $selectAliases = $from; - unset($selectAliases['address']); - $selectAliases = implode(', ', array_keys($selectAliases)); - if (!empty($selectAliases)) { - $selectAliases = ", $selectAliases"; - } $from = implode(' ', $from); $limit = (int) CRM_Utils_Array::value('limit', $params); $limit = $limit > 0 ? $limit : Civi::settings()->get('search_autocomplete_count'); @@ -939,14 +944,16 @@ function civicrm_api3_contact_getquick($params) { else { $strSearch = "$name%"; } - $includeEmailFrom = $includeNickName = $exactIncludeNickName = ''; + $includeEmailFrom = $includeNickName = ''; if ($config->includeNickNameInName) { $includeNickName = " OR nick_name LIKE '$strSearch'"; - $exactIncludeNickName = " OR nick_name LIKE '$name'"; } - //CRM-10687 - if (!empty($params['field_name']) && !empty($params['table_name'])) { + if (isset($customOptionsWhere)) { + $customOptionsWhere = $customOptionsWhere ?: [0]; + $whereClause = " WHERE (" . implode(' OR ', $customOptionsWhere) . ") $where"; + } + elseif (!empty($params['field_name']) && !empty($params['table_name'])) { $whereClause = " WHERE ( $table_name.$field_name LIKE '$strSearch') {$where}"; // Search by id should be exact if ($field_name == 'id' || $field_name == 'external_identifier') { @@ -983,7 +990,7 @@ function civicrm_api3_contact_getquick($params) { //CRM-5954 $query = " - SELECT DISTINCT(id), data, sort_name {$selectAliases}, exactFirst + SELECT DISTINCT(id), data, sort_name, exactFirst FROM ( ( SELECT IF($table_name.$field_name = '{$name}', 0, 1) as exactFirst, cc.id as id, CONCAT_WS( ' :: ', {$actualSelectElements} ) @@ -1035,6 +1042,14 @@ function civicrm_api3_contact_getquick($params) { $t[$k] = isset($dao->$k) ? $dao->$k : ''; } $t['data'] = $dao->data; + // Replace keys with values when displaying fields from an option list + if (!empty($customOptionsWhere)) { + $data = explode(' :: ', $dao->data); + $pos = count($data) - 1; + $customValue = array_intersect(CRM_Utils_Array::explodePadded($data[$pos]), array_keys($customOptionsWhere)); + $data[$pos] = implode(', ', array_intersect_key($customFieldOptions, array_flip($customValue))); + $t['data'] = implode(' :: ', $data); + } $contactList[] = $t; if (!empty($params['org']) && !empty($currEmpDetails) && -- 2.25.1