MDL-24690 fixed incorrect cohort condition when auto-creating groups
[moodle.git] / group / lib.php
CommitLineData
f3f7610c
ML
1<?php
2/**
ddff2fa8 3 * Extra library for groups and groupings.
f3f7610c
ML
4 *
5 * @copyright &copy; 2006 The Open University
2942a5cd 6 * @author J.White AT open.ac.uk, Petr Skoda (skodak)
f3f7610c
ML
7 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
8 * @package groups
9 */
10
ddff2fa8 11/*
12 * INTERNAL FUNCTIONS - to be used by moodle core only
13 * require_once $CFG->dirroot.'/group/lib.php' must be used
14 */
15
778918fd 16/**
17 * Adds a specified user to a group
9a0df45a 18 * @param mixed $groupid The group id or group object
19 * @param mixed $userid The user id or user object
f16fa0a3 20 * @return boolean True if user added successfully or the user is already a
21 * member of the group, false otherwise.
778918fd 22 */
9a0df45a 23function groups_add_member($grouporid, $userorid) {
dfdaabd6 24 global $DB;
25
9a0df45a 26 if (is_object($userorid)) {
27 $userid = $userorid->id;
28 $user = $userorid;
29 } else {
30 $userid = $userorid;
b18e25d5 31 $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
2061e59c 32 }
33
9a0df45a 34 if (is_object($grouporid)) {
35 $groupid = $grouporid->id;
36 $group = $grouporid;
37 } else {
38 $groupid = $grouporid;
39 $group = $DB->get_record('groups', array('id'=>$groupid), '*', MUST_EXIST);
778918fd 40 }
41
0d4723ee 42 //check if the user a participant of the group course
4f0c2d00 43 if (!is_enrolled(get_context_instance(CONTEXT_COURSE, $group->courseid), $userid)) {
9a0df45a 44 return false;
0d4723ee 45 }
46
778918fd 47 if (groups_is_member($groupid, $userid)) {
48 return true;
49 }
50
ace9051c 51 $member = new stdClass();
778918fd 52 $member->groupid = $groupid;
53 $member->userid = $userid;
54 $member->timeadded = time();
55
b25263ff 56 $DB->insert_record('groups_members', $member);
778918fd 57
58 //update group info
dfdaabd6 59 $DB->set_field('groups', 'timemodified', $member->timeadded, array('id'=>$groupid));
778918fd 60
2942a5cd 61 //trigger groups events
ace9051c 62 $eventdata = new stdClass();
778918fd 63 $eventdata->groupid = $groupid;
2942a5cd 64 $eventdata->userid = $userid;
65 events_trigger('groups_member_added', $eventdata);
778918fd 66
67 return true;
68}
69
70/**
71 * Deletes the link between the specified user and group.
9a0df45a 72 * @param mixed $groupid The group id or group object
73 * @param mixed $userid The user id or user object
778918fd 74 * @return boolean True if deletion was successful, false otherwise
75 */
9a0df45a 76function groups_remove_member($grouporid, $userorid) {
dfdaabd6 77 global $DB;
78
9a0df45a 79 if (is_object($userorid)) {
80 $userid = $userorid->id;
81 $user = $userorid;
82 } else {
83 $userid = $userorid;
b18e25d5 84 $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
2061e59c 85 }
86
9a0df45a 87 if (is_object($grouporid)) {
88 $groupid = $grouporid->id;
89 $group = $grouporid;
90 } else {
91 $groupid = $grouporid;
92 $group = $DB->get_record('groups', array('id'=>$groupid), '*', MUST_EXIST);
778918fd 93 }
94
95 if (!groups_is_member($groupid, $userid)) {
96 return true;
97 }
98
b25263ff 99 $DB->delete_records('groups_members', array('groupid'=>$groupid, 'userid'=>$userid));
100
778918fd 101 //update group info
dfdaabd6 102 $DB->set_field('groups', 'timemodified', time(), array('id'=>$groupid));
778918fd 103
2942a5cd 104 //trigger groups events
ace9051c 105 $eventdata = new stdClass();
2942a5cd 106 $eventdata->groupid = $groupid;
107 $eventdata->userid = $userid;
108 events_trigger('groups_member_removed', $eventdata);
109
778918fd 110 return true;
111}
112
ddff2fa8 113/**
114 * Add a new group
e88dd876 115 * @param object $data group properties
ddff2fa8 116 * @param object $um upload manager with group picture
117 * @return id of group or false if error
118 */
e88dd876 119function groups_create_group($data, $editform = false, $editoroptions = false) {
dfdaabd6 120 global $CFG, $DB;
6f5e0852 121
2061e59c 122 //check that courseid exists
9a0df45a 123 $course = $DB->get_record('course', array('id' => $data->courseid), '*', MUST_EXIST);
e88dd876 124 $context = get_context_instance(CONTEXT_COURSE, $course->id);
ddff2fa8 125
dfdaabd6 126 $data->timecreated = time();
ddff2fa8 127 $data->timemodified = $data->timecreated;
dfdaabd6 128 $data->name = trim($data->name);
8bdc9cac 129
e88dd876 130 if ($editform and $editoroptions) {
8bdc9cac
SH
131 $data->description = $data->description_editor['text'];
132 $data->descriptionformat = $data->description_editor['format'];
133 }
134
e88dd876
PS
135 $data->id = $DB->insert_record('groups', $data);
136
137 if ($editform and $editoroptions) {
138 // Update description from editor with fixed files
139 $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $context, 'group', 'description', $data->id);
ace9051c 140 $upd = new stdClass();
e88dd876
PS
141 $upd->id = $data->id;
142 $upd->description = $data->description;
143 $upd->descriptionformat = $data->descriptionformat;
144 $DB->update_record('groups', $upd);
145 }
146
147 $group = $DB->get_record('groups', array('id'=>$data->id));
ddff2fa8 148
b25263ff 149 if ($editform) {
e88dd876 150 groups_update_group_icon($group, $data, $editform);
ddff2fa8 151 }
152
b25263ff 153 //trigger groups events
e88dd876 154 events_trigger('groups_group_created', $group);
b25263ff 155
e88dd876 156 return $group->id;
ddff2fa8 157}
158
159/**
f16fa0a3 160 * Add a new grouping
e88dd876 161 * @param object $data grouping properties
f16fa0a3 162 * @return id of grouping or false if error
163 */
8bdc9cac 164function groups_create_grouping($data, $editoroptions=null) {
dfdaabd6 165 global $DB;
f16fa0a3 166
dfdaabd6 167 $data->timecreated = time();
f16fa0a3 168 $data->timemodified = $data->timecreated;
dfdaabd6 169 $data->name = trim($data->name);
8bdc9cac
SH
170
171 if ($editoroptions !== null) {
172 $data->description = $data->description_editor['text'];
173 $data->descriptionformat = $data->description_editor['format'];
174 }
175
2942a5cd 176 $id = $DB->insert_record('groupings', $data);
177
b25263ff 178 //trigger groups events
179 $data->id = $id;
8bdc9cac
SH
180
181 if ($editoroptions !== null) {
182 $description = new stdClass;
183 $description->id = $data->id;
184 $description->description_editor = $data->description_editor;
64f93798 185 $description = file_postupdate_standard_editor($description, 'description', $editoroptions, $editoroptions['context'], 'grouping', 'description', $description->id);
8bdc9cac
SH
186 $DB->update_record('groupings', $description);
187 }
188
b25263ff 189 events_trigger('groups_grouping_created', $data);
2942a5cd 190
191 return $id;
f16fa0a3 192}
193
e88dd876
PS
194/**
195 * Update the group icon from form data
196 * @param $group
197 * @param $data
198 * @param $editform
199 */
200function groups_update_group_icon($group, $data, $editform) {
201 global $CFG, $DB;
202 require_once("$CFG->libdir/gdlib.php");
203
204 $fs = get_file_storage();
205 $context = get_context_instance(CONTEXT_COURSE, $group->courseid, MUST_EXIST);
206
207 //TODO: it would make sense to allow picture deleting too (skodak)
208
209 if ($iconfile = $editform->save_temp_file('imagefile')) {
210 if (process_new_icon($context, 'group', 'icon', $group->id, $iconfile)) {
211 $DB->set_field('groups', 'picture', 1, array('id'=>$group->id));
212 $group->picture = 1;
213 } else {
214 $fs->delete_area_files($context->id, 'group', 'icon', $group->id);
215 $DB->set_field('groups', 'picture', 0, array('id'=>$group->id));
216 $group->picture = 0;
217 }
218 @unlink($iconfile);
219 }
220}
221
f16fa0a3 222/**
223 * Update group
224 * @param object $data group properties (with magic quotes)
e88dd876
PS
225 * @param object $editform
226 * @param array $editoroptions
b25263ff 227 * @return boolean true or exception
ddff2fa8 228 */
e88dd876 229function groups_update_group($data, $editform = false, $editoroptions = false) {
dfdaabd6 230 global $CFG, $DB;
e88dd876
PS
231
232 $context = get_context_instance(CONTEXT_COURSE, $data->courseid);
ddff2fa8 233
234 $data->timemodified = time();
dfdaabd6 235 $data->name = trim($data->name);
8bdc9cac 236
e88dd876
PS
237 if ($editform and $editoroptions) {
238 $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $context, 'group', 'description', $data->id);
8bdc9cac
SH
239 }
240
b25263ff 241 $DB->update_record('groups', $data);
2942a5cd 242
e88dd876
PS
243 $group = $DB->get_record('groups', array('id'=>$data->id));
244
b25263ff 245 if ($editform) {
e88dd876 246 groups_update_group_icon($group, $data, $editform);
ddff2fa8 247 }
248
b25263ff 249 //trigger groups events
e88dd876
PS
250 events_trigger('groups_group_updated', $group);
251
b25263ff 252
253 return true;
ddff2fa8 254}
255
f16fa0a3 256/**
257 * Update grouping
258 * @param object $data grouping properties (with magic quotes)
b25263ff 259 * @return boolean true or exception
f16fa0a3 260 */
8bdc9cac 261function groups_update_grouping($data, $editoroptions=null) {
dfdaabd6 262 global $DB;
f16fa0a3 263 $data->timemodified = time();
dfdaabd6 264 $data->name = trim($data->name);
8bdc9cac 265 if ($editoroptions !== null) {
64f93798 266 $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $editoroptions['context'], 'grouping', 'description', $data->id);
8bdc9cac 267 }
b25263ff 268 $DB->update_record('groupings', $data);
269 //trigger groups events
270 events_trigger('groups_grouping_updated', $data);
271
272 return true;
f16fa0a3 273}
274
ddff2fa8 275/**
276 * Delete a group best effort, first removing members and links with courses and groupings.
277 * Removes group avatar too.
2942a5cd 278 * @param mixed $grouporid The id of group to delete or full group object
ddff2fa8 279 * @return boolean True if deletion was successful, false otherwise
280 */
2942a5cd 281function groups_delete_group($grouporid) {
b7e8cfb6 282 global $CFG, $DB;
283 require_once("$CFG->libdir/gdlib.php");
ddff2fa8 284
2942a5cd 285 if (is_object($grouporid)) {
286 $groupid = $grouporid->id;
287 $group = $grouporid;
288 } else {
289 $groupid = $grouporid;
290 if (!$group = $DB->get_record('groups', array('id'=>$groupid))) {
9a0df45a 291 //silently ignore attempts to delete missing already deleted groups ;-)
292 return true;
2942a5cd 293 }
ddff2fa8 294 }
295
0b5a80a1 296 // delete group calendar events
dfdaabd6 297 $DB->delete_records('event', array('groupid'=>$groupid));
ddff2fa8 298 //first delete usage in groupings_groups
dfdaabd6 299 $DB->delete_records('groupings_groups', array('groupid'=>$groupid));
ddff2fa8 300 //delete members
dfdaabd6 301 $DB->delete_records('groups_members', array('groupid'=>$groupid));
ddff2fa8 302 //group itself last
b25263ff 303 $DB->delete_records('groups', array('id'=>$groupid));
8bdc9cac
SH
304
305 // Delete all files associated with this group
70e0f41e 306 $context = get_context_instance(CONTEXT_COURSE, $group->courseid);
8bdc9cac 307 $fs = get_file_storage();
e88dd876
PS
308 $fs->delete_area_files($context->id, 'group', 'description', $groupid);
309 $fs->delete_area_files($context->id, 'group', 'icon', $groupid);
8bdc9cac 310
b25263ff 311 //trigger groups events
312 events_trigger('groups_group_deleted', $group);
2942a5cd 313
b25263ff 314 return true;
ddff2fa8 315}
316
f16fa0a3 317/**
318 * Delete grouping
319 * @param int $groupingid
320 * @return bool success
321 */
2942a5cd 322function groups_delete_grouping($groupingorid) {
dfdaabd6 323 global $DB;
324
2942a5cd 325 if (is_object($groupingorid)) {
326 $groupingid = $groupingorid->id;
327 $grouping = $groupingorid;
328 } else {
329 $groupingid = $groupingorid;
330 if (!$grouping = $DB->get_record('groupings', array('id'=>$groupingorid))) {
9a0df45a 331 //silently ignore attempts to delete missing already deleted groupings ;-)
332 return true;
2942a5cd 333 }
ddff2fa8 334 }
335
336 //first delete usage in groupings_groups
dfdaabd6 337 $DB->delete_records('groupings_groups', array('groupingid'=>$groupingid));
ddff2fa8 338 // remove the default groupingid from course
dfdaabd6 339 $DB->set_field('course', 'defaultgroupingid', 0, array('defaultgroupingid'=>$groupingid));
ddff2fa8 340 // remove the groupingid from all course modules
dfdaabd6 341 $DB->set_field('course_modules', 'groupingid', 0, array('groupingid'=>$groupingid));
ddff2fa8 342 //group itself last
b25263ff 343 $DB->delete_records('groupings', array('id'=>$groupingid));
8bdc9cac 344
70e0f41e 345 $context = get_context_instance(CONTEXT_COURSE, $grouping->courseid);
8bdc9cac 346 $fs = get_file_storage();
64f93798 347 $files = $fs->get_area_files($context->id, 'grouping', 'description', $groupingid);
8bdc9cac
SH
348 foreach ($files as $file) {
349 $file->delete();
350 }
351
b25263ff 352 //trigger groups events
353 events_trigger('groups_grouping_deleted', $grouping);
2942a5cd 354
b25263ff 355 return true;
ddff2fa8 356}
357
f16fa0a3 358/**
ffc670d9 359 * Remove all users (or one user) from all groups in course
f16fa0a3 360 * @param int $courseid
ffc670d9 361 * @param int $userid 0 means all users
f16fa0a3 362 * @param bool $showfeedback
363 * @return bool success
364 */
ffc670d9 365function groups_delete_group_members($courseid, $userid=0, $showfeedback=false) {
a1c54f7a 366 global $DB, $OUTPUT;
ddff2fa8 367
ffc670d9 368 if (is_bool($userid)) {
369 debugging('Incorrect userid function parameter');
370 return false;
371 }
372
373 $params = array('courseid'=>$courseid);
374
375 if ($userid) {
376 $usersql = "AND userid = :userid";
377 $params['userid'] = $userid;
378 } else {
379 $usersql = "";
380 }
381
382 $groupssql = "SELECT id FROM {groups} g WHERE g.courseid = :courseid";
383 $DB->delete_records_select('groups_members', "groupid IN ($groupssql) $usersql", $params);
ddff2fa8 384
2942a5cd 385 //trigger groups events
ace9051c 386 $eventdata = new stdClass();
ffc670d9 387 $eventdata->courseid = $courseid;
388 $eventdata->userid = $userid;
389 events_trigger('groups_members_removed', $eventdata);
2942a5cd 390
ddff2fa8 391 if ($showfeedback) {
a1c54f7a 392 echo $OUTPUT->notification(get_string('deleted').' groups_members');
ddff2fa8 393 }
394
395 return true;
396}
397
0b5a80a1 398/**
399 * Remove all groups from all groupings in course
400 * @param int $courseid
401 * @param bool $showfeedback
402 * @return bool success
403 */
404function groups_delete_groupings_groups($courseid, $showfeedback=false) {
a1c54f7a 405 global $DB, $OUTPUT;
0b5a80a1 406
dfdaabd6 407 $groupssql = "SELECT id FROM {groups} g WHERE g.courseid = ?";
408 $DB->delete_records_select('groupings_groups', "groupid IN ($groupssql)", array($courseid));
0b5a80a1 409
8bdc9cac 410 // Delete all files associated with groupings for this course
70e0f41e 411 $context = get_context_instance(CONTEXT_COURSE, $courseid);
8bdc9cac 412
2942a5cd 413 //trigger groups events
414 events_trigger('groups_groupings_groups_removed', $courseid);
415
0b5a80a1 416 if ($showfeedback) {
a1c54f7a 417 echo $OUTPUT->notification(get_string('deleted').' groupings_groups');
0b5a80a1 418 }
419
420 return true;
421}
422
f16fa0a3 423/**
424 * Delete all groups from course
425 * @param int $courseid
426 * @param bool $showfeedback
427 * @return bool success
428 */
ddff2fa8 429function groups_delete_groups($courseid, $showfeedback=false) {
a1c54f7a 430 global $CFG, $DB, $OUTPUT;
ddff2fa8 431
0b5a80a1 432 // delete any uses of groups
8bdc9cac 433 // Any associated files are deleted as part of groups_delete_groupings_groups
0b5a80a1 434 groups_delete_groupings_groups($courseid, $showfeedback);
ffc670d9 435 groups_delete_group_members($courseid, 0, $showfeedback);
ddff2fa8 436
d08787af
PS
437 // delete group pictures and descriptions
438 $context = get_context_instance(CONTEXT_COURSE, $courseid);
439 $fs = get_file_storage();
440 $fs->delete_area_files($context->id, 'group');
ddff2fa8 441
0b5a80a1 442 // delete group calendar events
dfdaabd6 443 $groupssql = "SELECT id FROM {groups} g WHERE g.courseid = ?";
444 $DB->delete_records_select('event', "groupid IN ($groupssql)", array($courseid));
0b5a80a1 445
64f93798
PS
446 $context = get_context_instance(CONTEXT_COURSE, $courseid);
447 $fs = get_file_storage();
448 $fs->delete_area_files($context->id, 'group');
449
dfdaabd6 450 $DB->delete_records('groups', array('courseid'=>$courseid));
2942a5cd 451
452 //trigger groups events
453 events_trigger('groups_groups_deleted', $courseid);
454
ddff2fa8 455 if ($showfeedback) {
a1c54f7a 456 echo $OUTPUT->notification(get_string('deleted').' groups');
ddff2fa8 457 }
458
459 return true;
460}
461
f16fa0a3 462/**
463 * Delete all groupings from course
464 * @param int $courseid
465 * @param bool $showfeedback
466 * @return bool success
467 */
ddff2fa8 468function groups_delete_groupings($courseid, $showfeedback=false) {
a1c54f7a 469 global $DB, $OUTPUT;
ddff2fa8 470
d08787af
PS
471 $context = get_context_instance(CONTEXT_COURSE, $courseid);
472 $fs = get_file_storage();
473
ddff2fa8 474 // delete any uses of groupings
dfdaabd6 475 $sql = "DELETE FROM {groupings_groups}
476 WHERE groupingid in (SELECT id FROM {groupings} g WHERE g.courseid = ?)";
477 $DB->execute($sql, array($courseid));
ddff2fa8 478
479 // remove the default groupingid from course
dfdaabd6 480 $DB->set_field('course', 'defaultgroupingid', 0, array('id'=>$courseid));
ddff2fa8 481 // remove the groupingid from all course modules
dfdaabd6 482 $DB->set_field('course_modules', 'groupingid', 0, array('course'=>$courseid));
ddff2fa8 483
8bdc9cac 484 // Delete all files associated with groupings for this course
70e0f41e 485 $context = get_context_instance(CONTEXT_COURSE, $courseid);
8bdc9cac 486 $fs = get_file_storage();
64f93798
PS
487 $fs->delete_area_files($context->id, 'grouping');
488
489 $DB->delete_records('groupings', array('courseid'=>$courseid));
8bdc9cac 490
2942a5cd 491 //trigger groups events
492 events_trigger('groups_groupings_deleted', $courseid);
493
ddff2fa8 494 if ($showfeedback) {
a1c54f7a 495 echo $OUTPUT->notification(get_string('deleted').' groupings');
ddff2fa8 496 }
497
498 return true;
499}
500
501/* =================================== */
502/* various functions used by groups UI */
503/* =================================== */
504
e254aa34 505/**
506 * Obtains a list of the possible roles that group members might come from,
df997f84 507 * on a course. Generally this includes only profile roles.
e254aa34 508 * @param object $context Context of course
509 * @return Array of role ID integers, or false if error/none.
510 */
511function groups_get_possible_roles($context) {
df997f84
PS
512 $roles = get_profile_roles($context);
513 return array_keys($roles);
acf000b0 514}
515
516
517/**
518 * Gets potential group members for grouping
519 * @param int $courseid The id of the course
520 * @param int $roleid The role to select users from
92343cd2 521 * @param int $cohortid restrict to cohort id
64fa9aa7 522 * @param string $orderby The column to sort users by
acf000b0 523 * @return array An array of the users
524 */
92343cd2 525function groups_get_potential_members($courseid, $roleid = null, $cohortid = null, $orderby = 'lastname ASC, firstname ASC') {
4454447d 526 global $DB;
f16fa0a3 527
acf000b0 528 $context = get_context_instance(CONTEXT_COURSE, $courseid);
acf000b0 529
530 // we are looking for all users with this role assigned in this context or higher
4f0c2d00 531 $listofcontexts = get_related_contexts_string($context);
f16fa0a3 532
4f0c2d00 533 list($esql, $params) = get_enrolled_sql($context);
64f93798 534
acf000b0 535 if ($roleid) {
dfdaabd6 536 $params['roleid'] = $roleid;
4f0c2d00
PS
537 $where = "WHERE u.id IN (SELECT userid
538 FROM {role_assignments}
539 WHERE roleid = :roleid AND contextid $listofcontexts)";
acf000b0 540 } else {
4f0c2d00 541 $where = "";
acf000b0 542 }
f16fa0a3 543
92343cd2 544 if ($cohortid) {
d490ca81
PS
545 $cohortjoin = "JOIN {cohort_members} cm ON (cm.userid = u.id AND cm.cohortid = :cohortid)";
546 $params['cohortid'] = $cohortid;
92343cd2
PS
547 } else {
548 $cohortjoin = "";
549 }
550
dfdaabd6 551 $sql = "SELECT u.id, u.username, u.firstname, u.lastname, u.idnumber
552 FROM {user} u
4f0c2d00 553 JOIN ($esql) e ON e.id = u.id
92343cd2 554 $cohortjoin
4f0c2d00 555 $where
dfdaabd6 556 ORDER BY $orderby";
f16fa0a3 557
dfdaabd6 558 return $DB->get_records_sql($sql, $params);
f16fa0a3 559
acf000b0 560}
f3f7610c 561
acf000b0 562/**
563 * Parse a group name for characters to replace
564 * @param string $format The format a group name will follow
565 * @param int $groupnumber The number of the group to be used in the parsed format string
566 * @return string the parsed format string
567 */
568function groups_parse_name($format, $groupnumber) {
acf000b0 569 if (strstr($format, '@') !== false) { // Convert $groupnumber to a character series
f16fa0a3 570 $letter = 'A';
571 for($i=0; $i<$groupnumber; $i++) {
572 $letter++;
acf000b0 573 }
f16fa0a3 574 $str = str_replace('@', $letter, $format);
acf000b0 575 } else {
4454447d 576 $str = str_replace('#', $groupnumber+1, $format);
acf000b0 577 }
578 return($str);
ddff2fa8 579}
f3f7610c 580
f16fa0a3 581/**
582 * Assigns group into grouping
583 * @param int groupingid
584 * @param int groupid
b25263ff 585 * @return bool true or exception
f16fa0a3 586 */
587function groups_assign_grouping($groupingid, $groupid) {
dfdaabd6 588 global $DB;
589
590 if ($DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
f16fa0a3 591 return true;
592 }
ace9051c 593 $assign = new stdClass();
f16fa0a3 594 $assign->groupingid = $groupingid;
dfdaabd6 595 $assign->groupid = $groupid;
596 $assign->timeadded = time();
b25263ff 597 $DB->insert_record('groupings_groups', $assign);
598
599 return true;
f16fa0a3 600}
601
602/**
603 * Unassigns group grom grouping
604 * @param int groupingid
605 * @param int groupid
606 * @return bool success
607 */
608function groups_unassign_grouping($groupingid, $groupid) {
dfdaabd6 609 global $DB;
b25263ff 610 $DB->delete_records('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid));
dfdaabd6 611
b25263ff 612 return true;
f16fa0a3 613}
614
e254aa34 615/**
616 * Lists users in a group based on their role on the course.
6f5e0852 617 * Returns false if there's an error or there are no users in the group.
e254aa34 618 * Otherwise returns an array of role ID => role data, where role data includes:
619 * (role) $id, $shortname, $name
620 * $users: array of objects for each user which include the specified fields
621 * Users who do not have a role are stored in the returned array with key '-'
622 * and pseudo-role details (including a name, 'No role'). Users with multiple
623 * roles, same deal with key '*' and name 'Multiple roles'. You can find out
624 * which roles each has by looking in the $roles array of the user object.
625 * @param int $groupid
626 * @param int $courseid Course ID (should match the group's course)
627 * @param string $fields List of fields from user table prefixed with u, default 'u.*'
628 * @param string $sort SQL ORDER BY clause, default 'u.lastname ASC'
97873016 629 * @param string $extrawheretest extra SQL conditions ANDed with the existing where clause.
4f0c2d00 630 * @param array $whereparams any parameters required by $extrawheretest (named parameters).
e254aa34 631 * @return array Complex array as described above
632 */
97873016 633function groups_get_members_by_role($groupid, $courseid, $fields='u.*',
634 $sort='u.lastname ASC', $extrawheretest='', $whereparams=array()) {
dfdaabd6 635 global $CFG, $DB;
e254aa34 636
637 // Retrieve information about all users and their roles on the course or
6f5e0852 638 // parent ('related') contexts
dfdaabd6 639 $context = get_context_instance(CONTEXT_COURSE, $courseid);
640
97873016 641 if ($extrawheretest) {
642 $extrawheretest = ' AND ' . $extrawheretest;
643 }
644
dfdaabd6 645 $sql = "SELECT r.id AS roleid, r.shortname AS roleshortname, r.name AS rolename,
646 u.id AS userid, $fields
647 FROM {groups_members} gm
648 JOIN {user} u ON u.id = gm.userid
6f5e0852 649 JOIN {role_assignments} ra ON ra.userid = u.id
dfdaabd6 650 JOIN {role} r ON r.id = ra.roleid
4f0c2d00 651 WHERE gm.groupid=:mgroupid
97873016 652 AND ra.contextid ".get_related_contexts_string($context).
653 $extrawheretest."
dfdaabd6 654 ORDER BY r.sortorder, $sort";
4f0c2d00 655 $whereparams['mgroupid'] = $groupid;
97873016 656 $rs = $DB->get_recordset_sql($sql, $whereparams);
dfdaabd6 657
658 return groups_calculate_role_people($rs, $context);
e254aa34 659}
660
661/**
662 * Internal function used by groups_get_members_by_role to handle the
663 * results of a database query that includes a list of users and possible
664 * roles on a course.
665 *
666 * @param object $rs The record set (may be false)
3540f2b3 667 * @param int $contextid ID of course context
6f5e0852 668 * @return array As described in groups_get_members_by_role
e254aa34 669 */
dfdaabd6 670function groups_calculate_role_people($rs, $context) {
671 global $CFG, $DB;
672
673 if (!$rs) {
674 return array();
3540f2b3 675 }
e254aa34 676
dfdaabd6 677 $roles = $DB->get_records_menu('role', null, 'name', 'id, name');
678 $aliasnames = role_fix_names($roles, $context);
679
e254aa34 680 // Array of all involved roles
dfdaabd6 681 $roles = array();
e254aa34 682 // Array of all retrieved users
dfdaabd6 683 $users = array();
e254aa34 684 // Fill arrays
dfdaabd6 685 foreach ($rs as $rec) {
e254aa34 686 // Create information about user if this is a new one
dfdaabd6 687 if (!array_key_exists($rec->userid, $users)) {
e254aa34 688 // User data includes all the optional fields, but not any of the
689 // stuff we added to get the role details
690 $userdata=clone($rec);
691 unset($userdata->roleid);
692 unset($userdata->roleshortname);
693 unset($userdata->rolename);
694 unset($userdata->userid);
dfdaabd6 695 $userdata->id = $rec->userid;
e254aa34 696
697 // Make an array to hold the list of roles for this user
dfdaabd6 698 $userdata->roles = array();
699 $users[$rec->userid] = $userdata;
e254aa34 700 }
701 // If user has a role...
dfdaabd6 702 if (!is_null($rec->roleid)) {
e254aa34 703 // Create information about role if this is a new one
dfdaabd6 704 if (!array_key_exists($rec->roleid,$roles)) {
ace9051c 705 $roledata = new stdClass();
dfdaabd6 706 $roledata->id = $rec->roleid;
707 $roledata->shortname = $rec->roleshortname;
708 if (array_key_exists($rec->roleid, $aliasnames)) {
709 $roledata->name = $aliasnames[$rec->roleid];
3540f2b3 710 } else {
dfdaabd6 711 $roledata->name = $rec->rolename;
3540f2b3 712 }
dfdaabd6 713 $roledata->users = array();
714 $roles[$roledata->id] = $roledata;
e254aa34 715 }
716 // Record that user has role
717 $users[$rec->userid]->roles[] = $roles[$rec->roleid];
718 }
719 }
dfdaabd6 720 $rs->close();
e254aa34 721
722 // Return false if there weren't any users
dfdaabd6 723 if (count($users)==0) {
e254aa34 724 return false;
725 }
726
727 // Add pseudo-role for multiple roles
ace9051c 728 $roledata = new stdClass();
dfdaabd6 729 $roledata->name = get_string('multipleroles','role');
730 $roledata->users = array();
731 $roles['*'] = $roledata;
e254aa34 732
733 // Now we rearrange the data to store users by role
dfdaabd6 734 foreach ($users as $userid=>$userdata) {
735 $rolecount = count($userdata->roles);
736 if ($rolecount==0) {
e254aa34 737 debugging("Unexpected: user $userid is missing roles");
738 } else if($rolecount>1) {
dfdaabd6 739 $roleid = '*';
e254aa34 740 } else {
dfdaabd6 741 $roleid = $userdata->roles[0]->id;
e254aa34 742 }
dfdaabd6 743 $roles[$roleid]->users[$userid] = $userdata;
e254aa34 744 }
745
746 // Delete roles not used
dfdaabd6 747 foreach ($roles as $key=>$roledata) {
748 if (count($roledata->users)===0) {
e254aa34 749 unset($roles[$key]);
750 }
751 }
752
753 // Return list of roles containing their users
754 return $roles;
755}