OptionValues - Specify id+name+label for option callbacks that use it
[civicrm-core.git] / tests / phpunit / api / v3 / CustomValueTest.php
CommitLineData
6a488035 1<?php
7d61e75f
TO
2
3/*
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
6 | |
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
10 +--------------------------------------------------------------------+
6c6e6187 11 */
6a488035 12
e9479dcf
EM
13/**
14 * Class api_v3_CustomValueTest
acb109b7 15 * @group headless
e9479dcf 16 */
6a488035 17class api_v3_CustomValueTest extends CiviUnitTestCase {
6c6e6187 18 protected $_apiversion = 3;
f9a5aadd 19
ec28b24d 20 protected $optionGroup;
b7c9bc4c 21
6a488035
TO
22 public $DBResetRequired = FALSE;
23
56fbe1df
YN
24 /**
25 * @throws \CRM_Core_Exception
26 */
6fca1a34 27 public function _populateOptionAndCustomGroup($type = NULL) {
9099cab3
CW
28 $dataValues = [
29 'integer' => [1, 2, 3],
30 'number' => [10.11, 20.22, 30.33],
31 'string' => [substr(sha1(rand()), 0, 4) . '(', substr(sha1(rand()), 0, 3) . '|', substr(sha1(rand()), 0, 2) . ','],
f9887f64 32 // 'country' => array_rand(CRM_Core_PseudoConstant::country(FALSE, FALSE), 3),
33 // This does not work in the test at the moment due to caching issues.
34 //'state_province' => array_rand(CRM_Core_PseudoConstant::stateProvince(FALSE, FALSE), 3),
ec28b24d 35 'date' => NULL,
a6d226f4 36 'contact' => NULL,
872a35c1 37 'boolean' => NULL,
9099cab3 38 ];
ec28b24d 39
9099cab3 40 $dataValues = !empty($type) ? [$type => $dataValues[$type]] : $dataValues;
6fca1a34 41
ec28b24d 42 foreach ($dataValues as $dataType => $values) {
9099cab3 43 $this->optionGroup[$dataType] = ['values' => $values];
ec28b24d 44 if (!empty($values)) {
ec28b24d 45 $result = $this->callAPISuccess('OptionGroup', 'create',
9099cab3 46 [
ec28b24d 47 'name' => "{$dataType}_group",
9099cab3
CW
48 'api.option_value.create' => ['label' => "$dataType 1", 'value' => $values[0]],
49 'api.option_value.create.1' => ['label' => "$dataType 2", 'value' => $values[1]],
50 'api.option_value.create.2' => ['label' => "$dataType 3", 'value' => $values[2]],
51 ]
ec28b24d 52 );
53 $this->optionGroup[$dataType]['id'] = $result['id'];
54 }
56fbe1df 55 elseif ($dataType === 'contact') {
f819588f 56 for ($i = 0; $i < 3; $i++) {
9099cab3 57 $result = $this->callAPISuccess('Contact', 'create', ['contact_type' => 'Individual', 'email' => substr(sha1(rand()), 0, 7) . '@yahoo.com']);
a6d226f4 58 $this->optionGroup[$dataType]['values'][$i] = $result['id'];
59 }
60 }
ec28b24d 61 $this->ids[$dataType] = $this->entityCustomGroupWithSingleFieldCreate("$dataType Custom Group", 'Contacts');
62 }
63
6a488035
TO
64 }
65
11ba3ace 66 public function tearDown(): void {
9099cab3 67 $tablesToTruncate = [
6a488035
TO
68 'civicrm_email',
69 'civicrm_custom_field',
70 'civicrm_custom_group',
71 'civicrm_contact',
9099cab3 72 ];
6a488035
TO
73
74 // true tells quickCleanup to drop any tables that might have been created in the test
75 $this->quickCleanup($tablesToTruncate, TRUE);
6fca1a34 76
77 // cleanup created option group for each custom-set before running next test
78 if (!empty($this->optionGroup)) {
56fbe1df 79 foreach ($this->optionGroup as $value) {
6fca1a34 80 if (!empty($value['id'])) {
9099cab3 81 $count = $this->callAPISuccess('OptionGroup', 'get', ['id' => $value['id']]);
a60c0bc8 82 if ((bool) $count['count']) {
9099cab3 83 $this->callAPISuccess('OptionGroup', 'delete', ['id' => $value['id']]);
a60c0bc8 84 }
6fca1a34 85 }
86 }
87 }
56fbe1df 88 parent::tearDown();
6a488035
TO
89 }
90
91 public function testCreateCustomValue() {
6fca1a34 92 $this->_populateOptionAndCustomGroup();
9099cab3 93 $this->_customField = $this->customFieldCreate(['custom_group_id' => $this->ids['string']['custom_group_id']]);
0ec36ef1 94 $this->_customFieldID = $this->_customField['id'];
6fca1a34 95
c44d3d25 96 $customFieldDataType = array_column(CRM_Core_BAO_CustomField::dataType(), 'id');
5d2f1ed6 97 $dataToHtmlTypes = CRM_Custom_Form_Field::$_dataToHTML;
9b85cd33 98 $optionSupportingHTMLTypes = CRM_Custom_Form_Field::$htmlTypesWithOptions;
6a488035 99
c44d3d25 100 foreach ($customFieldDataType as $dataType) {
ec28b24d 101 switch ($dataType) {
9b85cd33 102 // skipping File data-type & state province due to caching issues
f9887f64 103 // case 'Country':
104 // case 'StateProvince':
ec28b24d 105 case 'String':
106 case 'Link':
107 case 'Int':
108 case 'Float':
109 case 'Money':
872a35c1 110 case 'Date':
872a35c1 111 case 'Boolean':
112
113 //Based on the custom field data-type choose desired SQL operators(to test with) and basic $type
9099cab3
CW
114 if (in_array($dataType, ['String', 'Link'])) {
115 $validSQLOperators = ['=', '!=', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE', 'IS NOT NULL', 'IS NULL'];
ec28b24d 116 $type = 'string';
117 }
872a35c1 118 elseif ($dataType == 'Boolean') {
9099cab3 119 $validSQLOperators = ['=', '!=', 'IS NOT NULL', 'IS NULL'];
872a35c1 120 $type = 'boolean';
121 }
ec28b24d 122 else {
872a35c1 123 if ($dataType == 'Country') {
124 $type = 'country';
125 }
126 elseif ($dataType == 'StateProvince') {
ec28b24d 127 $type = 'state_province';
128 }
a6d226f4 129 elseif ($dataType == 'ContactReference') {
130 $type = 'contact';
131 }
132 elseif ($dataType == 'Date') {
133 $type = 'date';
134 }
ec28b24d 135 else {
a6d226f4 136 $type = $dataType == 'Int' ? 'integer' : 'number';
ec28b24d 137 }
9099cab3 138 $validSQLOperators = ['=', '!=', 'IN', 'NOT IN', '<=', '>=', '>', '<', 'IS NOT NULL', 'IS NULL'];
ec28b24d 139 }
6a488035 140
872a35c1 141 //Create custom field of $dataType and html-type $html
9b85cd33 142 foreach ($dataToHtmlTypes[$dataType] as $html) {
f9887f64 143 // per CRM-18568 the like operator does not currently work for fields with options.
144 // the LIKE operator could potentially bypass ACLs (as could IS NOT NULL) and some thought needs to be given
145 // to it.
146 if (in_array($html, $optionSupportingHTMLTypes)) {
9099cab3 147 $validSQLOperators = array_diff($validSQLOperators, ['LIKE', 'NOT LIKE']);
f9887f64 148 }
9099cab3 149 $params = [
ec28b24d 150 'custom_group_id' => $this->ids[$type]['custom_group_id'],
151 'label' => "$dataType - $html",
152 'data_type' => $dataType,
153 'html_type' => $html,
154 'default_value' => NULL,
9099cab3
CW
155 ];
156 if (!in_array($html, ['Text', 'TextArea']) && !in_array($dataType, ['Link', 'Date', 'ContactReference', 'Boolean'])) {
157 $params += ['option_group_id' => $this->optionGroup[$type]['id']];
ec28b24d 158 }
159 $customField = $this->customFieldCreate($params);
872a35c1 160 //Now test with $validSQLOperator SQL operators against its custom value(s)
161 $this->_testCustomValue($customField['values'][$customField['id']], $validSQLOperators, $type);
ec28b24d 162 }
6a488035 163
ec28b24d 164 }
165 }
166 }
6a488035 167
ec28b24d 168 public function _testCustomValue($customField, $sqlOps, $type) {
169 $isSerialized = CRM_Core_BAO_CustomField::isSerialized($customField);
170 $customId = $customField['id'];
9099cab3 171 $params = [
6a488035 172 'contact_type' => 'Individual',
ec28b24d 173 'email' => substr(sha1(rand()), 0, 7) . 'man1@yahoo.com',
9099cab3 174 ];
fc928539 175 $result = $this->callAPISuccess('Contact', 'create', $params);
ec28b24d 176 $contactId = $result['id'];
6a488035 177
8007b543 178 $count = rand(1, 2);
f9887f64 179
ec28b24d 180 if ($isSerialized) {
181 $selectedValue = $this->optionGroup[$type]['values'];
182 $notselectedValue = $selectedValue[$count];
183 unset($selectedValue[$count]);
184 }
185 elseif ($customField['html_type'] == 'Link') {
186 $selectedValue = "http://" . substr(sha1(rand()), 0, 7) . ".com";
187 $notselectedValue = "http://" . substr(sha1(rand()), 0, 7) . ".com";
188 }
189 elseif ($type == 'date') {
190 $selectedValue = date('Ymd');
a6d226f4 191 $notselectedValue = $lesserSelectedValue = date('Ymd', strtotime('yesterday'));
192 $greaterSelectedValue = date('Ymd', strtotime('+ 1 day'));
193 }
194 elseif ($type == 'contact') {
195 $selectedValue = $this->optionGroup[$type]['values'][1];
196 $notselectedValue = $this->optionGroup[$type]['values'][0];
ec28b24d 197 }
872a35c1 198 elseif ($type == 'boolean') {
199 $selectedValue = 1;
200 $notselectedValue = 0;
201 }
ec28b24d 202 else {
203 $selectedValue = $this->optionGroup[$type]['values'][0];
204 $notselectedValue = $this->optionGroup[$type]['values'][$count];
a6d226f4 205 if (in_array(">", $sqlOps)) {
206 $greaterSelectedValue = $selectedValue + 1;
207 $lesserSelectedValue = $selectedValue - 1;
208 }
ec28b24d 209 }
6a488035 210
0ec36ef1
JP
211 $params = [
212 'entity_id' => $contactId,
213 'custom_' . $customId => $selectedValue,
214 "custom_{$this->_customFieldID}" => "Test String Value for {$this->_customFieldID}",
215 ];
ec28b24d 216 $this->callAPISuccess('CustomValue', 'create', $params);
6c6e6187 217
bc3c9f57
JP
218 //Test for different return value syntax.
219 $returnValues = [
220 ['return' => "custom_{$customId}"],
221 ['return' => ["custom_{$customId}"]],
222 ["return.custom_{$customId}" => 1],
0ec36ef1
JP
223 ['return' => ["custom_{$customId}", "custom_{$this->_customFieldID}"]],
224 ["return.custom_{$customId}" => 1, "return.custom_{$this->_customFieldID}" => 1],
bc3c9f57 225 ];
0ec36ef1 226 foreach ($returnValues as $key => $val) {
bc3c9f57 227 $params = array_merge($val, [
bc3c9f57
JP
228 'entity_id' => $contactId,
229 ]);
230 $customValue = $this->callAPISuccess('CustomValue', 'get', $params);
231 if (is_array($selectedValue)) {
232 $expected = array_values($selectedValue);
0ec36ef1 233 $this->checkArrayEquals($expected, $customValue['values'][$customId]['latest']);
bc3c9f57
JP
234 }
235 elseif ($type == 'date') {
0ec36ef1 236 $this->assertEquals($selectedValue, date('Ymd', strtotime(str_replace('.', '/', $customValue['values'][$customId]['latest']))));
bc3c9f57
JP
237 }
238 else {
0ec36ef1
JP
239 $this->assertEquals($selectedValue, $customValue['values'][$customId]['latest']);
240 }
241 if ($key > 2) {
242 $this->assertEquals("Test String Value for {$this->_customFieldID}", $customValue['values'][$this->_customFieldID]['latest']);
bc3c9f57
JP
243 }
244 }
245
ec28b24d 246 foreach ($sqlOps as $op) {
a6d226f4 247 $qillOp = CRM_Utils_Array::value($op, CRM_Core_SelectValues::getSearchBuilderOperators(), $op);
ec28b24d 248 switch ($op) {
a6d226f4 249 case '=':
9099cab3 250 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => (is_array($selectedValue) ? implode(CRM_Core_DAO::VALUE_SEPARATOR, $selectedValue) : $selectedValue)]);
a6d226f4 251 $this->assertEquals($contactId, $result['id']);
a6d226f4 252 break;
842ee194 253
ec28b24d 254 case '!=':
9099cab3 255 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => $notselectedValue]]);
a4a68fa4 256 $this->assertEquals(TRUE, array_key_exists($contactId, $result['values']));
ec28b24d 257 break;
6c6e6187 258
ec28b24d 259 case '>':
260 case '<':
261 case '>=':
262 case '<=':
a6d226f4 263 if ($isSerialized) {
e255b57a 264 break;
a6d226f4 265 }
ec28b24d 266 // To be precise in for these operator we can't just rely on one contact,
267 // hence creating multiple contact with custom value less/more then $selectedValue respectively
9099cab3 268 $result = $this->callAPISuccess('Contact', 'create', ['contact_type' => 'Individual', 'email' => substr(sha1(rand()), 0, 7) . 'man2@yahoo.com']);
ec28b24d 269 $contactId2 = $result['id'];
9099cab3 270 $this->callAPISuccess('CustomValue', 'create', ['entity_id' => $contactId2, 'custom_' . $customId => $lesserSelectedValue]);
842ee194 271
ec28b24d 272 if ($op == '>') {
9099cab3 273 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => $lesserSelectedValue]]);
ec28b24d 274 $this->assertEquals($contactId, $result['id']);
275 }
276 elseif ($op == '<') {
9099cab3 277 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => $selectedValue]]);
ec28b24d 278 $this->assertEquals($contactId2, $result['id']);
279 }
280 else {
9099cab3 281 $result = $this->callAPISuccess('Contact', 'create', ['contact_type' => 'Individual', 'email' => substr(sha1(rand()), 0, 7) . 'man3@yahoo.com']);
ec28b24d 282 $contactId3 = $result['id'];
9099cab3 283 $this->callAPISuccess('CustomValue', 'create', ['entity_id' => $contactId3, 'custom_' . $customId => $greaterSelectedValue]);
842ee194 284
9099cab3 285 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => $selectedValue]]);
ec28b24d 286
287 $this->assertEquals($contactId, $result['values'][$contactId]['id']);
288 if ($op == '>=') {
289 $this->assertEquals($contactId3, $result['values'][$contactId3]['id']);
290 }
291 else {
292 $this->assertEquals($contactId2, $result['values'][$contactId2]['id']);
293 }
9099cab3 294 $this->callAPISuccess('contact', 'delete', ['id' => $contactId3]);
ec28b24d 295 }
296
9099cab3 297 $this->callAPISuccess('contact', 'delete', ['id' => $contactId2]);
ec28b24d 298 break;
299
300 case 'IN':
9099cab3 301 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => (array) $selectedValue]]);
ec28b24d 302 $this->assertEquals($contactId, $result['id']);
303 break;
304
305 case 'NOT IN':
9099cab3 306 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => (array) $notselectedValue]]);
ec28b24d 307 $this->assertEquals($contactId, $result['id']);
308 break;
309
310 case 'LIKE':
a6d226f4 311 $selectedValue = is_array($selectedValue) ? $selectedValue[0] : $selectedValue;
9099cab3 312 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => "%$selectedValue%"]]);
ec28b24d 313 $this->assertEquals($contactId, $result['id']);
314 break;
6a488035 315
ec28b24d 316 case 'NOT LIKE':
9099cab3 317 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => $notselectedValue]]);
ec28b24d 318 $this->assertEquals($contactId, $result['id']);
319 break;
6c6e6187 320
ec28b24d 321 case 'IS NULL':
9099cab3 322 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => 1]]);
ec28b24d 323 $this->assertEquals(FALSE, array_key_exists($contactId, $result['values']));
324 break;
842ee194 325
ec28b24d 326 case 'IS NOT NULL':
9099cab3 327 $result = $this->callAPISuccess('Contact', 'Get', ['custom_' . $customId => [$op => 1]]);
ec28b24d 328 $this->assertEquals($contactId, $result['id']);
329 break;
330 }
331 }
6c6e6187 332
9099cab3 333 $this->callAPISuccess('Contact', 'delete', ['id' => $contactId]);
842ee194 334 }
96025800 335
58eaa092
CW
336 /**
337 * Ensure custom data is updated when option values are modified
338 *
339 * @link https://issues.civicrm.org/jira/browse/CRM-11856
340 *
341 * @throws \CiviCRM_API3_Exception
342 */
343 public function testAlterOptionValue() {
6fca1a34 344 $this->_populateOptionAndCustomGroup('string');
345
9099cab3 346 $selectField = $this->customFieldCreate([
6fca1a34 347 'custom_group_id' => $this->ids['string']['custom_group_id'],
58eaa092
CW
348 'label' => 'Custom Select',
349 'html_type' => 'Select',
6fca1a34 350 'option_group_id' => $this->optionGroup['string']['id'],
9099cab3
CW
351 ]);
352 $selectField = civicrm_api3('customField', 'getsingle', ['id' => $selectField['id']]);
353 $radioField = $this->customFieldCreate([
6fca1a34 354 'custom_group_id' => $this->ids['string']['custom_group_id'],
58eaa092
CW
355 'label' => 'Custom Radio',
356 'html_type' => 'Radio',
357 'option_group_id' => $selectField['option_group_id'],
9099cab3
CW
358 ]);
359 $multiSelectField = $this->customFieldCreate([
6fca1a34 360 'custom_group_id' => $this->ids['string']['custom_group_id'],
58eaa092
CW
361 'label' => 'Custom Multi-Select',
362 'html_type' => 'Multi-Select',
363 'option_group_id' => $selectField['option_group_id'],
9099cab3 364 ]);
58eaa092
CW
365 $selectName = 'custom_' . $selectField['id'];
366 $radioName = 'custom_' . $radioField['id'];
367 $multiSelectName = 'custom_' . $multiSelectField['id'];
6fca1a34 368 $controlFieldName = 'custom_' . $this->ids['string']['custom_field_id'];
58eaa092 369
9099cab3 370 $params = [
58eaa092
CW
371 'first_name' => 'abc4',
372 'last_name' => 'xyz4',
373 'contact_type' => 'Individual',
374 'email' => 'man4@yahoo.com',
6fca1a34 375 $selectName => $this->optionGroup['string']['values'][0],
376 $multiSelectName => $this->optionGroup['string']['values'],
377 $radioName => $this->optionGroup['string']['values'][1],
58eaa092 378 // The control group in a science experiment should be unaffected
6fca1a34 379 $controlFieldName => $this->optionGroup['string']['values'][2],
9099cab3 380 ];
58eaa092
CW
381
382 $contact = $this->callAPISuccess('Contact', 'create', $params);
383
9099cab3 384 $result = $this->callAPISuccess('Contact', 'getsingle', [
58eaa092 385 'id' => $contact['id'],
9099cab3
CW
386 'return' => [$selectName, $multiSelectName],
387 ]);
6fca1a34 388 $this->assertEquals($params[$selectName], $result[$selectName]);
389 $this->assertEquals($params[$multiSelectName], $result[$multiSelectName]);
58eaa092 390
9099cab3 391 $this->callAPISuccess('OptionValue', 'create', [
58eaa092
CW
392 'value' => 'one-modified',
393 'option_group_id' => $selectField['option_group_id'],
1453c6db 394 'label' => 'string 1',
9099cab3 395 'options' => [
1453c6db 396 'match-mandatory' => ['option_group_id', 'label'],
9099cab3
CW
397 ],
398 ]);
58eaa092 399
9099cab3 400 $result = $this->callAPISuccess('Contact', 'getsingle', [
58eaa092 401 'id' => $contact['id'],
9099cab3
CW
402 'return' => [$selectName, $multiSelectName, $controlFieldName, $radioName],
403 ]);
58eaa092
CW
404 // Ensure the relevant fields have been updated
405 $this->assertEquals('one-modified', $result[$selectName]);
9099cab3 406 $this->assertEquals(['one-modified', $params[$radioName], $params[$controlFieldName]], $result[$multiSelectName]);
58eaa092 407 // This field should not have changed because we didn't alter this option
6fca1a34 408 $this->assertEquals($params[$radioName], $result[$radioName]);
58eaa092 409 // This should not have changed because this field doesn't use the affected option group
6fca1a34 410 $this->assertEquals($params[$controlFieldName], $result[$controlFieldName]);
f36d17d2 411 // Add test of proof that multivalue fields.
9099cab3 412 $this->callAPISuccess('CustomValue', 'create', [
f36d17d2 413 'entity_id' => $contact['id'],
9099cab3
CW
414 $multiSelectName => [$params[$radioName], $params[$controlFieldName]],
415 ]);
416 $result = $this->callAPISuccess('Contact', 'getsingle', [
f36d17d2 417 'id' => $contact['id'],
9099cab3
CW
418 'return' => [$selectName, $multiSelectName, $controlFieldName, $radioName],
419 ]);
f36d17d2 420
9099cab3 421 $this->assertEquals([$params[$radioName], $params[$controlFieldName]], $result[$multiSelectName]);
58eaa092
CW
422 }
423
24871985 424 public function testGettree() {
9099cab3 425 $cg = $this->callAPISuccess('CustomGroup', 'create', [
24871985
CW
426 'title' => 'TestGettree',
427 'extends' => 'Individual',
9099cab3
CW
428 ]);
429 $cf = $this->callAPISuccess('CustomField', 'create', [
24871985
CW
430 'custom_group_id' => $cg['id'],
431 'label' => 'Got Options',
432 'name' => 'got_options',
433 "data_type" => "String",
434 "html_type" => "Multi-Select",
9099cab3
CW
435 'option_values' => ['1' => 'One', '2' => 'Two', '3' => 'Three'],
436 ]);
24871985 437 $fieldName = 'custom_' . $cf['id'];
9099cab3 438 $contact = $this->individualCreate([$fieldName => ['2', '3']]);
0b330e6d
CW
439
440 // Verify values are formatted correctly
9099cab3
CW
441 $tree = $this->callAPISuccess('CustomValue', 'gettree', ['entity_type' => 'Contact', 'entity_id' => $contact]);
442 $this->assertEquals(['2', '3'], $tree['values']['TestGettree']['fields']['got_options']['value']['data']);
24871985 443 $this->assertEquals('Two, Three', $tree['values']['TestGettree']['fields']['got_options']['value']['display']);
0b330e6d
CW
444
445 // Try limiting the return params
9099cab3 446 $tree = $this->callAPISuccess('CustomValue', 'gettree', [
0b330e6d
CW
447 'entity_type' => 'Contact',
448 'entity_id' => $contact,
9099cab3 449 'return' => [
0b330e6d
CW
450 'custom_group.id',
451 'custom_field.id',
9099cab3
CW
452 ],
453 ]);
454 $this->assertEquals(['2', '3'], $tree['values']['TestGettree']['fields']['got_options']['value']['data']);
e6446db2 455 $this->assertEquals('Two, Three', $tree['values']['TestGettree']['fields']['got_options']['value']['display']);
9099cab3 456 $this->assertEquals(['id', 'fields'], array_keys($tree['values']['TestGettree']));
0b330e6d 457
e6446db2 458 // Ensure display values are returned even if data is not
9099cab3 459 $tree = $this->callAPISuccess('CustomValue', 'gettree', [
e6446db2
CW
460 'entity_type' => 'Contact',
461 'entity_id' => $contact,
9099cab3 462 'return' => [
e6446db2 463 'custom_value.display',
9099cab3
CW
464 ],
465 ]);
e6446db2
CW
466 $this->assertEquals('Two, Three', $tree['values']['TestGettree']['fields']['got_options']['value']['display']);
467 $this->assertFalse(isset($tree['values']['TestGettree']['fields']['got_options']['value']['data']));
468
0b330e6d
CW
469 // Verify that custom set appears for individuals even who don't have any custom data
470 $contact2 = $this->individualCreate();
9099cab3 471 $tree = $this->callAPISuccess('CustomValue', 'gettree', ['entity_type' => 'Contact', 'entity_id' => $contact2]);
0b330e6d
CW
472 $this->assertArrayHasKey('TestGettree', $tree['values']);
473
474 // Verify that custom set doesn't appear for other contact types
475 $org = $this->organizationCreate();
9099cab3 476 $tree = $this->callAPISuccess('CustomValue', 'gettree', ['entity_type' => 'Contact', 'entity_id' => $org]);
0b330e6d
CW
477 $this->assertArrayNotHasKey('TestGettree', $tree['values']);
478
479 }
480
481 public function testGettree_getfields() {
9099cab3 482 $fields = $this->callAPISuccess('CustomValue', 'getfields', ['api_action' => 'gettree']);
0b330e6d
CW
483 $fields = $fields['values'];
484 $this->assertTrue((bool) $fields['entity_id']['api.required']);
485 $this->assertTrue((bool) $fields['entity_type']['api.required']);
486 $this->assertEquals('custom_group.id', $fields['custom_group.id']['name']);
487 $this->assertEquals('custom_field.id', $fields['custom_field.id']['name']);
488 $this->assertEquals('custom_value.id', $fields['custom_value.id']['name']);
24871985
CW
489 }
490
63b7d442
AS
491 /**
492 * Test that custom fields in greeting strings are updated.
493 */
d20c5e6c 494 public function testUpdateCustomGreetings(): void {
63b7d442 495 // Create a custom group with one field.
9099cab3 496 $customGroupResult = $this->callAPISuccess('CustomGroup', 'create', [
63b7d442 497 'sequential' => 1,
d20c5e6c
EM
498 'title' => 'test custom group',
499 'extends' => 'Individual',
9099cab3
CW
500 ]);
501 $customFieldResult = $this->callAPISuccess('CustomField', 'create', [
63b7d442
AS
502 'custom_group_id' => $customGroupResult['id'],
503 'label' => "greeting test",
504 'data_type' => "String",
505 'html_type' => "Text",
9099cab3 506 ]);
63b7d442
AS
507 $customFieldId = $customFieldResult['id'];
508
509 // Create a contact with an email greeting format that includes the new custom field.
9099cab3 510 $contactResult = $this->callAPISuccess('Contact', 'create', [
63b7d442 511 'contact_type' => 'Individual',
d20c5e6c
EM
512 'email' => 'her@yahoo.com',
513 'email_greeting_id' => 'Customized',
63b7d442 514 'email_greeting_custom' => "Dear {contact.custom_{$customFieldId}}",
9099cab3 515 ]);
63b7d442
AS
516 $cid = $contactResult['id'];
517
518 // Define testing values.
d20c5e6c 519 $testGreetingValue = 'Dear custom field';
63b7d442
AS
520
521 // Update contact's custom field with CustomValue.create
d20c5e6c 522 $this->callAPISuccess('CustomValue', 'create', [
63b7d442 523 'entity_id' => $cid,
d20c5e6c
EM
524 "custom_{$customFieldId}" => 'custom field',
525 'entity_table' => 'civicrm_contact',
9099cab3 526 ]);
63b7d442 527
9099cab3 528 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $cid, 'return' => 'email_greeting']);
63b7d442
AS
529 $this->assertEquals($testGreetingValue, $contact['email_greeting_display']);
530
531 }
532
5498def2
T
533 /**
534 * Creates a multi-valued custom field set and creates a contact with mutliple values for it.
535 *
536 * @return array
537 */
538 private function _testGetCustomValueMultiple() {
539 $fieldIDs = $this->CustomGroupMultipleCreateWithFields();
540 $customFieldValues = [];
541 foreach ($fieldIDs['custom_field_id'] as $id) {
542 $customFieldValues["custom_{$id}"] = "field_{$id}_value_1";
543 }
544 $this->assertNotEmpty($customFieldValues);
545 $contactParams = [
546 'first_name' => 'Jane',
547 'last_name' => 'Doe',
548 'contact_type' => 'Individual',
549 ];
550 $contact = $this->callAPISuccess('Contact', 'create', array_merge($contactParams, $customFieldValues));
551 foreach ($fieldIDs['custom_field_id'] as $id) {
552 $customFieldValues["custom_{$id}"] = "field_{$id}_value_2";
553 }
554 $result = $this->callAPISuccess('Contact', 'create', array_merge(['id' => $contact['id']], $customFieldValues));
555 return [
556 $contact['id'],
557 $customFieldValues,
558 ];
559 }
560
561 /**
562 * Test that specific custom values can be retrieved while using return with comma separated values as genererated by the api explorer.
563 * ['return' => 'custom_1,custom_2']
564 */
565 public function testGetCustomValueReturnMultipleApiExplorer() {
56fbe1df 566 [$cid, $customFieldValues] = $this->_testGetCustomValueMultiple();
5498def2
T
567 $result = $this->callAPISuccess('CustomValue', 'get', [
568 'return' => implode(',', array_keys($customFieldValues)),
569 'entity_id' => $cid,
570 ]);
571 $this->assertEquals(count($customFieldValues), $result['count']);
572 }
573
574 /**
575 * Test that specific custom values can be retrieved while using return with array style syntax.
576 * ['return => ['custom_1', 'custom_2']]
577 */
578 public function testGetCustomValueReturnMultipleArray() {
56fbe1df 579 [$cid, $customFieldValues] = $this->_testGetCustomValueMultiple();
5498def2
T
580 $result = $this->callAPISuccess('CustomValue', 'get', [
581 'return' => array_keys($customFieldValues),
582 'entity_id' => $cid,
583 ]);
584 $this->assertEquals(count($customFieldValues), $result['count']);
585 }
586
587 /**
588 * Test that specific custom values can be retrieved while using a list of return parameters.
589 * [['return.custom_1' => '1'], ['return.custom_2' => '1']]
590 */
591 public function testGetCustomValueReturnMultipleList() {
56fbe1df 592 [$cid, $customFieldValues] = $this->_testGetCustomValueMultiple();
5498def2
T
593 $returnArray = [];
594 foreach ($customFieldValues as $field => $value) {
595 $returnArray["return.{$field}"] = 1;
596 }
597 $result = $this->callAPISuccess('CustomValue', 'get', array_merge($returnArray, ['entity_id' => $cid]));
598 $this->assertEquals(count($customFieldValues), $result['count']);
599 }
600
afbd0c22
JP
601 /**
602 * Test getdisplayvalue api and verify if it returns
603 * the custom text for display.
604 */
605 public function testGetDisplayValue() {
56fbe1df 606 [$cid, $customFieldValues] = $this->_testGetCustomValueMultiple();
afbd0c22 607 foreach ($customFieldValues as $field => $value) {
56fbe1df 608 [, $customFieldID] = explode("_", $field);
afbd0c22
JP
609 $result = $this->callAPISuccess('CustomValue', 'getdisplayvalue', [
610 'entity_id' => $cid,
611 'custom_field_id' => $customFieldID,
612 ]);
613 $expectedValue = [
614 'display' => $value,
615 'raw' => $value,
616 ];
617 $this->checkArrayEquals($result['values'][$customFieldID], $expectedValue);
618
619 $customDisplayValue = $this->callAPISuccess('CustomValue', 'getdisplayvalue', [
620 'entity_id' => $cid,
621 'custom_field_id' => $customFieldID,
622 'custom_field_value' => "Test Custom Display - {$value}",
623 ]);
624 $expectedValue = [
625 'display' => "Test Custom Display - {$value}",
626 'raw' => "Test Custom Display - {$value}",
627 ];
628 $this->checkArrayEquals($customDisplayValue['values'][$customFieldID], $expectedValue);
629 }
630 }
631
ef10e0b5 632}