Merge pull request #21266 from civicrm/5.41
[civicrm-core.git] / tests / phpunit / api / v4 / Action / BasicCustomFieldTest.php
CommitLineData
19b53e5b
C
1<?php
2
380f3545
TO
3/*
4 +--------------------------------------------------------------------+
7d61e75f 5 | Copyright CiviCRM LLC. All rights reserved. |
380f3545 6 | |
7d61e75f
TO
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
380f3545
TO
10 +--------------------------------------------------------------------+
11 */
12
13/**
14 *
15 * @package CRM
ca5cec67 16 * @copyright CiviCRM LLC https://civicrm.org/licensing
380f3545
TO
17 */
18
19
19b53e5b
C
20namespace api\v4\Action;
21
22use Civi\Api4\Contact;
23use Civi\Api4\CustomField;
24use Civi\Api4\CustomGroup;
ab8c864e 25use Civi\Api4\OptionGroup;
cbda9790
CW
26use Civi\Api4\Relationship;
27use Civi\Api4\RelationshipCache;
19b53e5b
C
28
29/**
30 * @group headless
31 */
32class BasicCustomFieldTest extends BaseCustomValueTest {
33
06b84fc8
EM
34 /**
35 * @throws \API_Exception
36 */
37 public function testWithSingleField(): void {
fe806431 38 $customGroup = CustomGroup::create(FALSE)
c752d94b
CW
39 ->addValue('name', 'MyIndividualFields')
40 ->addValue('extends', 'Individual')
19b53e5b
C
41 ->execute()
42 ->first();
43
fe806431 44 CustomField::create(FALSE)
19b53e5b
C
45 ->addValue('label', 'FavColor')
46 ->addValue('custom_group_id', $customGroup['id'])
47 ->addValue('html_type', 'Text')
48 ->addValue('data_type', 'String')
49 ->execute();
50
c752d94b 51 // Individual fields should show up when contact_type = null|Individual but not other contact types
fe806431 52 $getFields = Contact::getFields(FALSE);
a1415a02 53 $this->assertEquals('Custom', $getFields->execute()->indexBy('name')['MyIndividualFields.FavColor']['type']);
c752d94b
CW
54 $this->assertContains('MyIndividualFields.FavColor', $getFields->setValues(['contact_type' => 'Individual'])->execute()->column('name'));
55 $this->assertNotContains('MyIndividualFields.FavColor', $getFields->setValues(['contact_type' => 'Household'])->execute()->column('name'));
56
fe806431 57 $contactId = Contact::create(FALSE)
19b53e5b
C
58 ->addValue('first_name', 'Johann')
59 ->addValue('last_name', 'Tester')
60 ->addValue('contact_type', 'Individual')
c752d94b 61 ->addValue('MyIndividualFields.FavColor', 'Red')
19b53e5b
C
62 ->execute()
63 ->first()['id'];
64
fe806431 65 $contact = Contact::get(FALSE)
19b53e5b 66 ->addSelect('first_name')
c752d94b 67 ->addSelect('MyIndividualFields.FavColor')
19b53e5b 68 ->addWhere('id', '=', $contactId)
c752d94b 69 ->addWhere('MyIndividualFields.FavColor', '=', 'Red')
19b53e5b
C
70 ->execute()
71 ->first();
72
c752d94b 73 $this->assertEquals('Red', $contact['MyIndividualFields.FavColor']);
19b53e5b
C
74
75 Contact::update()
76 ->addWhere('id', '=', $contactId)
c752d94b 77 ->addValue('MyIndividualFields.FavColor', 'Blue')
19b53e5b
C
78 ->execute();
79
fe806431 80 $contact = Contact::get(FALSE)
c752d94b 81 ->addSelect('MyIndividualFields.FavColor')
19b53e5b
C
82 ->addWhere('id', '=', $contactId)
83 ->execute()
84 ->first();
85
c752d94b 86 $this->assertEquals('Blue', $contact['MyIndividualFields.FavColor']);
19b53e5b
C
87 }
88
89 public function testWithTwoFields() {
ab8c864e 90 $optionGroupCount = OptionGroup::get(FALSE)->selectRowCount()->execute()->count();
19b53e5b 91
c9e3994d 92 // First custom set
fe806431 93 CustomGroup::create(FALSE)
19b53e5b
C
94 ->addValue('name', 'MyContactFields')
95 ->addValue('extends', 'Contact')
c9e3994d
CW
96 ->addChain('field1', CustomField::create()
97 ->addValue('label', 'FavColor')
98 ->addValue('custom_group_id', '$id')
99 ->addValue('html_type', 'Text')
100 ->addValue('data_type', 'String'))
101 ->addChain('field2', CustomField::create()
102 ->addValue('label', 'FavFood')
103 ->addValue('custom_group_id', '$id')
104 ->addValue('html_type', 'Text')
105 ->addValue('data_type', 'String'))
19b53e5b
C
106 ->execute();
107
c9e3994d 108 // Second custom set
fe806431 109 CustomGroup::create(FALSE)
c9e3994d
CW
110 ->addValue('name', 'MyContactFields2')
111 ->addValue('extends', 'Contact')
112 ->addChain('field1', CustomField::create()
113 ->addValue('label', 'FavColor')
114 ->addValue('custom_group_id', '$id')
115 ->addValue('html_type', 'Text')
116 ->addValue('data_type', 'String'))
117 ->addChain('field2', CustomField::create()
118 ->addValue('label', 'FavFood')
119 ->addValue('custom_group_id', '$id')
120 ->addValue('html_type', 'Text')
121 ->addValue('data_type', 'String'))
19b53e5b
C
122 ->execute();
123
ab8c864e
CW
124 // Test that no new option groups have been created (these are text fields with no options)
125 $this->assertEquals($optionGroupCount, OptionGroup::get(FALSE)->selectRowCount()->execute()->count());
126
fe806431 127 $contactId1 = Contact::create(FALSE)
19b53e5b
C
128 ->addValue('first_name', 'Johann')
129 ->addValue('last_name', 'Tester')
130 ->addValue('MyContactFields.FavColor', 'Red')
131 ->addValue('MyContactFields.FavFood', 'Cherry')
132 ->execute()
133 ->first()['id'];
134
fe806431 135 $contactId2 = Contact::create(FALSE)
19b53e5b
C
136 ->addValue('first_name', 'MaryLou')
137 ->addValue('last_name', 'Tester')
138 ->addValue('MyContactFields.FavColor', 'Purple')
139 ->addValue('MyContactFields.FavFood', 'Grapes')
140 ->execute()
141 ->first()['id'];
142
fe806431 143 $contact = Contact::get(FALSE)
19b53e5b
C
144 ->addSelect('first_name')
145 ->addSelect('MyContactFields.FavColor')
146 ->addSelect('MyContactFields.FavFood')
147 ->addWhere('id', '=', $contactId1)
148 ->addWhere('MyContactFields.FavColor', '=', 'Red')
149 ->addWhere('MyContactFields.FavFood', '=', 'Cherry')
150 ->execute()
151 ->first();
19b53e5b
C
152 $this->assertArrayHasKey('MyContactFields.FavColor', $contact);
153 $this->assertEquals('Red', $contact['MyContactFields.FavColor']);
154
2f69b203
CW
155 // By default custom fields are not returned
156 $contact = Contact::get(FALSE)
157 ->addWhere('id', '=', $contactId1)
158 ->addWhere('MyContactFields.FavColor', '=', 'Red')
159 ->addWhere('MyContactFields.FavFood', '=', 'Cherry')
160 ->execute()
161 ->first();
162 $this->assertArrayNotHasKey('MyContactFields.FavColor', $contact);
163
c9e3994d 164 // Update 2nd set and ensure 1st hasn't changed
19b53e5b
C
165 Contact::update()
166 ->addWhere('id', '=', $contactId1)
c9e3994d
CW
167 ->addValue('MyContactFields2.FavColor', 'Orange')
168 ->addValue('MyContactFields2.FavFood', 'Tangerine')
19b53e5b 169 ->execute();
fe806431 170 $contact = Contact::get(FALSE)
c9e3994d 171 ->addSelect('MyContactFields.FavColor', 'MyContactFields2.FavColor', 'MyContactFields.FavFood', 'MyContactFields2.FavFood')
19b53e5b
C
172 ->addWhere('id', '=', $contactId1)
173 ->execute()
174 ->first();
c9e3994d
CW
175 $this->assertEquals('Red', $contact['MyContactFields.FavColor']);
176 $this->assertEquals('Orange', $contact['MyContactFields2.FavColor']);
177 $this->assertEquals('Cherry', $contact['MyContactFields.FavFood']);
178 $this->assertEquals('Tangerine', $contact['MyContactFields2.FavFood']);
19b53e5b 179
c9e3994d
CW
180 // Update 1st set and ensure 2st hasn't changed
181 Contact::update()
182 ->addWhere('id', '=', $contactId1)
183 ->addValue('MyContactFields.FavColor', 'Blue')
184 ->execute();
fe806431 185 $contact = Contact::get(FALSE)
2f69b203 186 ->addSelect('custom.*')
c9e3994d
CW
187 ->addWhere('id', '=', $contactId1)
188 ->execute()
189 ->first();
19b53e5b 190 $this->assertEquals('Blue', $contact['MyContactFields.FavColor']);
c9e3994d
CW
191 $this->assertEquals('Orange', $contact['MyContactFields2.FavColor']);
192 $this->assertEquals('Cherry', $contact['MyContactFields.FavFood']);
193 $this->assertEquals('Tangerine', $contact['MyContactFields2.FavFood']);
19b53e5b 194
fe806431 195 $search = Contact::get(FALSE)
19b53e5b
C
196 ->addClause('OR', ['MyContactFields.FavColor', '=', 'Blue'], ['MyContactFields.FavFood', '=', 'Grapes'])
197 ->addSelect('id')
198 ->addOrderBy('id')
199 ->execute()
200 ->indexBy('id');
201
202 $this->assertEquals([$contactId1, $contactId2], array_keys((array) $search));
203
fe806431 204 $search = Contact::get(FALSE)
19b53e5b
C
205 ->addClause('NOT', ['MyContactFields.FavColor', '=', 'Purple'], ['MyContactFields.FavFood', '=', 'Grapes'])
206 ->addSelect('id')
207 ->addOrderBy('id')
208 ->execute()
209 ->indexBy('id');
210
211 $this->assertNotContains($contactId2, array_keys((array) $search));
212
fe806431 213 $search = Contact::get(FALSE)
19b53e5b
C
214 ->addClause('NOT', ['MyContactFields.FavColor', '=', 'Purple'], ['MyContactFields.FavFood', '=', 'Grapes'])
215 ->addSelect('id')
216 ->addOrderBy('id')
217 ->execute()
218 ->indexBy('id');
219
220 $this->assertContains($contactId1, array_keys((array) $search));
221 $this->assertNotContains($contactId2, array_keys((array) $search));
222
fe806431 223 $search = Contact::get(FALSE)
19b53e5b
C
224 ->setWhere([['NOT', ['OR', [['MyContactFields.FavColor', '=', 'Blue'], ['MyContactFields.FavFood', '=', 'Grapes']]]]])
225 ->addSelect('id')
226 ->addOrderBy('id')
227 ->execute()
228 ->indexBy('id');
229
230 $this->assertNotContains($contactId1, array_keys((array) $search));
231 $this->assertNotContains($contactId2, array_keys((array) $search));
232 }
233
cbda9790
CW
234 public function testRelationshipCacheCustomFields() {
235 $cgName = uniqid('RelFields');
236
237 $customGroup = CustomGroup::create(FALSE)
238 ->addValue('name', $cgName)
239 ->addValue('extends', 'Relationship')
240 ->execute()
241 ->first();
242
243 CustomField::create(FALSE)
244 ->addValue('label', 'PetName')
245 ->addValue('custom_group_id', $customGroup['id'])
246 ->addValue('html_type', 'Text')
247 ->addValue('data_type', 'String')
248 ->execute();
249
250 $parent = Contact::create(FALSE)
251 ->addValue('first_name', 'Parent')
252 ->addValue('last_name', 'Tester')
253 ->addValue('contact_type', 'Individual')
254 ->execute()
255 ->first()['id'];
256
257 $child = Contact::create(FALSE)
258 ->addValue('first_name', 'Child')
259 ->addValue('last_name', 'Tester')
260 ->addValue('contact_type', 'Individual')
261 ->execute()
262 ->first()['id'];
263
264 $relationship = Relationship::create(FALSE)
265 ->addValue('contact_id_a', $parent)
266 ->addValue('contact_id_b', $child)
267 ->addValue('relationship_type_id', 1)
268 ->addValue("$cgName.PetName", 'Buddy')
269 ->execute();
270
271 $results = RelationshipCache::get(FALSE)
272 ->addSelect("$cgName.PetName")
273 ->addWhere("$cgName.PetName", '=', 'Buddy')
274 ->execute();
275
276 $this->assertCount(2, $results);
277 $this->assertEquals('Buddy', $results[0]["$cgName.PetName"]);
278 }
279
b60c8243
CW
280 public function testMultipleJoinsToCustomTable() {
281 $cgName = uniqid('My');
282
283 CustomGroup::create(FALSE)
284 ->addValue('name', $cgName)
285 ->addValue('extends', 'Contact')
286 ->addChain('field1', CustomField::create()
287 ->addValue('label', 'FavColor')
288 ->addValue('custom_group_id', '$id')
289 ->addValue('html_type', 'Text')
290 ->addValue('data_type', 'String'))
291 ->execute();
292
293 $parent = Contact::create(FALSE)
294 ->addValue('first_name', 'Parent')
295 ->addValue('last_name', 'Tester')
296 ->addValue("$cgName.FavColor", 'Purple')
297 ->execute()
298 ->first()['id'];
299
300 $child = Contact::create(FALSE)
301 ->addValue('first_name', 'Child')
302 ->addValue('last_name', 'Tester')
303 ->addValue("$cgName.FavColor", 'Cyan')
304 ->execute()
305 ->first()['id'];
306
307 Relationship::create(FALSE)
308 ->addValue('contact_id_a', $parent)
309 ->addValue('contact_id_b', $child)
310 ->addValue('relationship_type_id', 1)
311 ->execute();
312
313 $results = Contact::get(FALSE)
314 ->addSelect('first_name', 'child.first_name', "$cgName.FavColor", "child.$cgName.FavColor")
315 ->addWhere('id', '=', $parent)
316 ->addJoin('Contact AS child', 'INNER', 'RelationshipCache', ['id', '=', 'child.far_contact_id'])
317 ->execute();
318
319 $this->assertCount(1, $results);
320 $this->assertEquals('Parent', $results[0]['first_name']);
321 $this->assertEquals('Child', $results[0]['child.first_name']);
322 $this->assertEquals('Purple', $results[0]["$cgName.FavColor"]);
323 $this->assertEquals('Cyan', $results[0]["child.$cgName.FavColor"]);
324 }
325
2986a716 326 /**
327 * Some types are creating a dummy option group even if we don't have
328 * any option values.
329 * @throws \API_Exception
330 */
331 public function testUndesiredOptionGroupCreation(): void {
332 $optionGroupCount = OptionGroup::get(FALSE)->selectRowCount()->execute()->count();
333
334 $customGroup = CustomGroup::create(FALSE)
335 ->addValue('name', 'MyIndividualFields')
336 ->addValue('extends', 'Individual')
337 ->execute()
338 ->first();
339
340 // This one doesn't make sense to have an option group.
341 CustomField::create(FALSE)
342 ->addValue('label', 'FavColor')
343 ->addValue('custom_group_id', $customGroup['id'])
344 ->addValue('html_type', 'Number')
345 ->addValue('data_type', 'Money')
346 ->execute();
347
348 // This one might be ok if we planned to then use the autocreated option
349 // group, but if we go on to create our own after then we have an extra
350 // unused group.
351 CustomField::create(FALSE)
352 ->addValue('label', 'FavMovie')
353 ->addValue('custom_group_id', $customGroup['id'])
354 ->addValue('html_type', 'Select')
355 ->addValue('data_type', 'String')
356 ->execute();
357
358 $this->assertEquals($optionGroupCount, OptionGroup::get(FALSE)->selectRowCount()->execute()->count());
359 }
360
19b53e5b 361}