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