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