weekly release 2.2dev
[moodle.git] / lib / grouplib.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
20  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21  * @package    core
22  * @subpackage group
23  */
25 defined('MOODLE_INTERNAL') || die();
27 /**
28  * Groups not used in course or activity
29  */
30 define('NOGROUPS', 0);
32 /**
33  * Groups used, users do not see other groups
34  */
35 define('SEPARATEGROUPS', 1);
37 /**
38  * Groups used, students see other groups
39  */
40 define('VISIBLEGROUPS', 2);
43 /**
44  * Determines if a group with a given groupid exists.
45  *
46  * @global object
47  * @param int $groupid The groupid to check for
48  * @return boolean True if the group exists, false otherwise or if an error
49  * occurred.
50  */
51 function groups_group_exists($groupid) {
52     global $DB;
53     return $DB->record_exists('groups', array('id'=>$groupid));
54 }
56 /**
57  * Gets the name of a group with a specified id
58  *
59  * @global object
60  * @param int $groupid The id of the group
61  * @return string The name of the group
62  */
63 function groups_get_group_name($groupid) {
64     global $DB;
65     return $DB->get_field('groups', 'name', array('id'=>$groupid));
66 }
68 /**
69  * Gets the name of a grouping with a specified id
70  *
71  * @global object
72  * @param int $groupingid The id of the grouping
73  * @return string The name of the grouping
74  */
75 function groups_get_grouping_name($groupingid) {
76     global $DB;
77     return $DB->get_field('groupings', 'name', array('id'=>$groupingid));
78 }
80 /**
81  * Returns the groupid of a group with the name specified for the course.
82  * Group names should be unique in course
83  *
84  * @global object
85  * @param int $courseid The id of the course
86  * @param string $name name of group (without magic quotes)
87  * @return int $groupid
88  */
89 function groups_get_group_by_name($courseid, $name) {
90     global $DB;
91     if ($groups = $DB->get_records('groups', array('courseid'=>$courseid, 'name'=>$name))) {
92         return key($groups);
93     }
94     return false;
95 }
97 /**
98  * Returns the groupingid of a grouping with the name specified for the course.
99  * Grouping names should be unique in course
100  *
101  * @global object
102  * @param int $courseid The id of the course
103  * @param string $name name of group (without magic quotes)
104  * @return int $groupid
105  */
106 function groups_get_grouping_by_name($courseid, $name) {
107     global $DB;
108     if ($groupings = $DB->get_records('groupings', array('courseid'=>$courseid, 'name'=>$name))) {
109         return key($groupings);
110     }
111     return false;
114 /**
115  * Get the group object
116  *
117  * @param int $groupid ID of the group.
118  * @return object group object
119  */
120 function groups_get_group($groupid, $fields='*', $strictness=IGNORE_MISSING) {
121     global $DB;
122     return $DB->get_record('groups', array('id'=>$groupid), $fields, $strictness);
125 /**
126  * Get the grouping object
127  *
128  * @param int $groupingid ID of the group.
129  * @param string $fields
130  * @return object group object
131  */
132 function groups_get_grouping($groupingid, $fields='*', $strictness=IGNORE_MISSING) {
133     global $DB;
134     return $DB->get_record('groupings', array('id'=>$groupingid), $fields, $strictness);
137 /**
138  * Gets array of all groups in a specified course.
139  *
140  * @param int $courseid The id of the course.
141  * @param mixed $userid optional user id or array of ids, returns only groups of the user.
142  * @param int $groupingid optional returns only groups in the specified grouping.
143  * @param string $fields
144  * @return array Returns an array of the group objects (userid field returned if array in $userid)
145  */
146 function groups_get_all_groups($courseid, $userid=0, $groupingid=0, $fields='g.*') {
147     global $DB;
149     if (empty($userid)) {
150         $userfrom  = "";
151         $userwhere = "";
152         $params = array();
154     } else {
155         list($usql, $params) = $DB->get_in_or_equal($userid);
156         $userfrom  = ", {groups_members} gm";
157         $userwhere = "AND g.id = gm.groupid AND gm.userid $usql";
158     }
160     if (!empty($groupingid)) {
161         $groupingfrom  = ", {groupings_groups} gg";
162         $groupingwhere = "AND g.id = gg.groupid AND gg.groupingid = ?";
163         $params[] = $groupingid;
164     } else {
165         $groupingfrom  = "";
166         $groupingwhere = "";
167     }
169     array_unshift($params, $courseid);
171     return $DB->get_records_sql("SELECT $fields
172                                    FROM {groups} g $userfrom $groupingfrom
173                                   WHERE g.courseid = ? $userwhere $groupingwhere
174                                ORDER BY name ASC", $params);
177 /**
178  * Returns info about user's groups in course.
179  *
180  * @param int $courseid
181  * @param int $userid $USER if not specified
182  * @return array Array[groupingid][groupid] including grouping id 0 which means all groups
183  */
184 function groups_get_user_groups($courseid, $userid=0) {
185     global $USER, $DB;
187     if (empty($userid)) {
188         $userid = $USER->id;
189     }
191     $sql = "SELECT g.id, gg.groupingid
192               FROM {groups} g
193                    JOIN {groups_members} gm   ON gm.groupid = g.id
194               LEFT JOIN {groupings_groups} gg ON gg.groupid = g.id
195              WHERE gm.userid = ? AND g.courseid = ?";
196     $params = array($userid, $courseid);
198     $rs = $DB->get_recordset_sql($sql, $params);
200     if (!$rs->valid()) {
201         $rs->close(); // Not going to iterate (but exit), close rs
202         return array('0' => array());
203     }
205     $result    = array();
206     $allgroups = array();
208     foreach ($rs as $group) {
209         $allgroups[$group->id] = $group->id;
210         if (is_null($group->groupingid)) {
211             continue;
212         }
213         if (!array_key_exists($group->groupingid, $result)) {
214             $result[$group->groupingid] = array();
215         }
216         $result[$group->groupingid][$group->id] = $group->id;
217     }
218     $rs->close();
220     $result['0'] = array_keys($allgroups); // all groups
222     return $result;
225 /**
226  * Gets array of all groupings in a specified course.
227  *
228  * @global object
229  * @global object
230  * @param int $courseid return only groupings in this with this courseid
231  * @return array|bool Returns an array of the grouping objects or false if no records
232  * or an error occurred.
233  */
234 function groups_get_all_groupings($courseid) {
235     global $CFG, $DB;
237     return $DB->get_records_sql("SELECT *
238                                    FROM {groupings}
239                                   WHERE courseid = ?
240                                ORDER BY name ASC", array($courseid));
245 /**
246  * Determines if the user is a member of the given group.
247  *
248  * If $userid is null, use the global object.
249  *
250  * @global object
251  * @global object
252  * @param int $groupid The group to check for membership.
253  * @param int $userid The user to check against the group.
254  * @return boolean True if the user is a member, false otherwise.
255  */
256 function groups_is_member($groupid, $userid=null) {
257     global $USER, $DB;
259     if (!$userid) {
260         $userid = $USER->id;
261     }
263     return $DB->record_exists('groups_members', array('groupid'=>$groupid, 'userid'=>$userid));
266 /**
267  * Determines if current or specified is member of any active group in activity
268  *
269  * @global object
270  * @global object
271  * @global object
272  * @staticvar array $cache
273  * @param object $cm coruse module object
274  * @param int $userid id of user, null menas $USER->id
275  * @return booelan true if user member of at least one group used in activity
276  */
277 function groups_has_membership($cm, $userid=null) {
278     global $CFG, $USER, $DB;
280     static $cache = array();
282     if (empty($userid)) {
283         $userid = $USER->id;
284     }
286     $cachekey = $userid.'|'.$cm->course.'|'.$cm->groupingid;
287     if (isset($cache[$cachekey])) {
288         return($cache[$cachekey]);
289     }
291     if ($cm->groupingid) {
292         // find out if member of any group in selected activity grouping
293         $sql = "SELECT 'x'
294                   FROM {groups_members} gm, {groupings_groups} gg
295                  WHERE gm.userid = ? AND gm.groupid = gg.groupid AND gg.groupingid = ?";
296         $params = array($userid, $cm->groupingid);
298     } else {
299         // no grouping used - check all groups in course
300         $sql = "SELECT 'x'
301                   FROM {groups_members} gm, {groups} g
302                  WHERE gm.userid = ? AND gm.groupid = g.id AND g.courseid = ?";
303         $params = array($userid, $cm->course);
304     }
306     $cache[$cachekey] = $DB->record_exists_sql($sql, $params);
308     return $cache[$cachekey];
311 /**
312  * Returns the users in the specified group.
313  *
314  * @global object
315  * @param int $groupid The groupid to get the users for
316  * @param int $fields The fields to return
317  * @param int $sort optional sorting of returned users
318  * @return array|bool Returns an array of the users for the specified
319  * group or false if no users or an error returned.
320  */
321 function groups_get_members($groupid, $fields='u.*', $sort='lastname ASC') {
322     global $DB;
324     return $DB->get_records_sql("SELECT $fields
325                                    FROM {user} u, {groups_members} gm
326                                   WHERE u.id = gm.userid AND gm.groupid = ?
327                                ORDER BY $sort", array($groupid));
331 /**
332  * Returns the users in the specified grouping.
333  *
334  * @global object
335  * @param int $groupingid The groupingid to get the users for
336  * @param int $fields The fields to return
337  * @param int $sort optional sorting of returned users
338  * @return array|bool Returns an array of the users for the specified
339  * group or false if no users or an error returned.
340  */
341 function groups_get_grouping_members($groupingid, $fields='u.*', $sort='lastname ASC') {
342     global $DB;
344     return $DB->get_records_sql("SELECT $fields
345                                    FROM {user} u
346                                      INNER JOIN {groups_members} gm ON u.id = gm.userid
347                                      INNER JOIN {groupings_groups} gg ON gm.groupid = gg.groupid
348                                   WHERE  gg.groupingid = ?
349                                ORDER BY $sort", array($groupingid));
352 /**
353  * Returns effective groupmode used in course
354  *
355  * @return integer group mode
356  */
357 function groups_get_course_groupmode($course) {
358     return $course->groupmode;
361 /**
362  * Returns effective groupmode used in activity, course setting
363  * overrides activity setting if groupmodeforce enabled.
364  *
365  * @global object
366  * @global object
367  * @param object $cm the course module object. Only the ->course and ->groupmode need to be set.
368  * @param object $course object optional course object to improve perf
369  * @return integer group mode
370  */
371 function groups_get_activity_groupmode($cm, $course=null) {
372     global $COURSE, $DB;
374     // get course object (reuse COURSE if possible)
375     if (isset($course->id) and $course->id == $cm->course) {
376         //ok
377     } else if ($cm->course == $COURSE->id) {
378         $course = $COURSE;
379     } else {
380         if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
381             print_error('invalidcourseid');
382         }
383     }
385     return empty($course->groupmodeforce) ? $cm->groupmode : $course->groupmode;
388 /**
389  * Print group menu selector for course level.
390  *
391  * @param stdClass $course course object
392  * @param string|moodle_url $urlroot return address
393  * @param boolean $return return as string instead of printing
394  * @return mixed void or string depending on $return param
395  */
396 function groups_print_course_menu($course, $urlroot, $return=false) {
397     global $USER, $OUTPUT;
399     if (!$groupmode = $course->groupmode) {
400         if ($return) {
401             return '';
402         } else {
403             return;
404         }
405     }
407     $context = get_context_instance(CONTEXT_COURSE, $course->id);
408     $aag = has_capability('moodle/site:accessallgroups', $context);
410     if ($groupmode == VISIBLEGROUPS or $aag) {
411         $allowedgroups = groups_get_all_groups($course->id, 0, $course->defaultgroupingid);
412     } else {
413         $allowedgroups = groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid);
414     }
416     $activegroup = groups_get_course_group($course, true, $allowedgroups);
418     $groupsmenu = array();
419     if (!$allowedgroups or $groupmode == VISIBLEGROUPS or $aag) {
420         $groupsmenu[0] = get_string('allparticipants');
421     }
423     if ($allowedgroups) {
424         foreach ($allowedgroups as $group) {
425             $groupsmenu[$group->id] = format_string($group->name);
426         }
427     }
429     if ($groupmode == VISIBLEGROUPS) {
430         $grouplabel = get_string('groupsvisible');
431     } else {
432         $grouplabel = get_string('groupsseparate');
433     }
435     if ($aag and $course->defaultgroupingid) {
436         if ($grouping = groups_get_grouping($course->defaultgroupingid)) {
437             $grouplabel = $grouplabel . ' (' . format_string($grouping->name) . ')';
438         }
439     }
441     if (count($groupsmenu) == 1) {
442         $groupname = reset($groupsmenu);
443         $output = $grouplabel.': '.$groupname;
444     } else {
445         $select = new single_select(new moodle_url($urlroot), 'group', $groupsmenu, $activegroup, null, 'selectgroup');
446         $select->label = $grouplabel;
447         $output = $OUTPUT->render($select);
448     }
450     $output = '<div class="groupselector">'.$output.'</div>';
452     if ($return) {
453         return $output;
454     } else {
455         echo $output;
456     }
459 /**
460  * Print group menu selector for activity.
461  *
462  * @param stdClass $cm course module object
463  * @param string|moodle_url $urlroot return address that users get to if they choose an option;
464  *   should include any parameters needed, e.g. "$CFG->wwwroot/mod/forum/view.php?id=34"
465  * @param boolean $return return as string instead of printing
466  * @param boolean $hideallparticipants If true, this prevents the 'All participants'
467  *   option from appearing in cases where it normally would. This is intended for
468  *   use only by activities that cannot display all groups together. (Note that
469  *   selecting this option does not prevent groups_get_activity_group from
470  *   returning 0; it will still do that if the user has chosen 'all participants'
471  *   in another activity, or not chosen anything.)
472  * @return mixed void or string depending on $return param
473  */
474 function groups_print_activity_menu($cm, $urlroot, $return=false, $hideallparticipants=false) {
475     global $USER, $OUTPUT;
477     if ($urlroot instanceof moodle_url) {
478         // no changes necessary
480     } else {
481         if (strpos($urlroot, 'http') !== 0) { // Will also work for https
482             // Display error if urlroot is not absolute (this causes the non-JS version to break)
483             debugging('groups_print_activity_menu requires absolute URL for ' .
484                       '$urlroot, not <tt>' . s($urlroot) . '</tt>. Example: ' .
485                       'groups_print_activity_menu($cm, $CFG->wwwroot . \'/mod/mymodule/view.php?id=13\');',
486                       DEBUG_DEVELOPER);
487         }
488         $urlroot = new moodle_url($urlroot);
489     }
491     if (!$groupmode = groups_get_activity_groupmode($cm)) {
492         if ($return) {
493             return '';
494         } else {
495             return;
496         }
497     }
499     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
500     $aag = has_capability('moodle/site:accessallgroups', $context);
502     if ($groupmode == VISIBLEGROUPS or $aag) {
503         $allowedgroups = groups_get_all_groups($cm->course, 0, $cm->groupingid); // any group in grouping
504     } else {
505         $allowedgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid); // only assigned groups
506     }
508     $activegroup = groups_get_activity_group($cm, true, $allowedgroups);
510     $groupsmenu = array();
511     if ((!$allowedgroups or $groupmode == VISIBLEGROUPS or $aag) and !$hideallparticipants) {
512         $groupsmenu[0] = get_string('allparticipants');
513     }
515     if ($allowedgroups) {
516         foreach ($allowedgroups as $group) {
517             $groupsmenu[$group->id] = format_string($group->name);
518         }
519     }
521     if ($groupmode == VISIBLEGROUPS) {
522         $grouplabel = get_string('groupsvisible');
523     } else {
524         $grouplabel = get_string('groupsseparate');
525     }
527     if ($aag and $cm->groupingid) {
528         if ($grouping = groups_get_grouping($cm->groupingid)) {
529             $grouplabel = $grouplabel . ' (' . format_string($grouping->name) . ')';
530         }
531     }
533     if (count($groupsmenu) == 1) {
534         $groupname = reset($groupsmenu);
535         $output = $grouplabel.': '.$groupname;
536     } else {
537         $select = new single_select($urlroot, 'group', $groupsmenu, $activegroup, null, 'selectgroup');
538         $select->label = $grouplabel;
539         $output = $OUTPUT->render($select);
540     }
542     $output = '<div class="groupselector">'.$output.'</div>';
544     if ($return) {
545         return $output;
546     } else {
547         echo $output;
548     }
551 /**
552  * Returns group active in course, changes the group by default if 'group' page param present
553  *
554  * @param stdClass $course course bject
555  * @param boolean $update change active group if group param submitted
556  * @param array $allowedgroups list of groups user may access (INTERNAL, to be used only from groups_print_course_menu())
557  * @return mixed false if groups not used, int if groups used, 0 means all groups (access must be verified in SEPARATE mode)
558  */
559 function groups_get_course_group($course, $update=false, $allowedgroups=null) {
560     global $USER, $SESSION;
562     if (!$groupmode = $course->groupmode) {
563         // NOGROUPS used
564         return false;
565     }
567     $context = get_context_instance(CONTEXT_COURSE, $course->id);
568     if (has_capability('moodle/site:accessallgroups', $context)) {
569         $groupmode = 'aag';
570     }
572     if (!is_array($allowedgroups)) {
573         if ($groupmode == VISIBLEGROUPS or $groupmode === 'aag') {
574             $allowedgroups = groups_get_all_groups($course->id, 0, $course->defaultgroupingid);
575         } else {
576             $allowedgroups = groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid);
577         }
578     }
580     _group_verify_activegroup($course->id, $groupmode, $course->defaultgroupingid, $allowedgroups);
582     // set new active group if requested
583     $changegroup = optional_param('group', -1, PARAM_INT);
584     if ($update and $changegroup != -1) {
586         if ($changegroup == 0) {
587             // do not allow changing to all groups without accessallgroups capability
588             if ($groupmode == VISIBLEGROUPS or $groupmode === 'aag') {
589                 $SESSION->activegroup[$course->id][$groupmode][$course->defaultgroupingid] = 0;
590             }
592         } else {
593             if ($allowedgroups and array_key_exists($changegroup, $allowedgroups)) {
594                 $SESSION->activegroup[$course->id][$groupmode][$course->defaultgroupingid] = $changegroup;
595             }
596         }
597     }
599     return $SESSION->activegroup[$course->id][$groupmode][$course->defaultgroupingid];
602 /**
603  * Returns group active in activity, changes the group by default if 'group' page param present
604  *
605  * @param stdClass $cm course module object
606  * @param boolean $update change active group if group param submitted
607  * @param array $allowedgroups list of groups user may access (INTERNAL, to be used only from groups_print_activity_menu())
608  * @return mixed false if groups not used, int if groups used, 0 means all groups (access must be verified in SEPARATE mode)
609  */
610 function groups_get_activity_group($cm, $update=false, $allowedgroups=null) {
611     global $USER, $SESSION;
613     if (!$groupmode = groups_get_activity_groupmode($cm)) {
614         // NOGROUPS used
615         return false;
616     }
618     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
619     if (has_capability('moodle/site:accessallgroups', $context)) {
620         $groupmode = 'aag';
621     }
623     if (!is_array($allowedgroups)) {
624         if ($groupmode == VISIBLEGROUPS or $groupmode === 'aag') {
625             $allowedgroups = groups_get_all_groups($cm->course, 0, $cm->groupingid);
626         } else {
627             $allowedgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid);
628         }
629     }
631     _group_verify_activegroup($cm->course, $groupmode, $cm->groupingid, $allowedgroups);
633     // set new active group if requested
634     $changegroup = optional_param('group', -1, PARAM_INT);
635     if ($update and $changegroup != -1) {
637         if ($changegroup == 0) {
638             // allgroups visible only in VISIBLEGROUPS or when accessallgroups
639             if ($groupmode == VISIBLEGROUPS or $groupmode === 'aag') {
640                 $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = 0;
641             }
643         } else {
644             if ($allowedgroups and array_key_exists($changegroup, $allowedgroups)) {
645                 $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = $changegroup;
646             }
647         }
648     }
650     return $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid];
653 /**
654  * Gets a list of groups that the user is allowed to access within the
655  * specified activity.
656  *
657  * @param object $cm Course-module
658  * @param int $userid User ID (defaults to current user)
659  * @return array An array of group objects, or false if none
660  */
661 function groups_get_activity_allowed_groups($cm,$userid=0) {
662     // Use current user by default
663     global $USER;
664     if(!$userid) {
665         $userid=$USER->id;
666     }
668     // Get groupmode for activity, taking into account course settings
669     $groupmode=groups_get_activity_groupmode($cm);
671     // If visible groups mode, or user has the accessallgroups capability,
672     // then they can access all groups for the activity...
673     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
674     if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
675         return groups_get_all_groups($cm->course, 0, $cm->groupingid);
676     } else {
677         // ...otherwise they can only access groups they belong to
678         return groups_get_all_groups($cm->course, $userid, $cm->groupingid);
679     }
682 /**
683  * Determine if a course module is currently visible to a user
684  *
685  * $USER If $userid is null, use the global object.
686  *
687  * @param int $cm The course module
688  * @param int $userid The user to check against the group.
689  * @return boolean True if the user can view the course module, false otherwise.
690  */
691 function groups_course_module_visible($cm, $userid=null) {
692     global $CFG, $USER;
694     if (empty($userid)) {
695         $userid = $USER->id;
696     }
697     if (empty($CFG->enablegroupmembersonly)) {
698         return true;
699     }
700     if (empty($cm->groupmembersonly)) {
701         return true;
702     }
703     if (has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id), $userid) or groups_has_membership($cm, $userid)) {
704         return true;
705     }
706     return false;
709 /**
710  * Internal method, sets up $SESSION->activegroup and verifies previous value
711  *
712  * @private
713  * @param int $courseid
714  * @param int|string $groupmode SEPARATEGROUPS, VISIBLEGROUPS or 'aag' (access all groups)
715  * @param int $groupingid 0 means all groups
716  * @param all $allowedgroups list of groups user can see
717  * @return void
718  */
719 function _group_verify_activegroup($courseid, $groupmode, $groupingid, array $allowedgroups) {
720     global $SESSION;
722     // init activegroup array if necessary
723     if (!isset($SESSION->activegroup)) {
724         $SESSION->activegroup = array();
725     }
726     if (!array_key_exists($courseid, $SESSION->activegroup)) {
727         $SESSION->activegroup[$courseid] = array(SEPARATEGROUPS=>array(), VISIBLEGROUPS=>array(), 'aag'=>array());
728     }
730     // make sure that the current group info is ok
731     if (array_key_exists($groupingid, $SESSION->activegroup[$courseid][$groupmode]) and !array_key_exists($SESSION->activegroup[$courseid][$groupmode][$groupingid], $allowedgroups)) {
732         // active group does not exist anymore or is 0
733         if ($SESSION->activegroup[$courseid][$groupmode][$groupingid] > 0 or $groupmode == SEPARATEGROUPS) {
734             // do not do this if all groups selected and groupmode is not separate
735             unset($SESSION->activegroup[$courseid][$groupmode][$groupingid]);
736         }
737     }
739     // set up defaults if necessary
740     if (!array_key_exists($groupingid, $SESSION->activegroup[$courseid][$groupmode])) {
741         if ($groupmode == 'aag') {
742             $SESSION->activegroup[$courseid][$groupmode][$groupingid] = 0; // all groups by default if user has accessallgroups
744         } else if ($allowedgroups) {
745             $firstgroup = reset($allowedgroups);
746             $SESSION->activegroup[$courseid][$groupmode][$groupingid] = $firstgroup->id;
748         } else {
749             // this happen when user not assigned into group in SEPARATEGROUPS mode or groups do not exist yet
750             // mod authors must add extra checks for this when SEPARATEGROUPS mode used (such as when posting to forum)
751             $SESSION->activegroup[$courseid][$groupmode][$groupingid] = 0;
752         }
753     }