dev/core#389 [preliminary cleanup] Standardise metadat for custom field use
[civicrm-core.git] / tests / phpunit / CRM / Core / BAO / CustomFieldTest.php
1 <?php
2
3 /**
4 * Class CRM_Core_BAO_CustomFieldTest
5 *
6 * @group headless
7 */
8 class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
9
10 use CRMTraits_Custom_CustomDataTrait;
11
12 protected $customFieldID;
13
14 public function setUp() {
15 parent::setUp();
16 }
17
18 public function testCreateCustomField() {
19 $customGroup = $this->createCustomField();
20 $customFieldID = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
21 'Database check for created CustomField.'
22 );
23 $fields = [
24 'id' => $customFieldID,
25 'label' => 'editTestFld',
26 'is_active' => 1,
27 'data_type' => 'String',
28 'html_type' => 'Text',
29 'custom_group_id' => $customGroup['id'],
30 ];
31
32 CRM_Core_BAO_CustomField::create($fields);
33 $this->assertDBNotNull('CRM_Core_DAO_CustomField', 1, 'id', 'is_active', 'Database check for edited CustomField.');
34 $this->assertDBNotNull('CRM_Core_DAO_CustomField', $fields['label'], 'id', 'label', 'Database check for edited CustomField.');
35
36 $dbFieldName = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customFieldID, 'name', 'id', 'Database check for edited CustomField.');
37 $dbColumnName = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customFieldID, 'column_name', 'id', 'Database check for edited CustomField.');
38 $this->assertEquals(strtolower("{$dbFieldName}_{$customFieldID}"), $dbColumnName,
39 "Column name ends in ID");
40
41 $this->customGroupDelete($customGroup['id']);
42 }
43
44 public function testCreateCustomFieldColumnName() {
45 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
46 $fields = [
47 'label' => 'testFld 2',
48 'column_name' => 'special_colname',
49 'data_type' => 'String',
50 'html_type' => 'Text',
51 'custom_group_id' => $customGroup['id'],
52 ];
53 CRM_Core_BAO_CustomField::create($fields);
54 $customFieldID = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
55 'Database check for created CustomField.'
56 );
57 $dbColumnName = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customFieldID, 'column_name', 'id', 'Database check for edited CustomField.');
58 $this->assertEquals($fields['column_name'], $dbColumnName,
59 "Column name set as specified");
60
61 $this->customGroupDelete($customGroup['id']);
62 }
63
64 public function testCreateCustomFieldName() {
65 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
66 $fields = [
67 'label' => 'testFld 2',
68 'name' => 'special_fldlname',
69 'data_type' => 'String',
70 'html_type' => 'Text',
71 'custom_group_id' => $customGroup['id'],
72 ];
73 CRM_Core_BAO_CustomField::create($fields);
74 $customFieldID = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
75 'Database check for created CustomField.'
76 );
77 $dbFieldName = $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customFieldID, 'name', 'id', 'Database check for edited CustomField.');
78 $this->assertEquals($fields['name'], $dbFieldName,
79 "Column name set as specified");
80
81 $this->customGroupDelete($customGroup['id']);
82 }
83
84 public function testGetFields() {
85 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
86 $fields = [
87 'label' => 'testFld1',
88 'data_type' => 'String',
89 'html_type' => 'Text',
90 'is_active' => 1,
91 'custom_group_id' => $customGroup['id'],
92 ];
93 CRM_Core_BAO_CustomField::create($fields);
94 $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
95 'Database check for created CustomField.'
96 );
97 $fields = [
98 'label' => 'testFld2',
99 'data_type' => 'String',
100 'html_type' => 'Text',
101 'is_active' => 1,
102 'custom_group_id' => $customGroup['id'],
103 ];
104 CRM_Core_BAO_CustomField::create($fields);
105 $this->assertDBNotNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id', 'custom_group_id',
106 'Database check for created CustomField.'
107 );
108
109 $this->customGroupDelete($customGroup['id']);
110 }
111
112 public function testGetDisplayedValues() {
113 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
114 $fieldsToCreate = [
115 [
116 'data_type' => 'Country',
117 'html_type' => 'Select Country',
118 'tests' => [
119 'United States' => 1228,
120 '' => NULL,
121 ],
122 ],
123 [
124 'data_type' => 'StateProvince',
125 'html_type' => 'Multi-Select State/Province',
126 'tests' => [
127 '' => 0,
128 'Alabama' => 1000,
129 'Alabama, Alaska' => [1000, 1001],
130 ],
131 ],
132 [
133 'data_type' => 'String',
134 'html_type' => 'Radio',
135 'option_values' => [
136 'key' => 'KeyLabel',
137 ],
138 'tests' => [
139 'KeyLabel' => 'key',
140 ],
141 ],
142 [
143 'data_type' => 'String',
144 'html_type' => 'CheckBox',
145 'option_values' => [
146 'key1' => 'Label1',
147 'key2' => 'Label2',
148 'key3' => 'Label3',
149 'key4' => 'Label4',
150 ],
151 'tests' => [
152 'Label1' => ['key1'],
153 'Label2' => 'key2',
154 'Label2, Label3' => ['key2', 'key3'],
155 'Label3, Label4' => CRM_Utils_Array::implodePadded(['key3', 'key4']),
156 'Label1, Label4' => ['key1' => 1, 'key4' => 1],
157 ],
158 ],
159 [
160 'data_type' => 'Date',
161 'html_type' => 'Select Date',
162 'date_format' => 'd M yy',
163 'time_format' => 1,
164 'tests' => [
165 '1 Jun 1999 1:30PM' => '1999-06-01 13:30',
166 '' => '',
167 ],
168 ],
169 ];
170 foreach ($fieldsToCreate as $num => $field) {
171 $params = $field + [
172 'label' => 'test field ' . $num,
173 'custom_group_id' => $customGroup['id'],
174 ];
175 unset($params['tests']);
176 $createdField = $this->callAPISuccess('customField', 'create', $params);
177 foreach ($field['tests'] as $expected => $input) {
178 $this->assertEquals($expected, CRM_Core_BAO_CustomField::displayValue($input, $createdField['id']));
179 }
180 }
181
182 $this->customGroupDelete($customGroup['id']);
183 }
184
185 public function testGetDisplayedValuesContactRef() {
186 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
187 $params = [
188 'data_type' => 'ContactReference',
189 'html_type' => 'Autocomplete-Select',
190 'label' => 'test ref',
191 'custom_group_id' => $customGroup['id'],
192 ];
193 $createdField = $this->callAPISuccess('customField', 'create', $params);
194 $contact1 = $this->individualCreate();
195 $contact2 = $this->individualCreate(['custom_' . $createdField['id'] => $contact1['id']]);
196
197 $this->assertEquals($contact1['display_name'], CRM_Core_BAO_CustomField::displayValue($contact2['id'], $createdField['id']));
198 $this->assertEquals("Bob", CRM_Core_BAO_CustomField::displayValue("Bob", $createdField['id']));
199
200 $this->contactDelete($contact2['id']);
201 $this->contactDelete($contact1['id']);
202 $this->customGroupDelete($customGroup['id']);
203 }
204
205 public function testDeleteCustomField() {
206 $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
207 $fields = [
208 'custom_group_id' => $customGroup['id'],
209 'label' => 'Throwaway Field',
210 'dataType' => 'Memo',
211 'htmlType' => 'TextArea',
212 ];
213
214 $customField = $this->customFieldCreate($fields);
215 $fieldObject = new CRM_Core_BAO_CustomField();
216 $fieldObject->id = $customField['id'];
217 $fieldObject->find(TRUE);
218 CRM_Core_BAO_CustomField::deleteField($fieldObject);
219 $this->assertDBNull('CRM_Core_DAO_CustomField', $customGroup['id'], 'id',
220 'custom_group_id', 'Database check for deleted Custom Field.'
221 );
222 $this->customGroupDelete($customGroup['id']);
223 }
224
225 /**
226 * Move a custom field from $groupA to $groupB.
227 *
228 * Make sure that data records are correctly matched and created.
229 */
230 public function testMoveField() {
231 $countriesByName = array_flip(CRM_Core_PseudoConstant::country(FALSE, FALSE));
232 $this->assertTrue($countriesByName['Andorra'] > 0);
233 $groups = [
234 'A' => $this->customGroupCreate([
235 'title' => 'Test_Group A',
236 'name' => 'test_group_a',
237 'extends' => ['Individual'],
238 'style' => 'Inline',
239 'is_multiple' => 0,
240 'is_active' => 1,
241 'version' => 3,
242 ]),
243 'B' => $this->customGroupCreate([
244 'title' => 'Test_Group B',
245 'name' => 'test_group_b',
246 'extends' => ['Individual'],
247 'style' => 'Inline',
248 'is_multiple' => 0,
249 'is_active' => 1,
250 'version' => 3,
251 ]),
252 ];
253 $groupA = $groups['A']['values'][$groups['A']['id']];
254 $groupB = $groups['B']['values'][$groups['B']['id']];
255 $countryA = $this->customFieldCreate([
256 'custom_group_id' => $groups['A']['id'],
257 'label' => 'Country A',
258 'dataType' => 'Country',
259 'htmlType' => 'Select Country',
260 'default_value' => NULL,
261 ]);
262 $countryB = $this->customFieldCreate([
263 'custom_group_id' => $groups['A']['id'],
264 'label' => 'Country B',
265 'dataType' => 'Country',
266 'htmlType' => 'Select Country',
267 'default_value' => NULL,
268 ]);
269 $countryC = $this->customFieldCreate([
270 'custom_group_id' => $groups['B']['id'],
271 'label' => 'Country C',
272 'dataType' => 'Country',
273 'htmlType' => 'Select Country',
274 'default_value' => NULL,
275 ]);
276
277 $fields = [
278 'countryA' => $countryA['values'][$countryA['id']],
279 'countryB' => $countryB['values'][$countryB['id']],
280 'countryC' => $countryC['values'][$countryC['id']],
281 ];
282 $contacts = [
283 'alice' => $this->individualCreate([
284 'first_name' => 'Alice',
285 'last_name' => 'Albertson',
286 'custom_' . $fields['countryA']['id'] => $countriesByName['Andorra'],
287 'custom_' . $fields['countryB']['id'] => $countriesByName['Barbados'],
288 ]),
289 'bob' => $this->individualCreate([
290 'first_name' => 'Bob',
291 'last_name' => 'Roberts',
292 'custom_' . $fields['countryA']['id'] => $countriesByName['Austria'],
293 'custom_' . $fields['countryB']['id'] => $countriesByName['Bermuda'],
294 'custom_' . $fields['countryC']['id'] => $countriesByName['Chad'],
295 ]),
296 'carol' => $this->individualCreate([
297 'first_name' => 'Carol',
298 'last_name' => 'Carolson',
299 'custom_' . $fields['countryC']['id'] => $countriesByName['Cambodia'],
300 ]),
301 ];
302
303 // Move!
304 CRM_Core_BAO_CustomField::moveField($fields['countryB']['id'], $groupB['id']);
305
306 // Group[A] no longer has fields[countryB]
307 $errorScope = CRM_Core_TemporaryErrorScope::useException();
308 try {
309 $this->assertDBQuery(1, "SELECT {$fields['countryB']['column_name']} FROM " . $groupA['table_name']);
310 $this->fail('Expected exception when querying column on wrong table');
311 }
312 catch (PEAR_Exception$e) {
313 }
314 $errorScope = NULL;
315
316 // Alice: Group[B] has fields[countryB], but fields[countryC] did not exist before
317 $this->assertDBQuery(1,
318 "SELECT count(*) FROM {$groupB['table_name']}
319 WHERE entity_id = %1
320 AND {$fields['countryB']['column_name']} = %3
321 AND {$fields['countryC']['column_name']} is null",
322 [
323 1 => [$contacts['alice'], 'Integer'],
324 3 => [$countriesByName['Barbados'], 'Integer'],
325 ]
326 );
327
328 // Bob: Group[B] has merged fields[countryB] and fields[countryC] on the same record
329 $this->assertDBQuery(1,
330 "SELECT count(*) FROM {$groupB['table_name']}
331 WHERE entity_id = %1
332 AND {$fields['countryB']['column_name']} = %3
333 AND {$fields['countryC']['column_name']} = %4",
334 [
335 1 => [$contacts['bob'], 'Integer'],
336 3 => [$countriesByName['Bermuda'], 'Integer'],
337 4 => [$countriesByName['Chad'], 'Integer'],
338 ]
339 );
340
341 // Carol: Group[B] still has fields[countryC] but did not get fields[countryB]
342 $this->assertDBQuery(1,
343 "SELECT count(*) FROM {$groupB['table_name']}
344 WHERE entity_id = %1
345 AND {$fields['countryB']['column_name']} is null
346 AND {$fields['countryC']['column_name']} = %4",
347 [
348 1 => [$contacts['carol'], 'Integer'],
349 4 => [$countriesByName['Cambodia'], 'Integer'],
350 ]
351 );
352
353 $this->customGroupDelete($groups['A']['id']);
354 $this->customGroupDelete($groupB['id']);
355 }
356
357 /**
358 * Test get custom field id function.
359 */
360 public function testGetCustomFieldID() {
361 $this->createCustomField();
362 $fieldID = CRM_Core_BAO_CustomField::getCustomFieldID('testFld');
363 $this->assertEquals($this->customFieldID, $fieldID);
364
365 $fieldID = CRM_Core_BAO_CustomField::getCustomFieldID('testFld', 'new custom group');
366 $this->assertEquals($this->customFieldID, $fieldID);
367
368 $fieldID = CRM_Core_BAO_CustomField::getCustomFieldID('testFld', 'new custom group', TRUE);
369 $this->assertEquals('custom_' . $this->customFieldID, $fieldID);
370
371 // create field with same name in a different group
372 $this->createCustomField('other custom group');
373 $otherFieldID = CRM_Core_BAO_CustomField::getCustomFieldID('testFld', 'other custom group');
374 // make sure it does not return the field ID of the first field
375 $this->assertNotEquals($fieldID, $otherFieldID);
376 }
377
378 /**
379 * Create a custom field
380 *
381 * @param string $groupTitle
382 *
383 * @return array
384 */
385 protected function createCustomField($groupTitle = 'new custom group') {
386 $customGroup = $this->customGroupCreate([
387 'extends' => 'Individual',
388 'title' => $groupTitle,
389 ]);
390 $fields = [
391 'label' => 'testFld',
392 'data_type' => 'String',
393 'html_type' => 'Text',
394 'custom_group_id' => $customGroup['id'],
395 ];
396 $field = CRM_Core_BAO_CustomField::create($fields);
397 $this->customFieldID = $field->id;
398 return $customGroup;
399 }
400
401 /**
402 * Tet the getFieldsForImport function.
403 */
404 public function testGetFieldsForImport() {
405 $this->entity = 'Contact';
406 $this->createCustomGroupWithFieldsOfAllTypes();
407 $expected = [
408 $this->getCustomFieldName('country') => [
409 'name' => $this->getCustomFieldName('country') ,
410 'type' => 1,
411 'title' => 'Country',
412 'headerPattern' => '//',
413 'import' => 1,
414 'custom_field_id' => $this->getCustomFieldID('country'),
415 'options_per_line' => NULL,
416 'text_length' => NULL,
417 'data_type' => 'Int',
418 'html_type' => 'Select Country',
419 'is_search_range' => '0',
420 ],
421 $this->getCustomFieldName('file') => [
422 'name' => $this->getCustomFieldName('file'),
423 'type' => 2,
424 'title' => 'Custom Field',
425 'headerPattern' => '//',
426 'import' => 1,
427 'custom_field_id' => $this->getCustomFieldID('file'),
428 'options_per_line' => NULL,
429 'text_length' => NULL,
430 'data_type' => 'File',
431 'html_type' => 'File',
432 'is_search_range' => '0',
433 ],
434 $this->getCustomFieldName('text') => [
435 'name' => $this->getCustomFieldName('text'),
436 'type' => 2,
437 'title' => 'Enter text here',
438 'headerPattern' => '//',
439 'import' => 1,
440 'custom_field_id' => $this->getCustomFieldID('text'),
441 'options_per_line' => NULL,
442 'text_length' => NULL,
443 'data_type' => 'String',
444 'html_type' => 'Text',
445 'is_search_range' => '0',
446 ],
447 $this->getCustomFieldName('select_string') => [
448 'name' => $this->getCustomFieldName('select_string'),
449 'type' => 2,
450 'title' => 'Pick Color',
451 'headerPattern' => '//',
452 'import' => 1,
453 'custom_field_id' => $this->getCustomFieldID('select_string'),
454 'options_per_line' => NULL,
455 'text_length' => NULL,
456 'data_type' => 'String',
457 'html_type' => 'Select',
458 'is_search_range' => '0',
459 ],
460 $this->getCustomFieldName('select_date') => [
461 'name' => $this->getCustomFieldName('select_date'),
462 'type' => 4,
463 'title' => 'test_date',
464 'headerPattern' => '//',
465 'import' => 1,
466 'custom_field_id' => $this->getCustomFieldID('select_date'),
467 'options_per_line' => NULL,
468 'text_length' => NULL,
469 'data_type' => 'Date',
470 'html_type' => 'Select Date',
471 'is_search_range' => '0',
472 'date_format' => 'mm/dd/yy',
473 'time_format' => '1',
474 ],
475 $this->getCustomFieldName('link') => [
476 'name' => $this->getCustomFieldName('link'),
477 'type' => 2,
478 'title' => 'test_link',
479 'headerPattern' => '//',
480 'import' => 1,
481 'custom_field_id' => $this->getCustomFieldID('link'),
482 'options_per_line' => NULL,
483 'text_length' => NULL,
484 'data_type' => 'Link',
485 'html_type' => 'Link',
486 'is_search_range' => '0',
487 ],
488 ];
489 $this->assertEquals($expected, CRM_Core_BAO_CustomField::getFieldsForImport());
490 }
491
492 }