Merge pull request #17580 from samuelsov/dev/core#1670
[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 adding a smart group.
114 */
115 public function testAddSmart() {
116
117 $checkParams = $params = [
118 'title' => 'Group Dos',
119 'description' => 'Group Two',
120 'visibility' => 'User and User Admin Only',
121 'is_active' => 1,
122 'formValues' => ['sort_name' => 'Adams'],
123 ];
124
125 $group = CRM_Contact_BAO_Group::createSmartGroup($params);
126
127 unset($checkParams['formValues']);
128 $this->assertDBCompareValues(
129 'CRM_Contact_DAO_Group',
130 ['id' => $group->id],
131 $checkParams
132 );
133 }
134
135 /**
136 * Load all sql data sets & return an array of saved searches.
137 *
138 * @return array
139 */
140 public function dataProviderSavedSearch() {
141
142 $this->loadSavedSearches();
143 $results = CRM_Core_DAO::singleValueQuery('SELECT GROUP_CONCAT(id) FROM civicrm_group WHERE saved_search_id IS NOT NULL');
144 return [explode(',', $results)];
145 }
146
147 /**
148 * Load saved search sql files into the DB.
149 */
150 public function loadSavedSearches() {
151 foreach (glob(dirname(__FILE__) . "/SavedSearchDataSets/*.sql") as $file) {
152 CRM_Utils_File::sourceSQLFile(NULL, $file);
153 }
154 }
155
156 /**
157 * Check we can load smart groups based on config from 'real DBs' without fatal errors.
158 *
159 * Note that we are only testing lack of errors at this stage
160 * @todo - for some reason the data was getting truncated from the group table using dataprovider - would be preferable to get that working
161 * //@notdataProvider dataProviderSavedSearch
162 * //@notparam integer $groupID
163 *
164 * To add to this dataset do
165 *
166 * SET @groupID = x;
167 * 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;
168 * SELECT * FROM civicrm_mapping WHERE id = @mappingID;
169 * SELECT * FROM civicrm_mapping_field WHERE mapping_id = @mappingID;
170 * SELECT * FROM civicrm_saved_search WHERE mapping_id = @mappingID;
171 * SELECT g.* FROM civicrm_saved_search s LEFT JOIN civicrm_group g ON g.saved_search_id = s.id WHERE mapping_id = @mappingID;
172 *
173 * Copy the output to a single sql file and place in the SavedSearchDataSets folder - use the group number as the prefix.
174 * 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
175 */
176 public function testGroupData() {
177 $groups = $this->dataProviderSavedSearch();
178 foreach ($groups[0] as $groupID) {
179 $group = new CRM_Contact_BAO_Group();
180 $group->id = $groupID;
181 $group->find(TRUE);
182
183 CRM_Contact_BAO_GroupContactCache::load($group, TRUE);
184 }
185 }
186
187 /**
188 * 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
189 */
190 public function testGroupUpdateWithOrganization() {
191 $params = [
192 'name' => uniqid(),
193 'title' => 'Group A',
194 'description' => 'Group One',
195 'visibility' => 'User and User Admin Only',
196 'is_active' => 1,
197 ];
198 $group1 = CRM_Contact_BAO_Group::create($params);
199
200 $domain1 = $this->callAPISuccess('Domain', 'get', ['id' => 1]);
201 $params2 = [
202 'name' => uniqid(),
203 'title' => 'Group B',
204 'description' => 'Group Two',
205 'visibility' => 'User and User Admin Only',
206 'is_active' => 1,
207 'organization_id' => $domain1['values'][1]['contact_id'],
208 ];
209 $group2 = CRM_Contact_BAO_Group::create($params2);
210
211 $domain2 = $this->callAPISuccess('Domain', 'get', ['id' => 2]);
212 $params3 = [
213 'name' => uniqid(),
214 'title' => 'Group C',
215 'description' => 'Group Three',
216 'visibility' => 'User and User Admin Only',
217 'is_active' => 1,
218 'organization_id' => $domain2['values'][2]['contact_id'],
219 ];
220 $group3 = CRM_Contact_BAO_Group::create($params3);
221 $params2['id'] = $group2->id;
222 $testUpdate = CRM_Contact_BAO_Group::create($params2);
223 }
224
225 /**
226 * Ensure that when hidden smart group is created, wildcard string value is not ignored
227 */
228 public function testHiddenSmartGroup() {
229 $customGroup = $this->customGroupCreate();
230 $fields = [
231 'label' => 'testFld',
232 'data_type' => 'String',
233 'html_type' => 'Text',
234 'custom_group_id' => $customGroup['id'],
235 ];
236 $customFieldID = CRM_Core_BAO_CustomField::create($fields)->id;
237
238 $contactID = $this->individualCreate(['custom_' . $customFieldID => 'abc']);
239
240 $hiddenSmartParams = [
241 'group_type' => ['2' => 1],
242 'form_values' => ['custom_' . $customFieldID => ['LIKE' => '%a%']],
243 'saved_search_id' => NULL,
244 'search_custom_id' => NULL,
245 'search_context' => 'advanced',
246 ];
247 list($smartGroupID, $savedSearchID) = CRM_Contact_BAO_Group::createHiddenSmartGroup($hiddenSmartParams);
248
249 $mailingID = $this->callAPISuccess('Mailing', 'create', [])['id'];
250 $this->callAPISuccess('MailingGroup', 'create', [
251 'mailing_id' => $mailingID,
252 'group_type' => 'Include',
253 'entity_table' => 'civicrm_group',
254 'entity_id' => $smartGroupID,
255 ]);
256
257 CRM_Mailing_BAO_Mailing::getRecipients($mailingID);
258 $recipients = $this->callAPISuccess('MailingRecipients', 'get', ['mailing_id' => $mailingID]);
259 $this->assertEquals(1, $recipients['count'], 'Check recipient count');
260 }
261
262 /**
263 * Test updating a group with just description and check the recent items
264 * list has the right title.
265 */
266 public function testGroupUpdateDescription() {
267 // Create a group. Copied from $this->testAddSimple().
268 // Note we need $checkParams because the function call changes $params.
269 $checkParams = $params = [
270 'title' => 'Group Uno',
271 'description' => 'Group One',
272 'visibility' => 'User and User Admin Only',
273 'is_active' => 1,
274 ];
275 $group = CRM_Contact_BAO_Group::create($params);
276
277 // Update the group with just id and description.
278 $newParams = [
279 'id' => $group->id,
280 'description' => 'The first group',
281 ];
282 CRM_Contact_BAO_Group::create($newParams);
283
284 // Check it against original array, except description.
285 $result = $this->callAPISuccess('Group', 'getsingle', ['id' => $group->id]);
286 foreach ($checkParams as $key => $value) {
287 if ($key === 'description') {
288 $this->assertEquals($newParams[$key], $result[$key], "$key doesn't match");
289 }
290 else {
291 $this->assertEquals($checkParams[$key], $result[$key], "$key doesn't match");
292 }
293 }
294
295 // Check recent items list.
296 $recentItems = CRM_Utils_Recent::get();
297 $this->assertEquals($checkParams['title'], $recentItems[0]['title']);
298 }
299
300 }