Merge pull request #15338 from totten/master-poc-postcommit
[civicrm-core.git] / api / v3 / Generic / Getlist.php
CommitLineData
fe43b7c9 1<?php
fe43b7c9
CW
2/*
3 +--------------------------------------------------------------------+
a30c801b 4 | Copyright CiviCRM LLC. All rights reserved. |
b081365f 5 | |
a30c801b
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 |
b081365f 9 +--------------------------------------------------------------------+
e70a7fc0 10 */
b081365f
CW
11
12/**
13 * @package CiviCRM_APIv3
14 */
15
fe43b7c9 16/**
2fb1dd66 17 * Generic api wrapper used for quicksearch and autocomplete.
fe43b7c9 18 *
72b3a70c 19 * @param array $apiRequest
2fb1dd66 20 *
fe43b7c9
CW
21 * @return mixed
22 */
23function civicrm_api3_generic_getList($apiRequest) {
24 $entity = _civicrm_api_get_entity_name_from_camel($apiRequest['entity']);
25 $request = $apiRequest['params'];
cf8f0fff 26 $meta = civicrm_api3_generic_getfields(['action' => 'get'] + $apiRequest, FALSE);
ebf2b57b 27
bc255d1d
CW
28 // Hey api, would you like to provide default values?
29 $fnName = "_civicrm_api3_{$entity}_getlist_defaults";
cf8f0fff 30 $defaults = function_exists($fnName) ? $fnName($request) : [];
6b4c9564 31 _civicrm_api3_generic_getList_defaults($entity, $request, $defaults, $meta['values']);
ebf2b57b 32
fe43b7c9
CW
33 // Hey api, would you like to format the search params?
34 $fnName = "_civicrm_api3_{$entity}_getlist_params";
35 $fnName = function_exists($fnName) ? $fnName : '_civicrm_api3_generic_getlist_params';
36 $fnName($request);
79ae07d9
CW
37
38 $request['params']['check_permissions'] = !empty($apiRequest['params']['check_permissions']);
fe43b7c9
CW
39 $result = civicrm_api3($entity, 'get', $request['params']);
40
41 // Hey api, would you like to format the output?
42 $fnName = "_civicrm_api3_{$entity}_getlist_output";
43 $fnName = function_exists($fnName) ? $fnName : '_civicrm_api3_generic_getlist_output';
6b4c9564 44 $values = $fnName($result, $request, $entity, $meta['values']);
fe43b7c9 45
27d7d241
CW
46 _civicrm_api3_generic_getlist_postprocess($result, $request, $values);
47
cf8f0fff 48 $output = ['page_num' => $request['page_num']];
78b203e5
CW
49
50 // Limit is set for searching but not fetching by id
a6c6059d 51 if (!empty($request['params']['options']['limit'])) {
fe43b7c9 52 // If we have an extra result then this is not the last page
a6c6059d 53 $last = $request['params']['options']['limit'] - 1;
78b203e5
CW
54 $output['more_results'] = isset($values[$last]);
55 unset($values[$last]);
56 }
fe43b7c9
CW
57
58 return civicrm_api3_create_success($values, $request['params'], $entity, 'getlist', CRM_Core_DAO::$_nullObject, $output);
59}
60
61/**
211e2fca 62 * Set defaults for api.getlist.
fe43b7c9 63 *
8c6b335b
CW
64 * @param string $entity
65 * @param array $request
bc255d1d 66 * @param array $apiDefaults
3bdf1f3a 67 * @param array $fields
fe43b7c9 68 */
6b4c9564 69function _civicrm_api3_generic_getList_defaults($entity, &$request, $apiDefaults, $fields) {
cf8f0fff 70 $defaults = [
fe43b7c9
CW
71 'page_num' => 1,
72 'input' => '',
73 'image_field' => NULL,
4fcc9877 74 'color_field' => isset($fields['color']) ? 'color' : NULL,
0724132d 75 'id_field' => $entity == 'option_value' ? 'value' : 'id',
cf8f0fff 76 'description_field' => [],
81b7bb6f 77 'add_wildcard' => Civi::settings()->get('includeWildCardInName'),
cf8f0fff
CW
78 'params' => [],
79 'extra' => [],
80 ];
fe43b7c9 81 // Find main field from meta
cf8f0fff 82 foreach (['sort_name', 'title', 'label', 'name', 'subject'] as $field) {
fe43b7c9
CW
83 if (isset($fields[$field])) {
84 $defaults['label_field'] = $defaults['search_field'] = $field;
85 break;
86 }
87 }
8250601e 88 // Find fields to be used for the description
cf8f0fff 89 foreach (['description'] as $field) {
fe43b7c9 90 if (isset($fields[$field])) {
8250601e 91 $defaults['description_field'][] = $field;
fe43b7c9
CW
92 }
93 }
89595c92 94 $resultsPerPage = Civi::settings()->get('search_autocomplete_count');
6b4c9564
CW
95 if (isset($request['params']) && isset($apiDefaults['params'])) {
96 $request['params'] += $apiDefaults['params'];
97 }
bc255d1d 98 $request += $apiDefaults + $defaults;
fe43b7c9 99 // Default api params
cf8f0fff 100 $params = [
fe43b7c9 101 'sequential' => 1,
cf8f0fff
CW
102 'options' => [],
103 ];
76ec9ca7 104 // When searching e.g. autocomplete
fe43b7c9 105 if ($request['input']) {
cf8f0fff 106 $params[$request['search_field']] = ['LIKE' => ($request['add_wildcard'] ? '%' : '') . $request['input'] . '%'];
fe43b7c9 107 }
76ec9ca7
CW
108 // When looking up a field e.g. displaying existing record
109 if (!empty($request['id'])) {
83e11123
CW
110 if (is_string($request['id']) && strpos($request['id'], ',')) {
111 $request['id'] = explode(',', trim($request['id'], ', '));
76ec9ca7 112 }
78b203e5 113 // Don't run into search limits when prefilling selection
ba3b21c3
CW
114 $params['options']['limit'] = NULL;
115 unset($params['options']['offset'], $request['params']['options']['limit'], $request['params']['options']['offset']);
cf8f0fff 116 $params[$request['id_field']] = is_array($request['id']) ? ['IN' => $request['id']] : $request['id'];
76ec9ca7 117 }
fe43b7c9 118 $request['params'] += $params;
deb188d8 119
cf8f0fff 120 $request['params']['options'] += [
deb188d8
FW
121 // Add pagination parameters
122 'sort' => $request['label_field'],
123 // Adding one extra result allows us to see if there are any more
124 'limit' => $resultsPerPage + 1,
125 // Because sql is zero-based
126 'offset' => ($request['page_num'] - 1) * $resultsPerPage,
cf8f0fff 127 ];
fe43b7c9
CW
128}
129
130/**
c1a920f1 131 * Fallback implementation of getlist_params. May be overridden by individual apis.
fe43b7c9 132 *
8c6b335b 133 * @param array $request
fe43b7c9
CW
134 */
135function _civicrm_api3_generic_getlist_params(&$request) {
cf8f0fff 136 $fieldsToReturn = [$request['id_field'], $request['label_field']];
ff88d165
CW
137 if (!empty($request['image_field'])) {
138 $fieldsToReturn[] = $request['image_field'];
139 }
4fcc9877
CW
140 if (!empty($request['color_field'])) {
141 $fieldsToReturn[] = $request['color_field'];
142 }
ff88d165 143 if (!empty($request['description_field'])) {
8250601e 144 $fieldsToReturn = array_merge($fieldsToReturn, (array) $request['description_field']);
ff88d165 145 }
8250601e 146 $request['params']['return'] = array_unique(array_merge($fieldsToReturn, $request['extra']));
fe43b7c9
CW
147}
148
149/**
211e2fca 150 * Fallback implementation of getlist_output. May be overridden by individual api functions.
fe43b7c9 151 *
8c6b335b
CW
152 * @param array $result
153 * @param array $request
b233e1b4 154 * @param string $entity
6b4c9564 155 * @param array $fields
fe43b7c9
CW
156 *
157 * @return array
158 */
6b4c9564 159function _civicrm_api3_generic_getlist_output($result, $request, $entity, $fields) {
cf8f0fff 160 $output = [];
fe43b7c9
CW
161 if (!empty($result['values'])) {
162 foreach ($result['values'] as $row) {
cf8f0fff 163 $data = [
76ec9ca7 164 'id' => $row[$request['id_field']],
fe43b7c9 165 'label' => $row[$request['label_field']],
cf8f0fff 166 ];
ff88d165 167 if (!empty($request['description_field'])) {
cf8f0fff 168 $data['description'] = [];
8250601e
CW
169 foreach ((array) $request['description_field'] as $field) {
170 if (!empty($row[$field])) {
6b4c9564
CW
171 if (!isset($fields[$field]['pseudoconstant'])) {
172 $data['description'][] = $row[$field];
173 }
174 else {
175 $data['description'][] = CRM_Core_PseudoConstant::getLabel(
176 _civicrm_api3_get_BAO($entity),
177 $field,
178 $row[$field]
179 );
180 }
8250601e
CW
181 }
182 }
ff88d165
CW
183 };
184 if (!empty($request['image_field'])) {
185 $data['image'] = isset($row[$request['image_field']]) ? $row[$request['image_field']] : '';
8250601e 186 }
4fcc9877
CW
187 if (isset($row[$request['color_field']])) {
188 $data['color'] = $row[$request['color_field']];
189 }
ff88d165 190 $output[] = $data;
fe43b7c9
CW
191 }
192 }
193 return $output;
194}
f7b2fef0 195
27d7d241
CW
196/**
197 * Common postprocess for getlist output
198 *
199 * @param $result
200 * @param $request
201 * @param $values
202 */
203function _civicrm_api3_generic_getlist_postprocess($result, $request, &$values) {
cf8f0fff 204 $chains = [];
27d7d241
CW
205 foreach ($request['params'] as $field => $param) {
206 if (substr($field, 0, 4) === 'api.') {
207 $chains[] = $field;
208 }
209 }
210 if (!empty($result['values'])) {
211 foreach (array_values($result['values']) as $num => $row) {
212 foreach ($request['extra'] as $field) {
213 $values[$num]['extra'][$field] = isset($row[$field]) ? $row[$field] : NULL;
214 }
215 foreach ($chains as $chain) {
216 $values[$num][$chain] = isset($row[$chain]) ? $row[$chain] : NULL;
217 }
218 }
219 }
220}
221
f7b2fef0
CW
222/**
223 * Provide metadata for this api
224 *
225 * @param array $params
226 * @param array $apiRequest
227 */
228function _civicrm_api3_generic_getlist_spec(&$params, $apiRequest) {
cf8f0fff
CW
229 $params += [
230 'page_num' => [
f7b2fef0
CW
231 'title' => 'Page Number',
232 'description' => "Current page of a multi-page lookup",
233 'type' => CRM_Utils_Type::T_INT,
cf8f0fff
CW
234 ],
235 'input' => [
f7b2fef0
CW
236 'title' => 'Search Input',
237 'description' => "String to search on",
238 'type' => CRM_Utils_Type::T_TEXT,
cf8f0fff
CW
239 ],
240 'params' => [
f7b2fef0
CW
241 'title' => 'API Params',
242 'description' => "Additional filters to send to the {$apiRequest['entity']} API.",
cf8f0fff
CW
243 ],
244 'extra' => [
f7b2fef0
CW
245 'title' => 'Extra',
246 'description' => 'Array of additional fields to return.',
cf8f0fff
CW
247 ],
248 'image_field' => [
f7b2fef0
CW
249 'title' => 'Image Field',
250 'description' => "Field that this entity uses to store icons (usually automatic)",
251 'type' => CRM_Utils_Type::T_TEXT,
cf8f0fff
CW
252 ],
253 'id_field' => [
f7b2fef0
CW
254 'title' => 'ID Field',
255 'description' => "Field that uniquely identifies this entity (usually automatic)",
256 'type' => CRM_Utils_Type::T_TEXT,
cf8f0fff
CW
257 ],
258 'description_field' => [
f7b2fef0
CW
259 'title' => 'Description Field',
260 'description' => "Field that this entity uses to store summary text (usually automatic)",
261 'type' => CRM_Utils_Type::T_TEXT,
cf8f0fff
CW
262 ],
263 'label_field' => [
fee3e3c3 264 'title' => 'Label Field',
f7b2fef0
CW
265 'description' => "Field to display as title of results (usually automatic)",
266 'type' => CRM_Utils_Type::T_TEXT,
cf8f0fff
CW
267 ],
268 'search_field' => [
f7b2fef0
CW
269 'title' => 'Search Field',
270 'description' => "Field to search on (assumed to be the same as label field unless otherwise specified)",
271 'type' => CRM_Utils_Type::T_TEXT,
cf8f0fff
CW
272 ],
273 ];
f7b2fef0 274}