From 76ec9ca7d4546098e13e8f3d7d6fee7b383cd21e Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Mon, 10 Feb 2014 20:23:06 -0800 Subject: [PATCH] CRM-13966 - Wire up getlist api to entityRef fields --- CRM/Core/Form.php | 42 ++++-------- CRM/Core/Form/Renderer.php | 5 +- api/v3/Generic/Getlist.php | 18 ++++-- api/v3/examples/TagGetList.php | 71 +++++++++++++++++++++ js/Common.js | 16 ++--- tests/phpunit/CiviTest/CiviUnitTestCase.php | 4 ++ tests/phpunit/api/v3/TagTest.php | 9 +++ 7 files changed, 122 insertions(+), 43 deletions(-) create mode 100644 api/v3/examples/TagGetList.php diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php index 1b6f38b7a8..a4deeb4138 100644 --- a/CRM/Core/Form.php +++ b/CRM/Core/Form.php @@ -1256,13 +1256,8 @@ class CRM_Core_Form extends HTML_QuickForm_Page { * @param string $label * @param array $props mix of html and widget properties, including: * - select - params to give to select2 widget - * - api - array of settings for the api: - * - "entity" - defaults to contact - * - "action" - defaults to get (getquick when entity is contact) - * - "params" - additional params to pass to the api - * - "key" - what to store as this field's value - defaults to "id" - * - "label" - what to show to the user - defaults to "label" - * - "search" - rarely used - only needed if search field is different from label field + * - entity - defaults to contact + * - api - array of settings for the getlist api * - placeholder - string * - multiple - bool * - class, etc. - other html properties @@ -1270,23 +1265,12 @@ class CRM_Core_Form extends HTML_QuickForm_Page { * @return HTML_QuickForm_Element */ function addEntityRef($name, $label, $props = array(), $required = FALSE) { + // Default properties $props['api'] = CRM_Utils_Array::value('api', $props, array()); - // Merge in defaults for api params - $props['api'] += array( - 'entity' => 'contact', - 'key' => 'id', - ); - $props['api'] += array( - 'action' => $props['api']['entity'] == 'contact' ? 'getquick' : 'get', - 'label' => $props['api']['entity'] == 'contact' ? 'data' : 'label', - ); - // this can be ommitted for normal apis since search field is usually the same as label field. But getquick is bizarre. - $props['api'] += array( - 'search' => $props['api']['entity'] == 'contact' ? 'name' : $props['api']['label'], - ); + $props['entity'] = CRM_Utils_Array::value('entity', $props, 'contact'); $props['class'] = isset($props['class']) ? $props['class'] . ' ' : ''; - $props['class'] .= "crm-select2 crm-{$props['api']['entity']}-ref-field"; + $props['class'] .= "crm-select2 crm-form-entityref"; $props['select'] = CRM_Utils_Array::value('select', $props, array()) + array( 'minimumInputLength' => 1, @@ -1308,8 +1292,9 @@ class CRM_Core_Form extends HTML_QuickForm_Page { */ private function formatReferenceFieldAttributes(&$props) { $props['data-select-params'] = json_encode($props['select']); - $props['data-api-params'] = json_encode($props['api']); - CRM_Utils_Array::remove($props, 'multiple', 'select', 'api', 'placeholder'); + $props['data-api-params'] = $props['api'] ? json_encode($props['api']) : NULL; + $props['data-api-entity'] = $props['entity']; + CRM_Utils_Array::remove($props, 'multiple', 'select', 'api', 'entity', 'placeholder'); } /** @@ -1326,18 +1311,17 @@ class CRM_Core_Form extends HTML_QuickForm_Page { } if ($val) { $data = array(); - $api = json_decode($field->getAttribute('data-api-params'), TRUE); + $entity = $field->getAttribute('data-api-entity'); $select = json_decode($field->getAttribute('data-select-params'), TRUE); // Support serialized values if (strpos($val, CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE) { $val = str_replace(CRM_Core_DAO::VALUE_SEPARATOR, ',', trim($val, CRM_Core_DAO::VALUE_SEPARATOR)); $field->setValue($val); } - // TODO: we could fetch multiple values with array(IN => $val) but not all apis support this - foreach (explode(',', $val) as $v) { - $result = civicrm_api3($api['entity'], $api['action'], array('sequential' => 1, $api['key'] => $v)); - if (!empty($result['values'])) { - $data[] = array('id' => $v, 'text' => $result['values'][0][$api['label']]); + $result = civicrm_api3($entity, 'getlist', array('params' => array('id' => $val))); + if (!empty($result['values'])) { + foreach($result['values'] as $row) { + $data[] = array('id' => $row['id'], 'text' => $row['label']); } } if ($field->isFrozen()) { diff --git a/CRM/Core/Form/Renderer.php b/CRM/Core/Form/Renderer.php index 713bead502..e619497dea 100644 --- a/CRM/Core/Form/Renderer.php +++ b/CRM/Core/Form/Renderer.php @@ -179,7 +179,10 @@ class CRM_Core_Form_Renderer extends HTML_QuickForm_Renderer_ArraySmarty { if ($type == 'select' && $element->getAttribute('multiple')) { $type = 'multiselect'; } - $class = ($class ? "$class " : '') . 'crm-form-' . $type; + // Add widget-specific class + if (!$class || strpos($class, 'crm-form-') === FALSE) { + $class = ($class ? "$class " : '') . 'crm-form-' . $type; + } if ($required) { $class .= ' required'; diff --git a/api/v3/Generic/Getlist.php b/api/v3/Generic/Getlist.php index d5a65b84ff..84412592e9 100644 --- a/api/v3/Generic/Getlist.php +++ b/api/v3/Generic/Getlist.php @@ -72,7 +72,7 @@ function _civicrm_api3_generic_getList_defaults($entity, &$request) { 'page_num' => 1, 'input' => '', 'image_field' => NULL, - 'key_field' => 'id', + 'id_field' => 'id', 'params' => array(), ); // Find main field from meta @@ -101,9 +101,17 @@ function _civicrm_api3_generic_getList_defaults($entity, &$request) { ), 'sequential' => 1, ); + // When searching e.g. autocomplete if ($request['input']) { $params[$request['search_field']] = array('LIKE' => ($config->includeWildCardInName ? '%' : '') . $request['input'] . '%'); } + // When looking up a field e.g. displaying existing record + if (!empty($request['id'])) { + if (is_string($request['id']) && strpos(',', $request['id'])) { + $request['id'] = explode(',', $request['id']); + } + $params[$request['id_field']] = is_array($request['id']) ? array('IN' => $request['id']) : $request['id']; + } $request['params'] += $params; } @@ -113,9 +121,9 @@ function _civicrm_api3_generic_getList_defaults($entity, &$request) { * @param $request array */ function _civicrm_api3_generic_getlist_params(&$request) { - $fieldsToReturn = array($request['key_field'], $request['label_field']); - $request['image_field'] && $fieldsToReturn[] = $request['image_field']; - $request['description_field'] && $fieldsToReturn[] = $request['description_field']; + $fieldsToReturn = array($request['id_field'], $request['label_field']); + !empty($request['image_field']) && $fieldsToReturn[] = $request['image_field']; + !empty($request['description_field']) && $fieldsToReturn[] = $request['description_field']; $request['params']['options']['return'] = $fieldsToReturn; } @@ -132,7 +140,7 @@ function _civicrm_api3_generic_getlist_output($result, $request) { if (!empty($result['values'])) { foreach ($result['values'] as $row) { $output[] = array( - 'key' => $row[$request['key_field']], + 'id' => $row[$request['id_field']], 'label' => $row[$request['label_field']], 'description' => isset($request['description_field']) && isset($row[$request['description_field']]) ? $row[$request['description_field']] : NULL, 'image' => isset($request['image_field']) && isset($row[$request['image_field']]) ? $row[$request['image_field']] : NULL, diff --git a/api/v3/examples/TagGetList.php b/api/v3/examples/TagGetList.php new file mode 100644 index 0000000000..43d1b72baa --- /dev/null +++ b/api/v3/examples/TagGetList.php @@ -0,0 +1,71 @@ + 'New Tag3', +); + +try{ + $result = civicrm_api3('tag', 'getlist', $params); +} +catch (CiviCRM_API3_Exception $e) { + // handle error here + $errorMessage = $e->getMessage(); + $errorCode = $e->getErrorCode(); + $errorData = $e->getExtraParams(); + return array('error' => $errorMessage, 'error_code' => $errorCode, 'error_data' => $errorData); +} + +return $result; +} + +/** + * Function returns array of result expected from previous function + */ +function tag_getlist_expectedresult(){ + + $expectedResult = array( + 'is_error' => 0, + 'version' => 3, + 'count' => 1, + 'id' => 0, + 'values' => array( + '0' => array( + 'id' => '6', + 'label' => 'New Tag3', + 'description' => 'This is description for Our New Tag ', + 'image' => '', + ), + ), + 'more_results' => '', + 'page_num' => 1, +); + + return $expectedResult; +} + + +/* +* This example has been generated from the API test suite. The test that created it is called +* +* testTagGetList and can be found in +* http://svn.civicrm.org/civicrm/trunk/tests/phpunit/CiviTest/api/v3/TagTest.php +* +* You can see the outcome of the API tests at +* http://tests.dev.civicrm.org/trunk/results-api_v3 +* +* To Learn about the API read +* http://book.civicrm.org/developer/current/techniques/api/ +* +* and review the wiki at +* http://wiki.civicrm.org/confluence/display/CRMDOC/CiviCRM+Public+APIs +* +* Read more about testing here +* http://wiki.civicrm.org/confluence/display/CRM/Testing +* +* API Standards documentation: +* http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards +*/ diff --git a/js/Common.js b/js/Common.js index fb59c47c19..2f06ba6701 100644 --- a/js/Common.js +++ b/js/Common.js @@ -304,18 +304,18 @@ CRM.validate = CRM.validate || { options.placeholderOption = 'first'; } } - // Api-based searching - if ($(this).data('api-params')) { + // Autocomplete using the getlist api + if ($(this).data('api-entity') && $(this).hasClass('crm-form-entityref')) { $(this).addClass('crm-ajax-select') options.query = function(info) { - var api = $(info.element).data('api-params'); - var params = api.params || {}; - params[api.search] = info.term; - CRM.api3(api.entity, api.action, params).done(function(data) { - var results = {context: info.context, results: []}; + var params = $(info.element).data('api-params') || {}; + params.input = info.term; + params.page_num = info.page; + CRM.api3($(info.element).data('api-entity'), 'getlist', params).done(function(data) { + var results = {context: info.context, more: data.more_results, results: []}; if (typeof(data.values) === 'object') { $.each(data.values, function(k, v) { - results.results.push({id: v[api.key], text: v[api.label]}); + results.results.push({id: v.id, text: v.label}); }); } info.callback(results); diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index 6833161f31..048114cbc3 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -1862,6 +1862,10 @@ class CiviUnitTestCase extends PHPUnit_Extensions_Database_TestCase { $action = empty($action) ? 'getfields' : $action; $entityAction = 'GetFields'; } + elseif (strstr($function, 'GetList')) { + $action = empty($action) ? 'getlist' : $action; + $entityAction = 'GetList'; + } elseif (strstr($function, 'Get')) { $action = empty($action) ? 'get' : $action; $entityAction = 'Get'; diff --git a/tests/phpunit/api/v3/TagTest.php b/tests/phpunit/api/v3/TagTest.php index 62419f7f0c..aa4798a0e4 100644 --- a/tests/phpunit/api/v3/TagTest.php +++ b/tests/phpunit/api/v3/TagTest.php @@ -191,5 +191,14 @@ class api_v3_TagTest extends CiviUnitTestCase { $result = $this->callAPIAndDocument('tag', 'getfields', $params, __FUNCTION__, __FILE__, $description, NULL, 'getfields'); $this->assertEquals('civicrm_contact', $result['values']['used_for']['api.default']); } + + function testTagGetList() { + $description = "Demonstrates use of api.getlist for autocomplete and quicksearch applications"; + $params = array( + 'input' => $this->tag['name'], + ); + $result = $this->callAPIAndDocument('tag', 'getlist', $params, __FUNCTION__, __FILE__); + $this->assertEquals($this->tag['description'], $result['values'][0]['description'], 'In line ' . __LINE__); + } } -- 2.25.1