3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
13 * Test APIv3 civicrm_create_custom_group
18 class api_v3_CustomFieldTest
extends CiviUnitTestCase
{
21 * Clean up after test.
23 * @throws \CRM_Core_Exception
25 public function tearDown() {
29 'civicrm_entity_file',
35 * Check with no label.
37 public function testCustomFieldCreateWithoutLabel() {
38 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'text_test_group']);
40 'custom_group_id' => $customGroup['id'],
41 'name' => 'test_textfield2',
42 'html_type' => 'Text',
43 'data_type' => 'String',
44 'default_value' => 'abc',
51 $customField = $this->callAPIFailure('custom_field', 'create', $params);
52 $this->assertEquals($customField['error_message'], 'Mandatory key(s) missing from params array: label');
58 public function testCustomFieldCreateWithEdit() {
59 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'text_test_group']);
61 'custom_group_id' => $customGroup['id'],
62 'name' => 'test_textfield2',
64 'html_type' => 'Text',
65 'data_type' => 'String',
66 'default_value' => 'abc',
73 $customField = $this->callAPIAndDocument('custom_field', 'create', $params, __FUNCTION__
, __FILE__
);
74 $params['id'] = $customField['id'];
75 $customField = $this->callAPISuccess('custom_field', 'create', $params);
77 $this->assertNotNull($customField['id']);
81 * Check without groupId.
83 public function testCustomFieldCreateWithoutGroupID() {
85 'name' => 'test_textfield1',
87 'html_type' => 'Text',
88 'data_type' => 'String',
89 'default_value' => 'abc',
97 $customField = $this->callAPIFailure('custom_field', 'create', $fieldParams);
98 $this->assertEquals($customField['error_message'], 'Mandatory key(s) missing from params array: custom_group_id');
102 * Check for Each data type: loop through available form input types
104 public function testCustomFieldCreateAllAvailableFormInputs() {
105 $gid = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'testAllFormInputs']);
107 $dtype = CRM_Core_BAO_CustomField
::dataType();
108 $htype = CRM_Custom_Form_Field
::$_dataToHTML;
110 // Legacy html types returned by v3
111 foreach ($htype as &$item) {
112 if (isset($item['StateProvince'])) {
113 $item['StateProvince'] = 'Select State/Province';
115 if (isset($item['Country'])) {
116 $item['Country'] = 'Select Country';
121 foreach ($dtype as $dkey => $dvalue) {
122 foreach ($htype[$n] as $hkey => $hvalue) {
123 //echo $dkey."][".$hvalue."\n";
124 $this->_loopingCustomFieldCreateTest($this->_buildParams($gid['id'], $hvalue, $dkey));
131 * Can't figure out the point of this?
135 * @param array $params
137 public function _loopingCustomFieldCreateTest($params) {
138 $customField = $this->callAPISuccess('custom_field', 'create', $params);
139 $this->assertNotNull($customField['id']);
140 $this->getAndCheck($params, $customField['id'], 'CustomField');
150 public function _buildParams($gid, $htype, $dtype) {
151 $params = $this->_buildBasicParams($gid, $htype, $dtype);
152 /* //Not Working for any type. Maybe redundant with testCustomFieldCreateWithOptionValues()
153 if ($htype == 'Multi-Select')
154 $params = array_merge($params, array(
155 'option_label' => array( 'Label1','Label2'),
156 'option_value' => array( 'val1', 'val2' ),
157 'option_weight' => array( 1, 2),
158 'option_status' => array( 1, 1),
172 public function _buildBasicParams($gid, $htype, $dtype) {
174 'custom_group_id' => $gid,
175 'label' => $dtype . $htype,
176 'html_type' => $htype,
177 'data_type' => $dtype,
180 'is_searchable' => 0,
187 * Test using example code.
189 /*function testCustomFieldCreateExample( )
192 $customGroup = $this->customGroupCreate('Individual','date_test_group',3);
193 require_once 'api/v3/examples/CustomField/Create.ex.php';
194 $result = custom_field_create_example();
195 $expectedResult = custom_field_create_expectedresult();
196 $this->assertEquals($result,$expectedResult);
200 * Check with data type - Options with option_values
202 public function testCustomFieldCreateWithEmptyOptionGroup() {
203 $customGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'select_test_group']);
205 'custom_group_id' => $customGroup['id'],
206 'label' => 'Country',
207 'html_type' => 'Select',
208 'data_type' => 'String',
211 'is_searchable' => 0,
215 $customField = $this->callAPISuccess('custom_field', 'create', $params);
216 $this->assertNotNull($customField['id']);
217 $optionGroupID = $this->callAPISuccess('custom_field', 'getvalue', [
218 'id' => $customField['id'],
219 'return' => 'option_group_id',
222 $this->assertTrue(is_numeric($optionGroupID) && ($optionGroupID > 0));
223 $optionGroup = $this->callAPISuccess('option_group', 'getsingle', [
224 'id' => $optionGroupID,
226 $this->assertEquals($optionGroup['title'], 'Country');
227 $optionValueCount = $this->callAPISuccess('option_value', 'getcount', [
228 'option_group_id' => $optionGroupID,
230 $this->assertEquals(0, $optionValueCount);
234 * Check with non-ascii labels
236 public function testCustomFieldCreateWithNonAsciiLabel() {
237 $customGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'select_test_group']);
239 'custom_group_id' => $customGroup['id'],
240 'label' => 'ôôôô',
241 'html_type' => 'Select',
242 'data_type' => 'String',
245 'is_searchable' => 0,
248 $customField = $this->callAPISuccess('custom_field', 'create', $params);
249 $this->assertNotNull($customField['id']);
250 $params['label'] = 'Ã Ã Ã ';
251 $customField = $this->callAPISuccess('custom_field', 'create', $params);
252 $this->assertNotNull($customField['id']);
256 * Test custom field with existing option group.
258 public function testCustomFieldExistingOptionGroup() {
259 $customGroup = $this->customGroupCreate(['extends' => 'Organization', 'title' => 'test_group']);
261 'custom_group_id' => $customGroup['id'],
262 // Just to say something:
263 'label' => 'Organization Gender',
264 'html_type' => 'Select',
265 'data_type' => 'Int',
268 'is_searchable' => 0,
270 // Option group id 3: gender
271 'option_group_id' => 3,
274 $customField = $this->callAPISuccess('custom_field', 'create', $params);
275 $this->assertNotNull($customField['id']);
276 $optionGroupID = $this->callAPISuccess('custom_field', 'getvalue', [
277 'id' => $customField['id'],
278 'return' => 'option_group_id',
281 $this->assertEquals($optionGroupID, 3);
285 * Test adding an optionGroup to an existing field doesn't cause a fatal error.
287 * (this was happening due to a check running despite no existing option_group_id)
289 * @throws \CiviCRM_API3_Exception
291 public function testUpdateCustomFieldAddOptionGroup() {
292 $customGroup = $this->customGroupCreate(['extends' => 'Organization', 'title' => 'test_group']);
294 'custom_group_id' => $customGroup['id'],
295 'label' => 'Organization Gender',
296 'html_type' => 'Text',
297 'data_type' => 'Int',
300 $customField = $this->callAPISuccess('custom_field', 'create', $params);
301 $this->callAPISuccess('CustomField', 'create', [
302 'option_group_id' => civicrm_api3('OptionGroup', 'getvalue', ['options' => ['limit' => 1], 'return' => 'id']),
303 'id' => $customField['id'],
304 'html_type' => 'Select',
309 * Test custom field get works & return param works
311 public function testCustomFieldGetReturnOptions() {
312 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_group']);
313 $customField = $this->customFieldCreate(['custom_group_id' => $customGroup['id']]);
315 $result = $this->callAPISuccess('custom_field', 'getsingle', [
316 'id' => $customField['id'],
317 'return' => 'data_type',
319 $this->assertTrue(array_key_exists('data_type', $result));
320 $this->assertFalse(array_key_exists('custom_group_id', $result));
324 * Test custom field get works & return param works
326 public function testCustomFieldGetReturnArray() {
327 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_group']);
328 $customField = $this->customFieldCreate(['custom_group_id' => $customGroup['id']]);
330 $result = $this->callAPISuccess('custom_field', 'getsingle', [
331 'id' => $customField['id'],
332 'return' => ['data_type'],
334 $this->assertTrue(array_key_exists('data_type', $result));
335 $this->assertFalse(array_key_exists('custom_group_id', $result));
339 * Test custom field get works & return param works
341 public function testCustomFieldGetReturnTwoOptions() {
342 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'test_group']);
343 $customField = $this->customFieldCreate(['custom_group_id' => $customGroup['id']]);
345 $result = $this->callAPISuccess('custom_field', 'getsingle', [
346 'id' => $customField['id'],
347 'return' => 'data_type, custom_group_id',
349 $this->assertTrue(array_key_exists('data_type', $result));
350 $this->assertTrue(array_key_exists('custom_group_id', $result));
351 $this->assertFalse(array_key_exists('label', $result));
354 public function testCustomFieldCreateWithOptionValues() {
355 $customGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'select_test_group']);
373 'custom_group_id' => $customGroup['id'],
374 'label' => 'Our special field',
375 'html_type' => 'Select',
376 'data_type' => 'String',
379 'is_searchable' => 0,
381 'option_values' => $option_values,
385 $customField = $this->callAPISuccess('custom_field', 'create', $params);
387 $this->assertAPISuccess($customField);
388 $this->assertNotNull($customField['id']);
390 'options' => ['get_options' => 'custom_' . $customField['id']],
391 'action' => 'create',
393 $description = "Demonstrates retrieving metadata with custom field options.";
394 $subfile = "GetFieldsOptions";
395 $fields = $this->callAPIAndDocument('contact', 'getfields', $getFieldsParams, __FUNCTION__
, 'ContactTest.php', $description, $subfile);
396 $this->assertArrayHasKey('options', $fields['values']['custom_' . $customField['id']]);
397 $this->assertEquals('Label1', $fields['values']['custom_' . $customField['id']]['options'][1]);
399 'field' => 'custom_' . $customField['id'],
401 $description = "Demonstrates retrieving options for a custom field.";
402 $subfile = "GetOptions";
403 $result = $this->callAPIAndDocument('contact', 'getoptions', $getOptionsArray, __FUNCTION__
, 'ContactTest.php', $description, '');
404 $this->assertEquals('Label1', $result['values'][1]);
407 ///////////////// civicrm_custom_field_delete methods
410 * Check without Field ID.
412 public function testCustomFieldDeleteWithoutFieldID() {
414 $customField = $this->callAPIFailure('custom_field', 'delete', $params,
415 'Mandatory key(s) missing from params array: id');
419 * Check without valid array.
421 public function testCustomFieldDelete() {
422 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_group']);
423 $customField = $this->customFieldCreate(['custom_group_id' => $customGroup['id']]);
424 $this->assertNotNull($customField['id']);
427 'id' => $customField['id'],
429 $result = $this->callAPIAndDocument('custom_field', 'delete', $params, __FUNCTION__
, __FILE__
);
431 $this->assertAPISuccess($result);
435 * Check for Option Value.
437 public function testCustomFieldOptionValueDelete() {
438 $customGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'ABC']);
439 $customOptionValueFields = $this->customFieldOptionValueCreate($customGroup, 'fieldABC');
441 'id' => $customOptionValueFields,
444 $customField = $this->callAPISuccess('custom_field', 'delete', $customOptionValueFields);
448 * If there's one custom group for "Contact" and one for "Activity", then "Contact.getfields"
449 * and "Activity.getfields" should return only their respective fields (not the other's fields),
450 * and unrelated entities should return no custom fields.
452 public function testGetfields_CrossEntityPollution() {
453 $auxEntities = ['Email', 'Address', 'LocBlock', 'Membership', 'ContributionPage', 'ReportInstance'];
454 $allEntities = array_merge(['Contact', 'Activity'], $auxEntities);
456 // Baseline - getfields doesn't reporting any customfields for any entities
457 foreach ($allEntities as $entity) {
460 $this->getCustomFieldKeys($this->callAPISuccess($entity, 'getfields', [])),
461 "Baseline custom fields for $entity should be empty"
466 $contactGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'test_group_c']);
467 $contactField = $this->customFieldCreate([
468 'custom_group_id' => $contactGroup['id'],
469 'label' => 'For Contacts',
471 $indivGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_group_i']);
472 $indivField = $this->customFieldCreate(['custom_group_id' => $indivGroup['id'], 'label' => 'For Individuals']);
473 $activityGroup = $this->customGroupCreate(['extends' => 'Activity', 'title' => 'test_group_a']);
474 $activityField = $this->customFieldCreate([
475 'custom_group_id' => $activityGroup['id'],
476 'label' => 'For Activities',
481 ['custom_' . $contactField['id'], 'custom_' . $indivField['id']],
482 $this->getCustomFieldKeys($this->callAPISuccess('Contact', 'getfields', [])),
483 'Contact custom fields'
486 ['custom_' . $contactField['id'], 'custom_' . $indivField['id']],
487 $this->getCustomFieldKeys($this->callAPISuccess('Individual', 'getfields', [])),
488 'Individual custom fields'
491 ['custom_' . $contactField['id']],
492 $this->getCustomFieldKeys($this->callAPISuccess('Organization', 'getfields', [])),
493 'Organization custom fields'
496 ['custom_' . $activityField['id']],
497 $this->getCustomFieldKeys($this->callAPISuccess('Activity', 'getfields', [])),
498 'Activity custom fields'
500 foreach ($auxEntities as $entity) {
503 $this->getCustomFieldKeys($this->callAPISuccess($entity, 'getfields', [])),
504 "Custom fields for $entity should be empty"
510 * Test setting and getting a custom file field value.
512 * Uses the "attachment" api for setting value.
514 public function testCustomFileField() {
515 $customGroup = $this->customGroupCreate(['title' => 'attachment_test_group']);
517 'custom_group_id' => $customGroup['id'],
518 'name' => 'test_file_attachment',
519 'label' => 'test_file_attachment',
520 'html_type' => 'File',
521 'data_type' => 'File',
524 $customField = $this->callAPISuccess('custom_field', 'create', $params);
525 $cfId = 'custom_' . $customField['id'];
527 $cid = $this->individualCreate();
529 $attachment = $this->callAPISuccess('attachment', 'create', [
530 'name' => CRM_Utils_String
::createRandom(5, CRM_Utils_String
::ALPHANUMERIC
) . '_testCustomFileField.txt',
531 'mime_type' => 'text/plain',
532 'content' => 'My test content',
533 'field_name' => $cfId,
536 $this->assertAttachmentExistence(TRUE, $attachment);
538 $result = $this->callAPISuccess('contact', 'getsingle', [
543 $this->assertEquals($attachment['id'], $result[$cfId]);
546 public function testUpdateCustomField() {
547 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
548 $params = ['id' => $customGroup['id'], 'is_active' => 0];
549 $result = $this->callAPISuccess('CustomGroup', 'create', $params);
550 $result = array_shift($result['values']);
552 $this->assertEquals(0, $result['is_active']);
554 $this->customGroupDelete($customGroup['id']);
557 public function testCustomFieldCreateWithOptionGroupName() {
558 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_custom_group']);
560 'custom_group_id' => $customGroup['id'],
561 'name' => 'Activity type',
562 'label' => 'Activity type',
563 'data_type' => 'String',
564 'html_type' => 'Select',
565 'option_group_id' => 'activity_type',
567 $result = $this->callAPISuccess('CustomField', 'create', $params);
571 * @param $getFieldsResult
575 public function getCustomFieldKeys($getFieldsResult) {
576 $isCustom = function ($key) {
577 return preg_match('/^custom_/', $key);
579 $r = array_values(array_filter(array_keys($getFieldsResult['values']), $isCustom));
584 public function testMakeSearchableContactReferenceFieldUnsearchable() {
585 $customGroup = $this->customGroupCreate([
586 'name' => 'testCustomGroup',
587 'title' => 'testCustomGroup',
588 'extends' => 'Individual',
591 'name' => 'testCustomField',
592 'label' => 'testCustomField',
593 'custom_group_id' => 'testCustomGroup',
594 'data_type' => 'ContactReference',
595 'html_type' => 'Autocomplete-Select',
596 'is_searchable' => '1',
598 $result = $this->callAPISuccess('CustomField', 'create', $params);
600 'id' => $result['id'],
601 'is_searchable' => 0,
603 $result = $this->callAPISuccess('CustomField', 'create', $params);
607 * Test disabling a searchable contact reference field.
609 public function testDisableSearchableContactReferenceField() {
610 $customGroup = $this->customGroupCreate([
611 'name' => 'testCustomGroup',
612 'title' => 'testCustomGroup',
613 'extends' => 'Individual',
616 'name' => 'testCustomField',
617 'label' => 'testCustomField',
618 'custom_group_id' => 'testCustomGroup',
619 'data_type' => 'ContactReference',
620 'html_type' => 'Autocomplete-Select',
621 'is_searchable' => '1',
623 $result = $this->callAPISuccess('CustomField', 'create', $params);
625 'id' => $result['id'],
628 $this->callAPISuccess('CustomField', 'create', $params);
631 public function testLegacyHtmlType() {
632 $customGroup = $this->customGroupCreate([
633 'name' => 'testCustomGroup',
634 'title' => 'testCustomGroup',
635 'extends' => 'Individual',
637 $f1 = $this->callAPISuccess('CustomField', 'create', [
638 'label' => 'SingleSelect',
639 'custom_group_id' => 'testCustomGroup',
640 'data_type' => 'String',
641 'html_type' => 'Select',
642 'option_values' => [1 => 'One', 2 => 'Two'],
644 $f2 = $this->callAPISuccess('CustomField', 'create', [
645 'label' => 'CheckBoxes',
646 'custom_group_id' => 'testCustomGroup',
647 'data_type' => 'String',
648 'html_type' => 'CheckBox',
649 'option_values' => [1 => 'One', 2 => 'Two'],
651 $f3 = $this->callAPISuccess('CustomField', 'create', [
652 'label' => 'MultiSelect',
653 'custom_group_id' => 'testCustomGroup',
654 'data_type' => 'String',
655 'html_type' => 'Multi-Select',
656 'option_values' => [1 => 'One', 2 => 'Two'],
659 $result = $this->callAPISuccess('CustomField', 'get', [
660 'custom_group_id' => 'testCustomGroup',
661 'html_type' => 'Multi-Select',
664 $this->assertCount(1, $result['values']);
665 $this->assertEquals('MultiSelect', $result['values'][0]['label']);
667 $result = $this->callAPISuccess('CustomField', 'get', [
668 'custom_group_id' => 'testCustomGroup',
669 'html_type' => ['IN' => ['Multi-Select', 'CheckBox']],
672 $this->assertCount(2, $result['values']);
674 $result = $this->callAPISuccess('CustomField', 'get', [
675 'custom_group_id' => 'testCustomGroup',
676 'html_type' => 'Select',
679 $this->assertCount(1, $result['values']);
680 $this->assertEquals('SingleSelect', $result['values'][0]['label']);
682 $result = $this->callAPISuccess('CustomField', 'get', [
683 'custom_group_id' => 'testCustomGroup',
684 'html_type' => ['IN' => ['Select']],
687 $this->assertCount(1, $result['values']);
688 $this->assertEquals('SingleSelect', $result['values'][0]['label']);
691 public function testLegacyStateCountryTypes() {
692 $customGroup = $this->customGroupCreate([
693 'name' => 'testCustomGroup',
694 'title' => 'testCustomGroup',
695 'extends' => 'Individual',
697 $f1 = $this->callAPISuccess('CustomField', 'create', [
698 'label' => 'CountrySelect',
699 'custom_group_id' => 'testCustomGroup',
700 'data_type' => 'Country',
701 'html_type' => 'Select Country',
703 $f2 = $this->callAPISuccess('CustomField', 'create', [
704 'label' => 'StateSelect',
705 'custom_group_id' => 'testCustomGroup',
706 'data_type' => 'StateProvince',
707 'html_type' => 'Select State/Province',
709 $f3 = $this->callAPISuccess('CustomField', 'create', [
710 'label' => 'MultiSelectSP',
711 'custom_group_id' => 'testCustomGroup',
712 'data_type' => 'StateProvince',
713 'html_type' => 'Multi-Select State/Province',
715 $f4 = $this->callAPISuccess('CustomField', 'create', [
716 'label' => 'MultiSelectCountry',
717 'custom_group_id' => 'testCustomGroup',
718 'data_type' => 'Country',
719 'html_type' => 'Select Country',
723 $result = $this->callAPISuccess('CustomField', 'get', [
724 'custom_group_id' => 'testCustomGroup',
725 'html_type' => 'Multi-Select State/Province',
728 $this->assertCount(1, $result['values']);
729 $this->assertEquals('MultiSelectSP', $result['values'][0]['label']);
730 $this->assertEquals('Multi-Select State/Province', $result['values'][0]['html_type']);
731 $this->assertEquals('1', $result['values'][0]['serialize']);
733 $result = $this->callAPISuccess('CustomField', 'get', [
734 'custom_group_id' => 'testCustomGroup',
735 'html_type' => 'Multi-Select Country',
738 $this->assertCount(1, $result['values']);
739 $this->assertEquals('MultiSelectCountry', $result['values'][0]['label']);
740 $this->assertEquals('Multi-Select Country', $result['values'][0]['html_type']);
741 $this->assertEquals('1', $result['values'][0]['serialize']);
743 $result = $this->callAPISuccess('CustomField', 'get', [
744 'custom_group_id' => 'testCustomGroup',
745 'html_type' => 'Select Country',
748 $this->assertCount(1, $result['values']);
749 $this->assertEquals('CountrySelect', $result['values'][0]['label']);
750 $this->assertEquals('Select Country', $result['values'][0]['html_type']);
751 $this->assertEquals('0', $result['values'][0]['serialize']);
753 $result = $this->callAPISuccess('CustomField', 'get', [
754 'custom_group_id' => 'testCustomGroup',
755 'html_type' => 'Select State/Province',
758 $this->assertCount(1, $result['values']);
759 $this->assertEquals('StateSelect', $result['values'][0]['label']);
760 $this->assertEquals('Select State/Province', $result['values'][0]['html_type']);
761 $this->assertEquals('0', $result['values'][0]['serialize']);