Merge pull request #19806 from eileenmcnaughton/msg_compat
[civicrm-core.git] / tests / phpunit / CRM / Contact / BAO / GroupTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * Test class for CRM_Contact_BAO_Group BAO
14 *
15 * @package CiviCRM
16 * @group headless
17 */
18 class CRM_Contact_BAO_GroupTest extends CiviUnitTestCase {
19
20 /**
21 * Tears down the fixture, for example, closes a network connection.
22 *
23 * This method is called after a test is executed.
24 */
25 protected function tearDown(): void {
26 $this->quickCleanup(['civicrm_mapping_field', 'civicrm_mapping', 'civicrm_group', 'civicrm_saved_search']);
27 }
28
29 /**
30 * Test case for add( ).
31 */
32 public function testAddSimple() {
33
34 $checkParams = $params = [
35 'title' => 'Group Uno',
36 'description' => 'Group One',
37 'visibility' => 'User and User Admin Only',
38 'is_active' => 1,
39 ];
40
41 $group = CRM_Contact_BAO_Group::create($params);
42
43 $this->assertDBCompareValues(
44 'CRM_Contact_DAO_Group',
45 ['id' => $group->id],
46 $checkParams
47 );
48 }
49
50 /**
51 * Test case to ensure child group is present in the hierarchy
52 * if it has multiple parent groups and not all are disabled.
53 */
54 public function testGroupHirearchy() {
55 // Use-case :
56 // 1. Create two parent group A and B and disable B
57 // 2. Create a child group C
58 // 3. Ensure that Group C is present in the group hierarchy
59 $params = [
60 'name' => uniqid(),
61 'title' => 'Parent Group A',
62 'description' => 'Parent Group One',
63 'visibility' => 'User and User Admin Only',
64 'is_active' => 1,
65 ];
66 $group1 = CRM_Contact_BAO_Group::create($params);
67
68 $params = array_merge($params, [
69 'name' => uniqid(),
70 'title' => 'Parent Group B',
71 'description' => 'Parent Group Two',
72 // disable
73 'is_active' => 0,
74 ]);
75 $group2 = CRM_Contact_BAO_Group::create($params);
76
77 $params = array_merge($params, [
78 'name' => uniqid(),
79 'title' => 'Child Group C',
80 'description' => 'Child Group C',
81 'parents' => [
82 $group1->id => 1,
83 $group2->id => 1,
84 ],
85 ]);
86 $group3 = CRM_Contact_BAO_Group::create($params);
87
88 $params = [
89 $group1->id => 1,
90 $group3->id => 1,
91 ];
92 $groupsHierarchy = CRM_Contact_BAO_Group::getGroupsHierarchy($params, NULL, '&nbsp;&nbsp;', TRUE);
93 // check if child group is present in the tree with formatted group title prepended with spacer '&nbsp;&nbsp;'
94 $this->assertEquals('&nbsp;&nbsp;Child Group C', $groupsHierarchy[$group3->id]);
95
96 // Disable parent group A and ensure that child group C is not present as both of its parent groups are disabled
97 $group1->is_active = 0;
98 $group1->save();
99 $groupsHierarchy = CRM_Contact_BAO_Group::getGroupsHierarchy($params, NULL, '&nbsp;&nbsp;', TRUE);
100 $this->assertFalse(array_key_exists($group3->id, $groupsHierarchy));
101 }
102
103 /**
104 * Test nestedGroup pseudoconstant
105 */
106 public function testNestedGroup() {
107 $params = [
108 'name' => 'groupa',
109 'title' => 'Parent Group A',
110 'description' => 'Parent Group One',
111 'visibility' => 'User and User Admin Only',
112 'is_active' => 1,
113 // mailing group
114 'group_type' => ['2' => 1],
115 ];
116 $group1 = CRM_Contact_BAO_Group::create($params);
117
118 $params = [
119 'name' => 'groupb',
120 'title' => 'Parent Group B',
121 'description' => 'Parent Group Two',
122 'visibility' => 'User and User Admin Only',
123 'is_active' => 1,
124 ];
125 $group2 = CRM_Contact_BAO_Group::create($params);
126
127 $params = [
128 'name' => 'groupc',
129 'title' => 'Child Group C',
130 'description' => 'Child Group C',
131 'visibility' => 'User and User Admin Only',
132 'is_active' => 1,
133 'parents' => [
134 $group2->id => 1,
135 ],
136 'group_type' => ['2' => 1],
137 ];
138 $group3 = CRM_Contact_BAO_Group::create($params);
139
140 unset(Civi::$statics['CRM_Core_Permission_Base']);
141 // Check with no group type restriction
142 $nestedGroup = CRM_Core_PseudoConstant::nestedGroup();
143 $this->assertEquals([
144 $group1->id => 'Parent Group A',
145 $group2->id => 'Parent Group B',
146 $group3->id => '&nbsp;&nbsp;Child Group C',
147 ], $nestedGroup);
148
149 // Check restrict to mailing groups
150 $nestedGroup = CRM_Core_PseudoConstant::nestedGroup(TRUE, 'Mailing');
151 $this->assertSame([
152 $group1->id => 'Parent Group A',
153 $group3->id => '&nbsp;&nbsp;Child Group C',
154 ], $nestedGroup);
155 }
156
157 /**
158 * Test adding a smart group.
159 */
160 public function testAddSmart() {
161
162 $checkParams = $params = [
163 'title' => 'Group Dos',
164 'description' => 'Group Two',
165 'visibility' => 'User and User Admin Only',
166 'is_active' => 1,
167 'formValues' => ['sort_name' => 'Adams'],
168 ];
169
170 $group = CRM_Contact_BAO_Group::createSmartGroup($params);
171
172 unset($checkParams['formValues']);
173 $this->assertDBCompareValues(
174 'CRM_Contact_DAO_Group',
175 ['id' => $group->id],
176 $checkParams
177 );
178 }
179
180 /**
181 * Load all sql data sets & return an array of saved searches.
182 *
183 * @return array
184 */
185 public function dataProviderSavedSearch() {
186
187 $this->loadSavedSearches();
188 $results = CRM_Core_DAO::singleValueQuery('SELECT GROUP_CONCAT(id) FROM civicrm_group WHERE saved_search_id IS NOT NULL');
189 return [explode(',', $results)];
190 }
191
192 /**
193 * Load saved search sql files into the DB.
194 */
195 public function loadSavedSearches() {
196 foreach (glob(dirname(__FILE__) . "/SavedSearchDataSets/*.sql") as $file) {
197 CRM_Utils_File::sourceSQLFile(NULL, $file);
198 }
199 }
200
201 /**
202 * Check we can load smart groups based on config from 'real DBs' without fatal errors.
203 *
204 * Note that we are only testing lack of errors at this stage
205 * @todo - for some reason the data was getting truncated from the group table using dataprovider - would be preferable to get that working
206 * //@notdataProvider dataProviderSavedSearch
207 * //@notparam integer $groupID
208 *
209 * To add to this dataset do
210 *
211 * SET @groupID = x;
212 * SELECT mapping_id FROM civicrm_group g LEFT JOIN civicrm_saved_search s ON saved_search_id = s.id WHERE g.id = @groupID INTO @mappingID;
213 * SELECT * FROM civicrm_mapping WHERE id = @mappingID;
214 * SELECT * FROM civicrm_mapping_field WHERE mapping_id = @mappingID;
215 * SELECT * FROM civicrm_saved_search WHERE mapping_id = @mappingID;
216 * SELECT g.* FROM civicrm_saved_search s LEFT JOIN civicrm_group g ON g.saved_search_id = s.id WHERE mapping_id = @mappingID;
217 *
218 * Copy the output to a single sql file and place in the SavedSearchDataSets folder - use the group number as the prefix.
219 * Try to keep as much of the real world irregular glory as you can! Don't change the table ids to be number 1 as this can hide errors
220 */
221 public function testGroupData() {
222 $groups = $this->dataProviderSavedSearch();
223 foreach ($groups[0] as $groupID) {
224 $group = new CRM_Contact_BAO_Group();
225 $group->id = $groupID;
226 $group->find(TRUE);
227
228 CRM_Contact_BAO_GroupContactCache::load($group, TRUE);
229 }
230 }
231
232 /**
233 * Ensure that when updating a group with a linked organisation record even tho that record's id doesn't match the group id no db error is produced
234 */
235 public function testGroupUpdateWithOrganization() {
236 $params = [
237 'name' => uniqid(),
238 'title' => 'Group A',
239 'description' => 'Group One',
240 'visibility' => 'User and User Admin Only',
241 'is_active' => 1,
242 ];
243 $group1 = CRM_Contact_BAO_Group::create($params);
244
245 $domain1 = $this->callAPISuccess('Domain', 'get', ['id' => 1]);
246 $params2 = [
247 'name' => uniqid(),
248 'title' => 'Group B',
249 'description' => 'Group Two',
250 'visibility' => 'User and User Admin Only',
251 'is_active' => 1,
252 'organization_id' => $domain1['values'][1]['contact_id'],
253 ];
254 $group2 = CRM_Contact_BAO_Group::create($params2);
255
256 $domain2 = $this->callAPISuccess('Domain', 'get', ['id' => 2]);
257 $params3 = [
258 'name' => uniqid(),
259 'title' => 'Group C',
260 'description' => 'Group Three',
261 'visibility' => 'User and User Admin Only',
262 'is_active' => 1,
263 'organization_id' => $domain2['values'][2]['contact_id'],
264 ];
265 $group3 = CRM_Contact_BAO_Group::create($params3);
266 $params2['id'] = $group2->id;
267 $testUpdate = CRM_Contact_BAO_Group::create($params2);
268 }
269
270 /**
271 * Ensure that when hidden smart group is created, wildcard string value is not ignored
272 */
273 public function testHiddenSmartGroup() {
274 $customGroup = $this->customGroupCreate();
275 $fields = [
276 'label' => 'testFld',
277 'data_type' => 'String',
278 'html_type' => 'Text',
279 'custom_group_id' => $customGroup['id'],
280 ];
281 $customFieldID = CRM_Core_BAO_CustomField::create($fields)->id;
282
283 $contactID = $this->individualCreate(['custom_' . $customFieldID => 'abc']);
284
285 $hiddenSmartParams = [
286 'group_type' => ['2' => 1],
287 'form_values' => ['custom_' . $customFieldID => ['LIKE' => '%a%']],
288 'saved_search_id' => NULL,
289 'search_custom_id' => NULL,
290 'search_context' => 'advanced',
291 ];
292 list($smartGroupID, $savedSearchID) = CRM_Contact_BAO_Group::createHiddenSmartGroup($hiddenSmartParams);
293
294 $mailingID = $this->callAPISuccess('Mailing', 'create', [])['id'];
295 $this->callAPISuccess('MailingGroup', 'create', [
296 'mailing_id' => $mailingID,
297 'group_type' => 'Include',
298 'entity_table' => 'civicrm_group',
299 'entity_id' => $smartGroupID,
300 ]);
301
302 CRM_Mailing_BAO_Mailing::getRecipients($mailingID);
303 $recipients = $this->callAPISuccess('MailingRecipients', 'get', ['mailing_id' => $mailingID]);
304 $this->assertEquals(1, $recipients['count'], 'Check recipient count');
305 }
306
307 /**
308 * Test updating a group with just description and check the recent items
309 * list has the right title.
310 */
311 public function testGroupUpdateDescription() {
312 // Create a group. Copied from $this->testAddSimple().
313 // Note we need $checkParams because the function call changes $params.
314 $checkParams = $params = [
315 'title' => 'Group Uno',
316 'description' => 'Group One',
317 'visibility' => 'User and User Admin Only',
318 'is_active' => 1,
319 ];
320 $group = CRM_Contact_BAO_Group::create($params);
321
322 // Update the group with just id and description.
323 $newParams = [
324 'id' => $group->id,
325 'description' => 'The first group',
326 ];
327 CRM_Contact_BAO_Group::create($newParams);
328
329 // Check it against original array, except description.
330 $result = $this->callAPISuccess('Group', 'getsingle', ['id' => $group->id]);
331 foreach ($checkParams as $key => $value) {
332 if ($key === 'description') {
333 $this->assertEquals($newParams[$key], $result[$key], "$key doesn't match");
334 }
335 else {
336 $this->assertEquals($checkParams[$key], $result[$key], "$key doesn't match");
337 }
338 }
339
340 // Check recent items list.
341 $recentItems = CRM_Utils_Recent::get();
342 $this->assertEquals($checkParams['title'], $recentItems[0]['title']);
343 }
344
345 }