Merge pull request #21554 from eileenmcnaughton/loop
[civicrm-core.git] / tests / phpunit / CRM / Core / BAO / CustomFieldTest.php
1 <?php
2
3 use Civi\Api4\CustomField;
4
5 /**
6 * Class CRM_Core_BAO_CustomFieldTest
7 *
8 * @group headless
9 */
10 class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
11
12 use CRMTraits_Custom_CustomDataTrait;
13
14 protected $customFieldID;
15
16 /**
17 * Clean up after test.
18 */
19 public function tearDown(): void {
20 $this->quickCleanup(['civicrm_file', 'civicrm_entity_file'], TRUE);
21 parent::tearDown();
22 }
23
24 /**
25 * Test creating a custom field.
26 */
27 public function testCreateCustomField(): void {
28 $customGroup = $this->createCustomField();
29 $customFieldID = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
30 'Database check for created CustomField.'
31 );
32 $fields = [
33 'id' => $customFieldID,
34 'label' => 'editTestFld',
35 'is_active' => 1,
36 'data_type' => 'String',
37 'html_type' => 'Text',
38 'custom_group_id' => $customGroup['id'],
39 ];
40
41 CRM_Core_BAO_CustomField::create($fields);
42 $this->assertDBNotNull('CRM_Core_DAO_CustomField', 1, 'id', 'is_active', 'Database check for edited CustomField.');
43 $this->assertDBNotNull('CRM_Core_DAO_CustomField', $fields['label'], 'id', 'label', 'Database check for edited CustomField.');
44
45 $dbFieldName = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customFieldID, 'name', 'id', 'Database check for edited CustomField.');
46 $dbColumnName = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customFieldID, 'column_name', 'id', 'Database check for edited CustomField.');
47 $this->assertEquals(strtolower("{$dbFieldName}_{$customFieldID}"), $dbColumnName,
48 "Column name ends in ID");
49
50 $this->customGroupDelete($customGroup['id']);
51 }
52
53 /**
54 * Test changing a data type from multiple-choice to Text.
55 */
56 public function testChangeDataType() {
57 $customGroup = $this->createCustomField();
58 $fields = [
59 'label' => 'Radio to Text',
60 'is_active' => 1,
61 'data_type' => 'String',
62 'html_type' => 'Radio',
63 'custom_group_id' => $customGroup['id'],
64 'option_type' => 1,
65 'option_label' => ["One", "Two"],
66 'option_value' => [1, 2],
67 'option_weight' => [1, 2],
68 'option_status' => [1, 1],
69 ];
70 $customField = CRM_Core_BAO_CustomField::create($fields);
71 $this->assertNotNull($customField->option_group_id);
72 $fieldsNew = [
73 'id' => $customField->id,
74 'html_type' => 'Text',
75 'custom_group_id' => $customGroup['id'],
76 ];
77 $customFieldModified = CRM_Core_BAO_CustomField::create($fieldsNew);
78 $this->assertFalse($customFieldModified->option_group_id ?? FALSE);
79 }
80
81 /**
82 * Test custom field create accepts passed column name.
83 */
84 public function testCreateCustomFieldColumnName() {
85 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
86 $fields = [
87 'label' => 'testFld 2',
88 'column_name' => 'special_colname',
89 'data_type' => 'String',
90 'html_type' => 'Text',
91 'custom_group_id' => $customGroup['id'],
92 ];
93 CRM_Core_BAO_CustomField::create($fields);
94 $customFieldID = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
95 'Database check for created CustomField.'
96 );
97 $dbColumnName = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customFieldID, 'column_name', 'id', 'Database check for edited CustomField.');
98 $this->assertEquals($fields['column_name'], $dbColumnName,
99 "Column name set as specified");
100
101 $this->customGroupDelete($customGroup['id']);
102 }
103
104 /**
105 * Test that name is used for the column.
106 */
107 public function testCreateCustomFieldName() {
108 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
109 $fields = [
110 'label' => 'testFld 2',
111 'name' => 'special_fldlname',
112 'data_type' => 'String',
113 'html_type' => 'Text',
114 'custom_group_id' => $customGroup['id'],
115 ];
116 CRM_Core_BAO_CustomField::create($fields);
117 $customFieldID = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
118 'Database check for created CustomField.'
119 );
120 $dbFieldName = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customFieldID, 'name', 'id', 'Database check for edited CustomField.');
121 $this->assertEquals($fields['name'], $dbFieldName,
122 "Column name set as specified");
123
124 $this->customGroupDelete($customGroup['id']);
125 }
126
127 /**
128 * Test get fields function.
129 */
130 public function testGetFields() {
131 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
132 $fields = [
133 'label' => 'testFld1',
134 'data_type' => 'String',
135 'html_type' => 'Text',
136 'is_active' => 1,
137 'custom_group_id' => $customGroup['id'],
138 ];
139 CRM_Core_BAO_CustomField::create($fields);
140 $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
141 'Database check for created CustomField.'
142 );
143 $fields = [
144 'label' => 'testFld2',
145 'data_type' => 'String',
146 'html_type' => 'Text',
147 'is_active' => 1,
148 'custom_group_id' => $customGroup['id'],
149 ];
150 CRM_Core_BAO_CustomField::create($fields);
151 $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
152 'Database check for created CustomField.'
153 );
154
155 $this->customGroupDelete($customGroup['id']);
156 }
157
158 /**
159 * @throws \Exception
160 */
161 public function testGetDisplayedValues() {
162 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
163 $fieldsToCreate = [
164 [
165 'data_type' => 'Country',
166 'html_type' => 'Select',
167 'tests' => [
168 'United States' => 1228,
169 '' => NULL,
170 ],
171 ],
172 [
173 'data_type' => 'StateProvince',
174 'html_type' => 'Select',
175 'serialize' => 1,
176 'tests' => [
177 '' => 0,
178 'Alabama' => 1000,
179 'Alabama, Alaska' => [1000, 1001],
180 ],
181 ],
182 [
183 'data_type' => 'String',
184 'html_type' => 'Radio',
185 'option_values' => [
186 'key' => 'KeyLabel',
187 ],
188 'tests' => [
189 'KeyLabel' => 'key',
190 ],
191 ],
192 [
193 'data_type' => 'String',
194 'html_type' => 'CheckBox',
195 'option_values' => [
196 'key1' => 'Label1',
197 'key2' => 'Label2',
198 'key3' => 'Label3',
199 'key4' => 'Label4',
200 ],
201 'tests' => [
202 'Label1' => ['key1'],
203 'Label2' => 'key2',
204 'Label2, Label3' => ['key2', 'key3'],
205 'Label3, Label4' => CRM_Utils_Array::implodePadded(['key3', 'key4']),
206 'Label1, Label4' => ['key1' => 1, 'key4' => 1],
207 ],
208 ],
209 [
210 'data_type' => 'Date',
211 'html_type' => 'Select Date',
212 'date_format' => 'd M yy',
213 'time_format' => 1,
214 'tests' => [
215 '1 Jun 1999 1:30PM' => '1999-06-01 13:30',
216 '' => '',
217 ],
218 ],
219 [
220 'data_type' => 'Money',
221 'html_type' => 'Radio',
222 'option_values' => [
223 '10' => '10 USD',
224 '10.1' => '10.1 USD',
225 '10.99' => '10.99 USD',
226 ],
227 'tests' => [
228 '10 USD' => '10.00',
229 '10.1 USD' => '10.10',
230 '10.99 USD' => '10.99',
231 ],
232 ],
233 ];
234 foreach ($fieldsToCreate as $num => $field) {
235 $params = $field + ['label' => 'test field ' . $num, 'custom_group_id' => $customGroup['id']];
236 unset($params['tests']);
237 $createdField = $this->callAPISuccess('customField', 'create', $params);
238 foreach ($field['tests'] as $expected => $input) {
239 $this->assertEquals($expected, CRM_Core_BAO_CustomField::displayValue($input, $createdField['id']));
240 }
241 }
242
243 $this->customGroupDelete($customGroup['id']);
244 }
245
246 /**
247 * Test CRM_Core_BAO_CustomField::displayValue.
248 *
249 * @throws \CRM_Core_Exception
250 * @throws \Exception
251 */
252 public function testGetDisplayedValuesContactRef() {
253 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
254 $params = [
255 'data_type' => 'ContactReference',
256 'html_type' => 'Autocomplete-Select',
257 'label' => 'test ref',
258 'custom_group_id' => $customGroup['id'],
259 ];
260 $createdField = $this->callAPISuccess('customField', 'create', $params);
261 $contact1 = $this->individualCreate();
262 $contact2 = $this->individualCreate(['custom_' . $createdField['id'] => $contact1]);
263 $contact1Details = $this->callAPISuccess('Contact', 'getsingle', ['id' => $contact1]);
264 $this->assertEquals($contact1Details['display_name'], CRM_Core_BAO_CustomField::displayValue($contact2, $createdField['id']));
265 $this->assertEquals("Bob", CRM_Core_BAO_CustomField::displayValue("Bob", $createdField['id']));
266
267 $this->contactDelete($contact2);
268 $this->contactDelete($contact1);
269 $this->customGroupDelete($customGroup['id']);
270 }
271
272 public function testDeleteCustomField() {
273 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
274 $fields = [
275 'custom_group_id' => $customGroup['id'],
276 'label' => 'Throwaway Field',
277 'dataType' => 'Memo',
278 'htmlType' => 'TextArea',
279 ];
280
281 $customField = $this->customFieldCreate($fields);
282 $fieldObject = new CRM_Core_BAO_CustomField();
283 $fieldObject->id = $customField['id'];
284 $fieldObject->find(TRUE);
285 CRM_Core_BAO_CustomField::deleteField($fieldObject);
286 $this->assertDBNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id',
287 'custom_group_id', 'Database check for deleted Custom Field.'
288 );
289 $this->customGroupDelete($customGroup['id']);
290 }
291
292 /**
293 * Move a custom field from $groupA to $groupB.
294 *
295 * Make sure that data records are correctly matched and created.
296 *
297 * @throws \CRM_Core_Exception
298 */
299 public function testMoveField() {
300 $countriesByName = array_flip(CRM_Core_PseudoConstant::country(FALSE, FALSE));
301 $this->assertTrue($countriesByName['Andorra'] > 0);
302 $groups = [
303 'A' => $this->customGroupCreate([
304 'title' => 'Test_Group A',
305 'name' => 'test_group_a',
306 'extends' => ['Individual'],
307 'style' => 'Inline',
308 'is_multiple' => 0,
309 'is_active' => 1,
310 'version' => 3,
311 ]),
312 'B' => $this->customGroupCreate([
313 'title' => 'Test_Group B',
314 'name' => 'test_group_b',
315 'extends' => ['Individual'],
316 'style' => 'Inline',
317 'is_multiple' => 0,
318 'is_active' => 1,
319 'version' => 3,
320 ]),
321 ];
322 $groupA = $groups['A']['values'][$groups['A']['id']];
323 $groupB = $groups['B']['values'][$groups['B']['id']];
324 $countryA = $this->customFieldCreate([
325 'custom_group_id' => $groups['A']['id'],
326 'label' => 'Country A',
327 'dataType' => 'Country',
328 'htmlType' => 'Select',
329 'default_value' => NULL,
330 ]);
331 $countryB = $this->customFieldCreate([
332 'custom_group_id' => $groups['A']['id'],
333 'label' => 'Country B',
334 'dataType' => 'Country',
335 'htmlType' => 'Select',
336 'default_value' => NULL,
337 ]);
338 $countryC = $this->customFieldCreate([
339 'custom_group_id' => $groups['B']['id'],
340 'label' => 'Country C',
341 'dataType' => 'Country',
342 'htmlType' => 'Select',
343 'default_value' => NULL,
344 ]);
345
346 $fields = [
347 'countryA' => $countryA['values'][$countryA['id']],
348 'countryB' => $countryB['values'][$countryB['id']],
349 'countryC' => $countryC['values'][$countryC['id']],
350 ];
351 $contacts = [
352 'alice' => $this->individualCreate([
353 'first_name' => 'Alice',
354 'last_name' => 'Albertson',
355 'custom_' . $fields['countryA']['id'] => $countriesByName['Andorra'],
356 'custom_' . $fields['countryB']['id'] => $countriesByName['Barbados'],
357 ]),
358 'bob' => $this->individualCreate([
359 'first_name' => 'Bob',
360 'last_name' => 'Roberts',
361 'custom_' . $fields['countryA']['id'] => $countriesByName['Austria'],
362 'custom_' . $fields['countryB']['id'] => $countriesByName['Bermuda'],
363 'custom_' . $fields['countryC']['id'] => $countriesByName['Chad'],
364 ]),
365 'carol' => $this->individualCreate([
366 'first_name' => 'Carol',
367 'last_name' => 'Carolson',
368 'custom_' . $fields['countryC']['id'] => $countriesByName['Cambodia'],
369 ]),
370 ];
371
372 // Move!
373 CRM_Core_BAO_CustomField::moveField($fields['countryB']['id'], $groupB['id']);
374
375 // Group[A] no longer has fields[countryB]
376 try {
377 $this->assertDBQuery(1, "SELECT {$fields['countryB']['column_name']} FROM " . $groupA['table_name']);
378 $this->fail('Expected exception when querying column on wrong table');
379 }
380 catch (PEAR_Exception$e) {
381 }
382 $errorScope = NULL;
383
384 // Alice: Group[B] has fields[countryB], but fields[countryC] did not exist before
385 $this->assertDBQuery(1,
386 "SELECT count(*) FROM {$groupB['table_name']}
387 WHERE entity_id = %1
388 AND {$fields['countryB']['column_name']} = %3
389 AND {$fields['countryC']['column_name']} is null",
390 [
391 1 => [$contacts['alice'], 'Integer'],
392 3 => [$countriesByName['Barbados'], 'Integer'],
393 ]
394 );
395
396 // Bob: Group[B] has merged fields[countryB] and fields[countryC] on the same record
397 $this->assertDBQuery(1,
398 "SELECT count(*) FROM {$groupB['table_name']}
399 WHERE entity_id = %1
400 AND {$fields['countryB']['column_name']} = %3
401 AND {$fields['countryC']['column_name']} = %4",
402 [
403 1 => [$contacts['bob'], 'Integer'],
404 3 => [$countriesByName['Bermuda'], 'Integer'],
405 4 => [$countriesByName['Chad'], 'Integer'],
406 ]
407 );
408
409 // Carol: Group[B] still has fields[countryC] but did not get fields[countryB]
410 $this->assertDBQuery(1,
411 "SELECT count(*) FROM {$groupB['table_name']}
412 WHERE entity_id = %1
413 AND {$fields['countryB']['column_name']} is null
414 AND {$fields['countryC']['column_name']} = %4",
415 [
416 1 => [$contacts['carol'], 'Integer'],
417 4 => [$countriesByName['Cambodia'], 'Integer'],
418 ]
419 );
420
421 $this->customGroupDelete($groups['A']['id']);
422 $this->customGroupDelete($groupB['id']);
423 }
424
425 /**
426 * Test get custom field id function.
427 *
428 * @throws \CiviCRM_API3_Exception
429 */
430 public function testGetCustomFieldID() {
431 $this->createCustomField();
432 $fieldID = CRM_Core_BAO_CustomField::getCustomFieldID('testFld');
433 $this->assertEquals($this->customFieldID, $fieldID);
434
435 $fieldID = CRM_Core_BAO_CustomField::getCustomFieldID('testFld', 'new custom group');
436 $this->assertEquals($this->customFieldID, $fieldID);
437
438 $fieldID = CRM_Core_BAO_CustomField::getCustomFieldID('testFld', 'new custom group', TRUE);
439 $this->assertEquals('custom_' . $this->customFieldID, $fieldID);
440
441 // create field with same name in a different group
442 $this->createCustomField('other custom group');
443 $otherFieldID = CRM_Core_BAO_CustomField::getCustomFieldID('testFld', 'other custom group');
444 // make sure it does not return the field ID of the first field
445 $this->assertNotEquals($fieldID, $otherFieldID);
446 }
447
448 /**
449 * Create a custom field
450 *
451 * @param string $groupTitle
452 *
453 * @return array
454 */
455 protected function createCustomField($groupTitle = 'new custom group') {
456 $customGroup = $this->customGroupCreate([
457 'extends' => 'Individual',
458 'title' => $groupTitle,
459 ]);
460 $fields = [
461 'label' => 'testFld',
462 'data_type' => 'String',
463 'html_type' => 'Text',
464 'custom_group_id' => $customGroup['id'],
465 ];
466 $field = CRM_Core_BAO_CustomField::create($fields);
467 $this->customFieldID = $field->id;
468 return $customGroup;
469 }
470
471 /**
472 * Test the getFieldsForImport function.
473 *
474 * @throws \Exception
475 */
476 public function testGetFieldsForImport() {
477 $this->entity = 'Contact';
478 $this->createCustomGroupWithFieldsOfAllTypes();
479 $customGroupID = $this->ids['CustomGroup']['Custom Group'];
480 $expected = [
481 $this->getCustomFieldName('country') => [
482 'name' => $this->getCustomFieldName('country'),
483 'type' => 1,
484 'title' => 'Country',
485 'headerPattern' => '//',
486 'import' => 1,
487 'custom_field_id' => $this->getCustomFieldID('country'),
488 'options_per_line' => NULL,
489 'text_length' => NULL,
490 'data_type' => 'Country',
491 'html_type' => 'Select',
492 'is_search_range' => '0',
493 'id' => $this->getCustomFieldID('country'),
494 'label' => 'Country',
495 'groupTitle' => 'Custom Group',
496 'default_value' => NULL,
497 'custom_group_id' => $customGroupID,
498 'extends' => 'Contact',
499 'extends_entity_column_value' => NULL,
500 'extends_entity_column_id' => NULL,
501 'is_view' => '0',
502 'is_multiple' => '0',
503 'option_group_id' => NULL,
504 'date_format' => NULL,
505 'time_format' => NULL,
506 'is_required' => 0,
507 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
508 'column_name' => $this->getCustomFieldColumnName('country'),
509 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('country'),
510 'extends_table' => 'civicrm_contact',
511 'search_table' => 'contact_a',
512 'serialize' => 0,
513 'pseudoconstant' => [
514 'table' => 'civicrm_country',
515 'keyColumn' => 'id',
516 'labelColumn' => 'name',
517 'nameColumn' => 'iso_code',
518 ],
519 ],
520 $this->getCustomFieldName('multi_country') => [
521 'name' => $this->getCustomFieldName('multi_country'),
522 'type' => 1,
523 'title' => 'Country-multi',
524 'headerPattern' => '//',
525 'import' => 1,
526 'custom_field_id' => $this->getCustomFieldID('multi_country'),
527 'options_per_line' => NULL,
528 'text_length' => NULL,
529 'data_type' => 'Country',
530 'html_type' => 'Select',
531 'is_search_range' => '0',
532 'id' => $this->getCustomFieldID('multi_country'),
533 'label' => 'Country-multi',
534 'groupTitle' => 'Custom Group',
535 'default_value' => NULL,
536 'custom_group_id' => $customGroupID,
537 'extends' => 'Contact',
538 'extends_entity_column_value' => NULL,
539 'extends_entity_column_id' => NULL,
540 'is_view' => '0',
541 'is_multiple' => '0',
542 'option_group_id' => NULL,
543 'date_format' => NULL,
544 'time_format' => NULL,
545 'is_required' => 0,
546 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
547 'column_name' => $this->getCustomFieldColumnName('multi_country'),
548 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('multi_country'),
549 'extends_table' => 'civicrm_contact',
550 'search_table' => 'contact_a',
551 'serialize' => 1,
552 'pseudoconstant' => [
553 'table' => 'civicrm_country',
554 'keyColumn' => 'id',
555 'labelColumn' => 'name',
556 'nameColumn' => 'iso_code',
557 ],
558 ],
559 $this->getCustomFieldName('file') => [
560 'name' => $this->getCustomFieldName('file'),
561 'type' => 2,
562 'title' => 'My file',
563 'headerPattern' => '//',
564 'import' => 1,
565 'custom_field_id' => $this->getCustomFieldID('file'),
566 'options_per_line' => NULL,
567 'text_length' => NULL,
568 'data_type' => 'File',
569 'html_type' => 'File',
570 'is_search_range' => '0',
571 'id' => $this->getCustomFieldID('file'),
572 'label' => 'My file',
573 'groupTitle' => 'Custom Group',
574 'default_value' => NULL,
575 'custom_group_id' => $customGroupID,
576 'extends' => 'Contact',
577 'extends_entity_column_value' => NULL,
578 'extends_entity_column_id' => NULL,
579 'is_view' => '0',
580 'is_multiple' => '0',
581 'option_group_id' => NULL,
582 'date_format' => NULL,
583 'time_format' => NULL,
584 'is_required' => 0,
585 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
586 'column_name' => 'my_file_' . $this->getCustomFieldID('file'),
587 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.my_file_' . $this->getCustomFieldID('file'),
588 'extends_table' => 'civicrm_contact',
589 'search_table' => 'contact_a',
590 'serialize' => 0,
591 ],
592 $this->getCustomFieldName('text') => [
593 'name' => $this->getCustomFieldName('text'),
594 'type' => 2,
595 'title' => 'Enter text here',
596 'headerPattern' => '//',
597 'import' => 1,
598 'custom_field_id' => $this->getCustomFieldID('text'),
599 'options_per_line' => NULL,
600 'text_length' => 300,
601 'data_type' => 'String',
602 'html_type' => 'Text',
603 'is_search_range' => '0',
604 'id' => $this->getCustomFieldID('text'),
605 'label' => 'Enter text here',
606 'groupTitle' => 'Custom Group',
607 'default_value' => 'xyz',
608 'custom_group_id' => $customGroupID,
609 'extends' => 'Contact',
610 'extends_entity_column_value' => NULL,
611 'extends_entity_column_id' => NULL,
612 'is_view' => '0',
613 'is_multiple' => '0',
614 'option_group_id' => NULL,
615 'date_format' => NULL,
616 'time_format' => NULL,
617 'is_required' => 0,
618 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
619 'column_name' => 'enter_text_here_' . $this->getCustomFieldID('text'),
620 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.enter_text_here_' . $this->getCustomFieldID('text'),
621 'extends_table' => 'civicrm_contact',
622 'search_table' => 'contact_a',
623 'maxlength' => 300,
624 'serialize' => 0,
625 ],
626 $this->getCustomFieldName('select_string') => [
627 'name' => $this->getCustomFieldName('select_string'),
628 'type' => 2,
629 'title' => 'Pick Color',
630 'headerPattern' => '//',
631 'import' => 1,
632 'custom_field_id' => $this->getCustomFieldID('select_string'),
633 'options_per_line' => NULL,
634 'text_length' => NULL,
635 'data_type' => 'String',
636 'html_type' => 'Select',
637 'is_search_range' => '0',
638 'id' => $this->getCustomFieldID('select_string'),
639 'label' => 'Pick Color',
640 'groupTitle' => 'Custom Group',
641 'default_value' => NULL,
642 'custom_group_id' => $customGroupID,
643 'extends' => 'Contact',
644 'extends_entity_column_value' => NULL,
645 'extends_entity_column_id' => NULL,
646 'is_view' => '0',
647 'is_multiple' => '0',
648 'option_group_id' => $this->getOptionGroupID('select_string'),
649 'date_format' => NULL,
650 'time_format' => NULL,
651 'is_required' => 0,
652 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
653 'column_name' => 'pick_color_' . $this->getCustomFieldID('select_string'),
654 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.pick_color_' . $this->getCustomFieldID('select_string'),
655 'extends_table' => 'civicrm_contact',
656 'search_table' => 'contact_a',
657 'serialize' => 0,
658 'pseudoconstant' => [
659 'optionGroupName' => $this->callAPISuccessGetValue('CustomField', ['id' => $this->getCustomFieldID('select_string'), 'return' => 'option_group_id.name']),
660 'optionEditPath' => 'civicrm/admin/options/' . $this->callAPISuccessGetValue('CustomField', ['id' => $this->getCustomFieldID('select_string'), 'return' => 'option_group_id.name']),
661 ],
662 ],
663 $this->getCustomFieldName('select_date') => [
664 'name' => $this->getCustomFieldName('select_date'),
665 'type' => 4,
666 'title' => 'Test Date',
667 'headerPattern' => '//',
668 'import' => 1,
669 'custom_field_id' => $this->getCustomFieldID('select_date'),
670 'options_per_line' => NULL,
671 'text_length' => NULL,
672 'data_type' => 'Date',
673 'html_type' => 'Select Date',
674 'is_search_range' => '1',
675 'date_format' => 'mm/dd/yy',
676 'time_format' => '1',
677 'id' => $this->getCustomFieldID('select_date'),
678 'label' => 'Test Date',
679 'groupTitle' => 'Custom Group',
680 'default_value' => '20090711',
681 'custom_group_id' => $customGroupID,
682 'extends' => 'Contact',
683 'extends_entity_column_value' => NULL,
684 'extends_entity_column_id' => NULL,
685 'is_view' => '0',
686 'is_multiple' => '0',
687 'option_group_id' => NULL,
688 'is_required' => '0',
689 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
690 'column_name' => 'test_date_' . $this->getCustomFieldID('select_date'),
691 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.test_date_' . $this->getCustomFieldID('select_date'),
692 'extends_table' => 'civicrm_contact',
693 'search_table' => 'contact_a',
694 'serialize' => 0,
695 ],
696 $this->getCustomFieldName('link') => [
697 'name' => $this->getCustomFieldName('link'),
698 'type' => 2,
699 'title' => 'test_link',
700 'headerPattern' => '//',
701 'import' => 1,
702 'custom_field_id' => $this->getCustomFieldID('link'),
703 'options_per_line' => NULL,
704 'text_length' => NULL,
705 'data_type' => 'Link',
706 'html_type' => 'Link',
707 'is_search_range' => '0',
708 'id' => $this->getCustomFieldID('link'),
709 'label' => 'test_link',
710 'groupTitle' => 'Custom Group',
711 'default_value' => 'https://civicrm.org',
712 'custom_group_id' => $customGroupID,
713 'extends' => 'Contact',
714 'extends_entity_column_value' => NULL,
715 'extends_entity_column_id' => NULL,
716 'is_view' => '0',
717 'is_multiple' => '0',
718 'option_group_id' => NULL,
719 'date_format' => NULL,
720 'time_format' => NULL,
721 'is_required' => 0,
722 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
723 'column_name' => 'test_link_' . $this->getCustomFieldID('link'),
724 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.test_link_' . $this->getCustomFieldID('link'),
725 'extends_table' => 'civicrm_contact',
726 'search_table' => 'contact_a',
727 'serialize' => 0,
728 ],
729 $this->getCustomFieldName('int') => [
730 'name' => $this->getCustomFieldName('int'),
731 'type' => CRM_Utils_Type::T_INT,
732 'title' => 'Enter integer here',
733 'headerPattern' => '//',
734 'import' => 1,
735 'custom_field_id' => $this->getCustomFieldID('int'),
736 'options_per_line' => NULL,
737 'text_length' => NULL,
738 'data_type' => 'Int',
739 'html_type' => 'Text',
740 'is_search_range' => '1',
741 'id' => $this->getCustomFieldID('int'),
742 'label' => 'Enter integer here',
743 'groupTitle' => 'Custom Group',
744 'default_value' => '4',
745 'custom_group_id' => $customGroupID,
746 'extends' => 'Contact',
747 'extends_entity_column_value' => NULL,
748 'extends_entity_column_id' => NULL,
749 'is_view' => '0',
750 'is_multiple' => '0',
751 'option_group_id' => NULL,
752 'date_format' => NULL,
753 'time_format' => NULL,
754 'is_required' => 0,
755 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
756 'column_name' => $this->getCustomFieldColumnName('int'),
757 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('int'),
758 'extends_table' => 'civicrm_contact',
759 'search_table' => 'contact_a',
760 'serialize' => 0,
761 ],
762 $this->getCustomFieldName('contact_reference') => [
763 'name' => $this->getCustomFieldName('contact_reference'),
764 'type' => CRM_Utils_Type::T_INT,
765 'title' => 'Contact reference field',
766 'headerPattern' => '//',
767 'import' => 1,
768 'custom_field_id' => $this->getCustomFieldID('contact_reference'),
769 'options_per_line' => NULL,
770 'text_length' => NULL,
771 'data_type' => 'ContactReference',
772 'html_type' => 'Autocomplete-Select',
773 'is_search_range' => '0',
774 'id' => $this->getCustomFieldID('contact_reference'),
775 'label' => 'Contact reference field',
776 'groupTitle' => 'Custom Group',
777 'default_value' => NULL,
778 'custom_group_id' => $customGroupID,
779 'extends' => 'Contact',
780 'extends_entity_column_value' => NULL,
781 'extends_entity_column_id' => NULL,
782 'is_view' => '0',
783 'is_multiple' => '0',
784 'option_group_id' => NULL,
785 'date_format' => NULL,
786 'time_format' => NULL,
787 'is_required' => 0,
788 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
789 'column_name' => $this->getCustomFieldColumnName('contact_reference'),
790 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('contact_reference'),
791 'extends_table' => 'civicrm_contact',
792 'search_table' => 'contact_a',
793 'serialize' => 0,
794 ],
795 $this->getCustomFieldName('state') => [
796 'name' => $this->getCustomFieldName('state'),
797 'id' => $this->getCustomFieldID('state'),
798 'label' => 'State',
799 'headerPattern' => '//',
800 'title' => 'State',
801 'custom_field_id' => $this->getCustomFieldID('state'),
802 'groupTitle' => 'Custom Group',
803 'default_value' => NULL,
804 'custom_group_id' => $customGroupID,
805 'extends' => 'Contact',
806 'extends_entity_column_value' => NULL,
807 'extends_entity_column_id' => NULL,
808 'is_view' => '0',
809 'is_multiple' => '0',
810 'option_group_id' => NULL,
811 'date_format' => NULL,
812 'time_format' => NULL,
813 'is_required' => 0,
814 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
815 'column_name' => $this->getCustomFieldColumnName('state'),
816 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('state'),
817 'extends_table' => 'civicrm_contact',
818 'search_table' => 'contact_a',
819 'serialize' => 0,
820 'pseudoconstant' => [
821 'table' => 'civicrm_state_province',
822 'keyColumn' => 'id',
823 'labelColumn' => 'name',
824 ],
825 'import' => 1,
826 'data_type' => 'StateProvince',
827 'type' => 1,
828 'html_type' => 'Select',
829 'text_length' => NULL,
830 'options_per_line' => NULL,
831 'is_search_range' => '0',
832 ],
833 $this->getCustomFieldName('multi_state') => [
834 'id' => $this->getCustomFieldID('multi_state'),
835 'label' => 'State-multi',
836 'headerPattern' => '//',
837 'title' => 'State-multi',
838 'custom_field_id' => $this->getCustomFieldID('multi_state'),
839 'groupTitle' => 'Custom Group',
840 'default_value' => NULL,
841 'custom_group_id' => $customGroupID,
842 'extends' => 'Contact',
843 'extends_entity_column_value' => NULL,
844 'extends_entity_column_id' => NULL,
845 'is_view' => '0',
846 'is_multiple' => '0',
847 'option_group_id' => NULL,
848 'date_format' => NULL,
849 'time_format' => NULL,
850 'is_required' => 0,
851 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
852 'column_name' => $this->getCustomFieldColumnName('multi_state'),
853 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('multi_state'),
854 'extends_table' => 'civicrm_contact',
855 'search_table' => 'contact_a',
856 'serialize' => 1,
857 'pseudoconstant' => [
858 'table' => 'civicrm_state_province',
859 'keyColumn' => 'id',
860 'labelColumn' => 'name',
861 ],
862 'import' => 1,
863 'data_type' => 'StateProvince',
864 'name' => $this->getCustomFieldName('multi_state'),
865 'type' => 1,
866 'html_type' => 'Select',
867 'text_length' => NULL,
868 'options_per_line' => NULL,
869 'is_search_range' => '0',
870 ],
871 $this->getCustomFieldName('boolean') => [
872 'id' => $this->getCustomFieldID('boolean'),
873 'label' => 'Yes No',
874 'headerPattern' => '//',
875 'title' => 'Yes No',
876 'custom_field_id' => $this->getCustomFieldID('boolean'),
877 'groupTitle' => 'Custom Group',
878 'default_value' => NULL,
879 'custom_group_id' => $customGroupID,
880 'extends' => 'Contact',
881 'extends_entity_column_value' => NULL,
882 'extends_entity_column_id' => NULL,
883 'is_view' => '0',
884 'is_multiple' => '0',
885 'option_group_id' => NULL,
886 'date_format' => NULL,
887 'time_format' => NULL,
888 'is_required' => 0,
889 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
890 'column_name' => $this->getCustomFieldColumnName('boolean'),
891 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('boolean'),
892 'extends_table' => 'civicrm_contact',
893 'search_table' => 'contact_a',
894 'import' => 1,
895 'data_type' => 'Boolean',
896 'name' => $this->getCustomFieldName('boolean'),
897 'type' => 16,
898 'html_type' => 'Radio',
899 'text_length' => NULL,
900 'options_per_line' => NULL,
901 'is_search_range' => '0',
902 'serialize' => 0,
903 'pseudoconstant' => [
904 'callback' => 'CRM_Core_SelectValues::boolean',
905 ],
906 ],
907 $this->getCustomFieldName('checkbox') => [
908 'name' => $this->getCustomFieldName('checkbox'),
909 'custom_field_id' => $this->getCustomFieldID('checkbox'),
910 'id' => $this->getCustomFieldID('checkbox'),
911 'groupTitle' => 'Custom Group',
912 'default_value' => NULL,
913 'option_group_id' => $this->getOptionGroupID('checkbox'),
914 'custom_group_id' => $customGroupID,
915 'extends' => 'Contact',
916 'extends_entity_column_value' => NULL,
917 'extends_entity_column_id' => NULL,
918 'is_view' => '0',
919 'is_multiple' => '0',
920 'date_format' => NULL,
921 'time_format' => NULL,
922 'is_required' => 0,
923 'table_name' => 'civicrm_value_custom_group_' . $customGroupID,
924 'column_name' => $this->getCustomFieldColumnName('checkbox'),
925 'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('checkbox'),
926 'extends_table' => 'civicrm_contact',
927 'search_table' => 'contact_a',
928 'import' => 1,
929 'label' => 'Pick Shade',
930 'headerPattern' => '//',
931 'title' => 'Pick Shade',
932 'data_type' => 'String',
933 'type' => 2,
934 'html_type' => 'CheckBox',
935 'text_length' => NULL,
936 'options_per_line' => NULL,
937 'is_search_range' => '0',
938 'serialize' => '1',
939 'pseudoconstant' => [
940 'optionGroupName' => $this->getOptionGroupName('checkbox'),
941 'optionEditPath' => 'civicrm/admin/options/' . $this->getOptionGroupName('checkbox'),
942
943 ],
944 ],
945 ];
946 $this->assertEquals($expected, CRM_Core_BAO_CustomField::getFieldsForImport());
947 }
948
949 /**
950 * Test the bulk create function works.
951 */
952 public function testBulkCreate(): void {
953 $customGroup = $this->customGroupCreate([
954 'extends' => 'Individual',
955 'title' => 'my bulk group',
956 ]);
957 CustomField::save(FALSE)->setRecords([
958 [
959 'label' => 'Test',
960 'data_type' => 'String',
961 'html_type' => 'Text',
962 'column_name' => 'my_text',
963 ],
964 [
965 'label' => 'test_link',
966 'data_type' => 'Link',
967 'html_type' => 'Link',
968 'is_search_range' => '0',
969 ],
970 ])->setDefaults(
971 [
972 'custom_group_id' => $customGroup['id'],
973 'is_active' => 1,
974 'is_searchable' => 1,
975 ])->execute();
976 $dao = CRM_Core_DAO::executeQuery(('SHOW CREATE TABLE ' . $customGroup['values'][$customGroup['id']]['table_name']));
977 $dao->fetch();
978 $this->assertStringContainsString('`test_link_2` varchar(255) COLLATE ' . CRM_Core_BAO_SchemaHandler::getInUseCollation() . ' DEFAULT NULL', $dao->Create_Table);
979 $this->assertStringContainsString('KEY `INDEX_my_text` (`my_text`)', $dao->Create_Table);
980 }
981
982 /**
983 * Check that outputting the display value for a file field with No description doesn't generate error
984 */
985 public function testFileDisplayValueNoDescription(): void {
986 $customGroup = $this->customGroupCreate([
987 'extends' => 'Individual',
988 'title' => 'Test Contact File Custom Group',
989 ]);
990 $fileField = $this->customFieldCreate([
991 'custom_group_id' => $customGroup['id'],
992 'data_type' => 'File',
993 'html_type' => 'File',
994 'default_value' => '',
995 ]);
996 $filePath = Civi::paths()->getPath('[civicrm.files]/custom/test_file.txt');
997 $file = $this->callAPISuccess('File', 'create', [
998 'uri' => $filePath,
999 ]);
1000 $individual = $this->individualCreate(['custom_' . $fileField['id'] => $file['id']]);
1001 $expectedDisplayValue = CRM_Core_BAO_File::paperIconAttachment('*', $file['id'])[$file['id']];
1002 $this->assertEquals($expectedDisplayValue, CRM_Core_BAO_CustomField::displayValue($file['id'], $fileField['id']));
1003 }
1004
1005 /**
1006 * Test for hook_civicrm_alterCustomFieldDisplayValue().
1007 */
1008 public function testAlterCustomFieldDisplayValueHook() {
1009 CRM_Utils_Hook_UnitTests::singleton()->setHook('civicrm_alterCustomFieldDisplayValue', [$this, 'alterCustomFieldDisplayValue']);
1010 $customGroupId = $this->customGroupCreate([
1011 'extends' => 'Individual',
1012 'title' => 'Test Contactcustom Group',
1013 ])['id'];
1014 $fieldId = $this->customFieldCreate([
1015 'custom_group_id' => $customGroupId,
1016 'name' => 'alter_cf_field',
1017 'label' => 'Alter CF Field',
1018 ])['id'];
1019 $contactId = $this->individualCreate(['custom_' . $fieldId => 'Test']);
1020
1021 $this->assertEquals('Test', $this->callAPISuccessGetValue('Contact',
1022 ['id' => $contactId, 'return' => "custom_{$fieldId}"]
1023 ));
1024
1025 $values = [];
1026 $fields = [
1027 'custom_' . $fieldId => $this->callAPISuccess('Contact', 'getfield', [
1028 'name' => 'custom_' . $fieldId,
1029 'action' => 'get',
1030 ])['values'],
1031 ];
1032
1033 // CRM_Core_BAO_UFGroup::getValues() invokes CRM_Core_BAO_CustomField::displayValue() function.
1034 CRM_Core_BAO_UFGroup::getValues($contactId, $fields, $values);
1035 $this->assertEquals('New value', $values['Alter CF Field']);
1036 }
1037
1038 /**
1039 * @param string $displayValue
1040 * @param mixed $value
1041 * @param int $entityId
1042 * @param array $fieldInfo
1043 *
1044 */
1045 public function alterCustomFieldDisplayValue(&$displayValue, $value, $entityId, $fieldInfo) {
1046 if ($fieldInfo['name'] == 'alter_cf_field') {
1047 $displayValue = 'New value';
1048 }
1049 }
1050
1051 /**
1052 * Test for single select Autocomplete custom field.
1053 *
1054 */
1055 public function testSingleSelectAutoComplete() {
1056 $customGroupId = $this->customGroupCreate([
1057 'extends' => 'Individual',
1058 ])['id'];
1059 $colors = ['Y' => 'Yellow', 'G' => 'Green'];
1060 $fieldId = $this->createAutoCompleteCustomField([
1061 'custom_group_id' => $customGroupId,
1062 'option_values' => $colors,
1063 ])['id'];
1064 $contactId = $this->individualCreate(['custom_' . $fieldId => 'Y']);
1065 $value = $this->callAPISuccessGetValue('Contact', [
1066 'id' => $contactId,
1067 'return' => 'custom_' . $fieldId,
1068 ]);
1069 $this->assertEquals('Y', $value);
1070 }
1071
1072 /**
1073 * Test for multi select Autocomplete custom field.
1074 *
1075 */
1076 public function testMultiSelectAutoComplete() {
1077 $customGroupId = $this->customGroupCreate([
1078 'extends' => 'Individual',
1079 ])['id'];
1080 $colors = ['Y' => 'Yellow', 'G' => 'Green'];
1081 $fieldId = $this->createAutoCompleteCustomField([
1082 'custom_group_id' => $customGroupId,
1083 'serialize' => '1',
1084 'option_values' => $colors,
1085 ])['id'];
1086 $contactId = $this->individualCreate(['custom_' . $fieldId => ['Y', 'G']]);
1087 $value = $this->callAPISuccessGetValue('Contact', [
1088 'id' => $contactId,
1089 'return' => 'custom_' . $fieldId,
1090 ]);
1091 $this->assertEquals(array_keys($colors), $value);
1092 }
1093
1094 }