3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 * Test APIv3 civicrm_create_custom_group
34 class api_v3_CustomFieldTest
extends CiviUnitTestCase
{
37 * Clean up after test.
39 * @throws \CRM_Core_Exception
41 public function tearDown() {
45 'civicrm_entity_file',
51 * Check with no array.
53 public function testCustomFieldCreateNoArray() {
56 $customField = $this->callAPIFailure('custom_field', 'create', $fieldParams);
57 $this->assertEquals($customField['error_message'], 'Input variable `params` is not an array');
61 * Check with no label.
63 public function testCustomFieldCreateWithoutLabel() {
64 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'text_test_group']);
66 'custom_group_id' => $customGroup['id'],
67 'name' => 'test_textfield2',
68 'html_type' => 'Text',
69 'data_type' => 'String',
70 'default_value' => 'abc',
77 $customField = $this->callAPIFailure('custom_field', 'create', $params);
78 $this->assertEquals($customField['error_message'], 'Mandatory key(s) missing from params array: label');
84 public function testCustomFieldCreateWithEdit() {
85 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'text_test_group']);
87 'custom_group_id' => $customGroup['id'],
88 'name' => 'test_textfield2',
90 'html_type' => 'Text',
91 'data_type' => 'String',
92 'default_value' => 'abc',
99 $customField = $this->callAPIAndDocument('custom_field', 'create', $params, __FUNCTION__
, __FILE__
);
100 $params['id'] = $customField['id'];
101 $customField = $this->callAPISuccess('custom_field', 'create', $params);
103 $this->assertNotNull($customField['id']);
107 * Check without groupId.
109 public function testCustomFieldCreateWithoutGroupID() {
111 'name' => 'test_textfield1',
113 'html_type' => 'Text',
114 'data_type' => 'String',
115 'default_value' => 'abc',
118 'is_searchable' => 0,
123 $customField = $this->callAPIFailure('custom_field', 'create', $fieldParams);
124 $this->assertEquals($customField['error_message'], 'Mandatory key(s) missing from params array: custom_group_id');
128 * Check for Each data type: loop through available form input types
130 public function testCustomFieldCreateAllAvailableFormInputs() {
131 $gid = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'testAllFormInputs']);
133 $dtype = CRM_Core_BAO_CustomField
::dataType();
134 $htype = CRM_Core_BAO_CustomField
::dataToHtml();
137 foreach ($dtype as $dkey => $dvalue) {
138 foreach ($htype[$n] as $hkey => $hvalue) {
139 //echo $dkey."][".$hvalue."\n";
140 $this->_loopingCustomFieldCreateTest($this->_buildParams($gid['id'], $hvalue, $dkey));
147 * Can't figure out the point of this?
151 * @param array $params
153 public function _loopingCustomFieldCreateTest($params) {
154 $customField = $this->callAPISuccess('custom_field', 'create', $params);
155 $this->assertNotNull($customField['id']);
156 $this->getAndCheck($params, $customField['id'], 'CustomField');
166 public function _buildParams($gid, $htype, $dtype) {
167 $params = $this->_buildBasicParams($gid, $htype, $dtype);
168 /* //Not Working for any type. Maybe redundant with testCustomFieldCreateWithOptionValues()
169 if ($htype == 'Multi-Select')
170 $params = array_merge($params, array(
171 'option_label' => array( 'Label1','Label2'),
172 'option_value' => array( 'val1', 'val2' ),
173 'option_weight' => array( 1, 2),
174 'option_status' => array( 1, 1),
188 public function _buildBasicParams($gid, $htype, $dtype) {
190 'custom_group_id' => $gid,
191 'label' => $dtype . $htype,
192 'html_type' => $htype,
193 'data_type' => $dtype,
196 'is_searchable' => 0,
203 * Test using example code.
205 /*function testCustomFieldCreateExample( )
208 $customGroup = $this->customGroupCreate('Individual','date_test_group',3);
209 require_once 'api/v3/examples/CustomField/Create.php';
210 $result = custom_field_create_example();
211 $expectedResult = custom_field_create_expectedresult();
212 $this->assertEquals($result,$expectedResult);
216 * Check with data type - Options with option_values
218 public function testCustomFieldCreateWithEmptyOptionGroup() {
219 $customGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'select_test_group']);
221 'custom_group_id' => $customGroup['id'],
222 'label' => 'Country',
223 'html_type' => 'Select',
224 'data_type' => 'String',
227 'is_searchable' => 0,
231 $customField = $this->callAPISuccess('custom_field', 'create', $params);
232 $this->assertNotNull($customField['id']);
233 $optionGroupID = $this->callAPISuccess('custom_field', 'getvalue', [
234 'id' => $customField['id'],
235 'return' => 'option_group_id',
238 $this->assertTrue(is_numeric($optionGroupID) && ($optionGroupID > 0));
239 $optionGroup = $this->callAPISuccess('option_group', 'getsingle', [
240 'id' => $optionGroupID,
242 $this->assertEquals($optionGroup['title'], 'Country');
243 $optionValueCount = $this->callAPISuccess('option_value', 'getcount', [
244 'option_group_id' => $optionGroupID,
246 $this->assertEquals(0, $optionValueCount);
250 * Check with non-ascii labels
252 public function testCustomFieldCreateWithNonAsciiLabel() {
253 $customGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'select_test_group']);
255 'custom_group_id' => $customGroup['id'],
256 'label' => 'ôôôô',
257 'html_type' => 'Select',
258 'data_type' => 'String',
261 'is_searchable' => 0,
264 $customField = $this->callAPISuccess('custom_field', 'create', $params);
265 $this->assertNotNull($customField['id']);
266 $params['label'] = 'Ã Ã Ã ';
267 $customField = $this->callAPISuccess('custom_field', 'create', $params);
268 $this->assertNotNull($customField['id']);
272 * Test custom field with existing option group.
274 public function testCustomFieldExistingOptionGroup() {
275 $customGroup = $this->customGroupCreate(['extends' => 'Organization', 'title' => 'test_group']);
277 'custom_group_id' => $customGroup['id'],
278 // Just to say something:
279 'label' => 'Organization Gender',
280 'html_type' => 'Select',
281 'data_type' => 'Int',
284 'is_searchable' => 0,
286 // Option group id 3: gender
287 'option_group_id' => 3,
290 $customField = $this->callAPISuccess('custom_field', 'create', $params);
291 $this->assertNotNull($customField['id']);
292 $optionGroupID = $this->callAPISuccess('custom_field', 'getvalue', [
293 'id' => $customField['id'],
294 'return' => 'option_group_id',
297 $this->assertEquals($optionGroupID, 3);
301 * Test adding an optionGroup to an existing field doesn't cause a fatal error.
303 * (this was happening due to a check running despite no existing option_group_id)
305 * @throws \CiviCRM_API3_Exception
307 public function testUpdateCustomFieldAddOptionGroup() {
308 $customGroup = $this->customGroupCreate(['extends' => 'Organization', 'title' => 'test_group']);
310 'custom_group_id' => $customGroup['id'],
311 'label' => 'Organization Gender',
312 'html_type' => 'Text',
313 'data_type' => 'Int',
316 $customField = $this->callAPISuccess('custom_field', 'create', $params);
317 $this->callAPISuccess('CustomField', 'create', [
318 'option_group_id' => civicrm_api3('OptionGroup', 'getvalue', ['options' => ['limit' => 1], 'return' => 'id']),
319 'id' => $customField['id'],
320 'html_type' => 'Select',
325 * Test custom field get works & return param works
327 public function testCustomFieldGetReturnOptions() {
328 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_group']);
329 $customField = $this->customFieldCreate(['custom_group_id' => $customGroup['id']]);
331 $result = $this->callAPISuccess('custom_field', 'getsingle', [
332 'id' => $customField['id'],
333 'return' => 'data_type',
335 $this->assertTrue(array_key_exists('data_type', $result));
336 $this->assertFalse(array_key_exists('custom_group_id', $result));
340 * Test custom field get works & return param works
342 public function testCustomFieldGetReturnArray() {
343 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_group']);
344 $customField = $this->customFieldCreate(['custom_group_id' => $customGroup['id']]);
346 $result = $this->callAPISuccess('custom_field', 'getsingle', [
347 'id' => $customField['id'],
348 'return' => ['data_type'],
350 $this->assertTrue(array_key_exists('data_type', $result));
351 $this->assertFalse(array_key_exists('custom_group_id', $result));
355 * Test custom field get works & return param works
357 public function testCustomFieldGetReturnTwoOptions() {
358 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'test_group']);
359 $customField = $this->customFieldCreate(['custom_group_id' => $customGroup['id']]);
361 $result = $this->callAPISuccess('custom_field', 'getsingle', [
362 'id' => $customField['id'],
363 'return' => 'data_type, custom_group_id',
365 $this->assertTrue(array_key_exists('data_type', $result));
366 $this->assertTrue(array_key_exists('custom_group_id', $result));
367 $this->assertFalse(array_key_exists('label', $result));
370 public function testCustomFieldCreateWithOptionValues() {
371 $customGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'select_test_group']);
389 'custom_group_id' => $customGroup['id'],
390 'label' => 'Our special field',
391 'html_type' => 'Select',
392 'data_type' => 'String',
395 'is_searchable' => 0,
397 'option_values' => $option_values,
401 $customField = $this->callAPISuccess('custom_field', 'create', $params);
403 $this->assertAPISuccess($customField);
404 $this->assertNotNull($customField['id']);
406 'options' => ['get_options' => 'custom_' . $customField['id']],
407 'action' => 'create',
409 $description = "Demonstrates retrieving metadata with custom field options.";
410 $subfile = "GetFieldsOptions";
411 $fields = $this->callAPIAndDocument('contact', 'getfields', $getFieldsParams, __FUNCTION__
, 'ContactTest.php', $description, $subfile);
412 $this->assertArrayHasKey('options', $fields['values']['custom_' . $customField['id']]);
413 $this->assertEquals('Label1', $fields['values']['custom_' . $customField['id']]['options'][1]);
415 'field' => 'custom_' . $customField['id'],
417 $description = "Demonstrates retrieving options for a custom field.";
418 $subfile = "GetOptions";
419 $result = $this->callAPIAndDocument('contact', 'getoptions', $getOptionsArray, __FUNCTION__
, 'ContactTest.php', $description, '');
420 $this->assertEquals('Label1', $result['values'][1]);
423 ///////////////// civicrm_custom_field_delete methods
426 * Check with no array.
428 public function testCustomFieldDeleteNoArray() {
430 $customField = $this->callAPIFailure('custom_field', 'delete', $params);
431 $this->assertEquals($customField['error_message'], 'Input variable `params` is not an array');
435 * Check without Field ID.
437 public function testCustomFieldDeleteWithoutFieldID() {
439 $customField = $this->callAPIFailure('custom_field', 'delete', $params,
440 'Mandatory key(s) missing from params array: id');
444 * Check without valid array.
446 public function testCustomFieldDelete() {
447 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_group']);
448 $customField = $this->customFieldCreate(['custom_group_id' => $customGroup['id']]);
449 $this->assertNotNull($customField['id']);
452 'id' => $customField['id'],
454 $result = $this->callAPIAndDocument('custom_field', 'delete', $params, __FUNCTION__
, __FILE__
);
456 $this->assertAPISuccess($result);
460 * Check for Option Value.
462 public function testCustomFieldOptionValueDelete() {
463 $customGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'ABC']);
464 $customOptionValueFields = $this->customFieldOptionValueCreate($customGroup, 'fieldABC');
466 'id' => $customOptionValueFields,
469 $customField = $this->callAPISuccess('custom_field', 'delete', $customOptionValueFields);
473 * If there's one custom group for "Contact" and one for "Activity", then "Contact.getfields"
474 * and "Activity.getfields" should return only their respective fields (not the other's fields),
475 * and unrelated entities should return no custom fields.
477 public function testGetfields_CrossEntityPollution() {
478 $auxEntities = ['Email', 'Address', 'LocBlock', 'Membership', 'ContributionPage', 'ReportInstance'];
479 $allEntities = array_merge(['Contact', 'Activity'], $auxEntities);
481 // Baseline - getfields doesn't reporting any customfields for any entities
482 foreach ($allEntities as $entity) {
485 $this->getCustomFieldKeys($this->callAPISuccess($entity, 'getfields', [])),
486 "Baseline custom fields for $entity should be empty"
491 $contactGroup = $this->customGroupCreate(['extends' => 'Contact', 'title' => 'test_group_c']);
492 $contactField = $this->customFieldCreate([
493 'custom_group_id' => $contactGroup['id'],
494 'label' => 'For Contacts',
496 $indivGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_group_i']);
497 $indivField = $this->customFieldCreate(['custom_group_id' => $indivGroup['id'], 'label' => 'For Individuals']);
498 $activityGroup = $this->customGroupCreate(['extends' => 'Activity', 'title' => 'test_group_a']);
499 $activityField = $this->customFieldCreate([
500 'custom_group_id' => $activityGroup['id'],
501 'label' => 'For Activities',
506 ['custom_' . $contactField['id'], 'custom_' . $indivField['id']],
507 $this->getCustomFieldKeys($this->callAPISuccess('Contact', 'getfields', [])),
508 'Contact custom fields'
511 ['custom_' . $contactField['id'], 'custom_' . $indivField['id']],
512 $this->getCustomFieldKeys($this->callAPISuccess('Individual', 'getfields', [])),
513 'Individual custom fields'
516 ['custom_' . $contactField['id']],
517 $this->getCustomFieldKeys($this->callAPISuccess('Organization', 'getfields', [])),
518 'Organization custom fields'
521 ['custom_' . $activityField['id']],
522 $this->getCustomFieldKeys($this->callAPISuccess('Activity', 'getfields', [])),
523 'Activity custom fields'
525 foreach ($auxEntities as $entity) {
528 $this->getCustomFieldKeys($this->callAPISuccess($entity, 'getfields', [])),
529 "Custom fields for $entity should be empty"
535 * Test setting and getting a custom file field value.
537 * Uses the "attachment" api for setting value.
539 public function testCustomFileField() {
540 $customGroup = $this->customGroupCreate(['title' => 'attachment_test_group']);
542 'custom_group_id' => $customGroup['id'],
543 'name' => 'test_file_attachment',
544 'label' => 'test_file_attachment',
545 'html_type' => 'File',
546 'data_type' => 'File',
549 $customField = $this->callAPISuccess('custom_field', 'create', $params);
550 $cfId = 'custom_' . $customField['id'];
552 $cid = $this->individualCreate();
554 $attachment = $this->callAPISuccess('attachment', 'create', [
555 'name' => CRM_Utils_String
::createRandom(5, CRM_Utils_String
::ALPHANUMERIC
) . '_testCustomFileField.txt',
556 'mime_type' => 'text/plain',
557 'content' => 'My test content',
558 'field_name' => $cfId,
561 $this->assertAttachmentExistence(TRUE, $attachment);
563 $result = $this->callAPISuccess('contact', 'getsingle', [
568 $this->assertEquals($attachment['id'], $result[$cfId]);
571 public function testUpdateCustomField() {
572 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
573 $params = ['id' => $customGroup['id'], 'is_active' => 0];
574 $result = $this->callAPISuccess('CustomGroup', 'create', $params);
575 $result = array_shift($result['values']);
577 $this->assertEquals(0, $result['is_active']);
579 $this->customGroupDelete($customGroup['id']);
582 public function testCustomFieldCreateWithOptionGroupName() {
583 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'test_custom_group']);
585 'custom_group_id' => $customGroup['id'],
586 'name' => 'Activity type',
587 'label' => 'Activity type',
588 'data_type' => 'String',
589 'html_type' => 'Select',
590 'option_group_id' => 'activity_type',
592 $result = $this->callAPISuccess('CustomField', 'create', $params);
596 * @param $getFieldsResult
600 public function getCustomFieldKeys($getFieldsResult) {
601 $isCustom = function ($key) {
602 return preg_match('/^custom_/', $key);
604 $r = array_values(array_filter(array_keys($getFieldsResult['values']), $isCustom));
609 public function testMakeSearchableContactReferenceFieldUnsearchable() {
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'],
626 'is_searchable' => 0,
628 $result = $this->callAPISuccess('CustomField', 'create', $params);
632 * Test disabling a searchable contact reference field.
634 public function testDisableSearchableContactReferenceField() {
635 $customGroup = $this->customGroupCreate([
636 'name' => 'testCustomGroup',
637 'title' => 'testCustomGroup',
638 'extends' => 'Individual',
641 'name' => 'testCustomField',
642 'label' => 'testCustomField',
643 'custom_group_id' => 'testCustomGroup',
644 'data_type' => 'ContactReference',
645 'html_type' => 'Autocomplete-Select',
646 'is_searchable' => '1',
648 $result = $this->callAPISuccess('CustomField', 'create', $params);
650 'id' => $result['id'],
653 $this->callAPISuccess('CustomField', 'create', $params);