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