Merge pull request #14922 from civicrm/5.16
[civicrm-core.git] / tests / phpunit / CRM / Core / FieldOptionsTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
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. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
26 */
27
28 /**
29 * Tests for field options
30 * @group headless
31 */
32 class CRM_Core_FieldOptionsTest extends CiviUnitTestCase {
33
34 /**
35 * @var array
36 */
37 public $replaceOptions;
38
39 /**
40 * @var array
41 */
42 public $appendOptions;
43
44 /**
45 * @var string
46 */
47 public $targetField;
48
49 public function setUp() {
50 parent::setUp();
51 CRM_Utils_Hook::singleton()->setHook('civicrm_fieldOptions', [$this, 'hook_civicrm_fieldOptions']);
52 }
53
54 public function tearDown() {
55 parent::tearDown();
56 $this->quickCleanup(['civicrm_custom_field', 'civicrm_custom_group']);
57 }
58
59 /**
60 * Assure CRM_Core_PseudoConstant::get() is working properly for a range of
61 * DAO fields having a <pseudoconstant> tag in the XML schema.
62 */
63 public function testOptionValues() {
64 /**
65 * baoName/field combinations to test
66 * Format: array[BAO Name] = $properties, where properties is an array whose
67 * named members can be:
68 * - fieldName: the SQL column name within the DAO table.
69 * - sample: Any one value which is expected in the list of option values.
70 * - context: Context to pass
71 * - props: Object properties to pass
72 * - exclude: Any one value which should not be in the list.
73 * - max: integer (default = 10) maximum number of option values expected.
74 */
75 $fields = [
76 'CRM_Core_BAO_Address' => [
77 [
78 'fieldName' => 'state_province_id',
79 'sample' => 'California',
80 'max' => 60,
81 'props' => ['country_id' => 1228],
82 ],
83 ],
84 'CRM_Contact_BAO_Contact' => [
85 [
86 'fieldName' => 'contact_sub_type',
87 'sample' => 'Team',
88 'exclude' => 'Organization',
89 'props' => ['contact_type' => 'Organization'],
90 ],
91 ],
92 ];
93
94 foreach ($fields as $baoName => $baoFields) {
95 foreach ($baoFields as $field) {
96 $message = "BAO name: '{$baoName}', field: '{$field['fieldName']}'";
97
98 $props = CRM_Utils_Array::value('props', $field, []);
99 $optionValues = $baoName::buildOptions($field['fieldName'], 'create', $props);
100 $this->assertNotEmpty($optionValues, $message);
101
102 // Ensure sample value is contained in the returned optionValues.
103 $this->assertContains($field['sample'], $optionValues, $message);
104
105 // Exclude test
106 if (!empty($field['exclude'])) {
107 $this->assertNotContains($field['exclude'], $optionValues, $message);
108 }
109
110 // Ensure count of optionValues is not extraordinarily high.
111 $max = CRM_Utils_Array::value('max', $field, 10);
112 $this->assertLessThanOrEqual($max, count($optionValues), $message);
113 }
114 }
115 }
116
117 /**
118 * Ensure hook_civicrm_fieldOptions is working
119 */
120 public function testHookFieldOptions() {
121 CRM_Core_PseudoConstant::flush();
122
123 // Test replacing all options with a hook
124 $this->targetField = 'case_type_id';
125 $this->replaceOptions = ['foo' => 'Foo', 'bar' => 'Bar'];
126 $result = $this->callAPISuccess('case', 'getoptions', ['field' => 'case_type_id']);
127 $this->assertEquals($result['values'], $this->replaceOptions);
128
129 // TargetField doesn't match - should get unmodified option list
130 $originalGender = CRM_Contact_BAO_Contact::buildOptions('gender_id');
131 $this->assertNotEquals($originalGender, $this->replaceOptions);
132
133 // This time we should get foo bar appended to the list
134 $this->targetField = 'gender_id';
135 $this->appendOptions = ['foo' => 'Foo', 'bar' => 'Bar'];
136 $this->replaceOptions = NULL;
137 CRM_Core_PseudoConstant::flush();
138 $result = CRM_Contact_BAO_Contact::buildOptions('gender_id');
139 $this->assertEquals($result, $originalGender + $this->appendOptions);
140 }
141
142 /**
143 * Ensure hook_civicrm_fieldOptions works with custom fields
144 */
145 public function testHookFieldOptionsWithCustomFields() {
146 // Create a custom field group for testing.
147 $custom_group_name = md5(microtime());
148 $api_params = [
149 'title' => $custom_group_name,
150 'extends' => 'Individual',
151 'is_active' => TRUE,
152 ];
153 $customGroup = $this->callAPISuccess('customGroup', 'create', $api_params);
154
155 // Add a custom select field.
156 $api_params = [
157 'custom_group_id' => $customGroup['id'],
158 'label' => $custom_group_name . 1,
159 'html_type' => 'Select',
160 'data_type' => 'String',
161 'option_values' => [
162 'foo' => 'Foo',
163 'bar' => 'Bar',
164 ],
165 ];
166 $result = $this->callAPISuccess('custom_field', 'create', $api_params);
167 $customField1 = $result['id'];
168
169 // Add a custom country field.
170 $api_params = [
171 'custom_group_id' => $customGroup['id'],
172 'label' => $custom_group_name . 2,
173 'html_type' => 'Select Country',
174 'data_type' => 'Country',
175 ];
176 $result = $this->callAPISuccess('custom_field', 'create', $api_params);
177 $customField2 = $result['id'];
178
179 // Add a custom boolean field.
180 $api_params = [
181 'custom_group_id' => $customGroup['id'],
182 'label' => $custom_group_name . 3,
183 'html_type' => 'Radio',
184 'data_type' => 'Boolean',
185 ];
186 $result = $this->callAPISuccess('custom_field', 'create', $api_params);
187 $customField3 = $result['id'];
188
189 $this->targetField = 'custom_' . $customField1;
190 $this->replaceOptions = NULL;
191 $this->appendOptions = ['baz' => 'Baz'];
192 $field = new CRM_Core_BAO_CustomField();
193 $field->id = $customField1;
194 $this->assertEquals(['foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'], $field->getOptions());
195
196 $this->targetField = 'custom_' . $customField2;
197 $this->replaceOptions = ['nowhere' => 'Nowhere'];
198 $field = new CRM_Core_BAO_CustomField();
199 $field->id = $customField2;
200 $this->assertEquals($this->replaceOptions + $this->appendOptions, $field->getOptions());
201
202 $this->targetField = 'custom_' . $customField3;
203 $this->replaceOptions = NULL;
204 $this->appendOptions = [2 => 'Maybe'];
205 $options = CRM_Core_PseudoConstant::get('CRM_Core_BAO_CustomField', $this->targetField);
206 $this->assertEquals([1 => 'Yes', 0 => 'No', 2 => 'Maybe'], $options);
207 }
208
209 /**
210 * Implements hook_civicrm_fieldOptions().
211 */
212 public function hook_civicrm_fieldOptions($entity, $field, &$options, $params) {
213 if ($field == $this->targetField) {
214 if (is_array($this->replaceOptions)) {
215 $options = $this->replaceOptions;
216 }
217 if ($this->appendOptions) {
218 $options += $this->appendOptions;
219 }
220 }
221 }
222
223 }