642cbc2e2744fedfbe7012a43dd44e68f23b3e04
[moodle.git] / group / autogroup.php
1 <?php // $Id$
2 /**
3  * Create and allocate users go groups
4  *
5  * @author  Matt Clarkson mattc@catalyst.net.nz
6  * @version 0.0.1
7  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
8  * @package groups
9  */
11 require_once('../config.php');
12 require_once('lib.php');
13 require_once('autogroup_form.php');
15 if (!defined('AUTOGROUP_MIN_RATIO')) {
16     define('AUTOGROUP_MIN_RATIO', 0.7); // means minimum member count is 70% in the smallest group
17 }
19 $courseid = required_param('courseid', PARAM_INT);
21 if (!$course = get_record('course', 'id', $courseid)) {
22     print_error('invalidcourse');
23 }
25 // Make sure that the user has permissions to manage groups.
26 require_login($course);
28 $context       = get_context_instance(CONTEXT_COURSE, $courseid);
29 $systemcontext = get_context_instance(CONTEXT_SYSTEM);
30 require_capability('moodle/course:managegroups', $context);
32 $returnurl = $CFG->wwwroot.'/group/index.php?id='.$course->id;
34 $strgroups           = get_string('groups');
35 $strparticipants     = get_string('participants');
36 $strautocreategroups = get_string('autocreategroups', 'group');
38 // Print the page and form
39 $navlinks = array(array('name'=>$strparticipants, 'link'=>$CFG->wwwroot.'/user/index.php?id='.$courseid, 'type'=>'misc'),
40                   array('name' => $strgroups, 'link' => "$CFG->wwwroot/group/index.php?id=$courseid", 'type' => 'misc'),
41                   array('name' => $strautocreategroups, 'link' => null, 'type' => 'misc'));
42 $navigation = build_navigation($navlinks);
44 $preview = '';
45 $error = '';
47 /// Get applicable roles
48 $rolenames = array();
49 if ($roles = get_roles_used_in_context($context, true)) {
50     $canviewroles    = get_roles_with_capability('moodle/course:view', CAP_ALLOW, $context);
51     $doanythingroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $systemcontext);
53     foreach ($roles as $role) {
54         if (!isset($canviewroles[$role->id])) {   // Avoid this role (eg course creator)
55             continue;
56         }
57         if (isset($doanythingroles[$role->id])) {   // Avoid this role (ie admin)
58             continue;
59         }
60         $rolenames[$role->id] = strip_tags(role_get_name($role, $context));   // Used in menus etc later on
61     }
62 }
64 /// Create the form
65 $editform = new autogroup_form(null, array('roles' => $rolenames));
66 $editform->set_data(array('courseid' => $courseid, 'seed' => time()));
68 /// Handle form submission
69 if ($editform->is_cancelled()) {
70     redirect($returnurl);
72 } elseif ($data = $editform->get_data(false)) {
74     /// Allocate members from the selected role to groups
75     switch ($data->allocateby) {
76         case 'no':
77         case 'random':
78         case 'lastname':
79             $orderby = 'lastname, firstname'; break;
80         case 'firstname':
81             $orderby = 'firstname, lastname'; break;
82         case 'idnumber':
83             $orderby = 'idnumber'; break;
84         default:
85             print_error('Unknown ordering');
86     }
87     $users = groups_get_potential_members($data->courseid, $data->roleid, $orderby);
88     $usercnt = count($users);
90     if ($data->allocateby == 'random') {
91         srand($data->seed);
92         shuffle($users);
93     }
95     $groups = array();
97     // Plan the allocation
98     if ($data->groupby == 'groups') {
99         $numgrps    = $data->number;
100         $userpergrp = floor($usercnt/$numgrps);
102     } else { // members
103         $numgrps    = ceil($usercnt/$data->number);
104         $userpergrp = $data->number;
106         if (!empty($data->nosmallgroups) and $usercnt % $data->number != 0) {
107             // If there would be one group with a small number of member reduce the number of groups
108             $missing = $userpergrp * $numgrps - $usercnt;
109             if ($missing > $userpergrp * (1-AUTOGROUP_MIN_RATIO)) {
110                 // spread the users from the last small group
111                 $numgrps--;
112                 $userpergrp = floor($usercnt/$numgrps);
113             }
114         }
115     }
117     // allocate the users - all groups equal count first
118     for ($i=0; $i<$numgrps; $i++) {
119         $groups[$i] = array();
120         $groups[$i]['name']    = groups_parse_name(trim($data->namingscheme), $i);
121         $groups[$i]['members'] = array();
122         if ($data->allocateby == 'no') {
123             continue; // do not allocate users
124         }
125         for ($j=0; $j<$userpergrp; $j++) {
126             if (empty($users)) {
127                 break 2;
128             }
129             $user = array_shift($users);
130             $groups[$i]['members'][$user->id] = $user;
131         }
132     }
133     // now distribute the rest
134     if ($data->allocateby != 'no') {
135         for ($i=0; $i<$numgrps; $i++) {
136             if (empty($users)) {
137                 break 1;
138             }
139             $user = array_shift($users);
140             $groups[$i]['members'][$user->id] = $user;
141         }
142     }
144     if (isset($data->preview)) {
145         $table = new object();
146         if ($data->allocateby == 'no') {
147             $table->head  = array(get_string('groupscount', 'group', $numgrps));
148             $table->size  = array('100%');
149             $table->align = array('left');
150             $table->width = '40%';
151         } else {
152             $table->head  = array(get_string('groupscount', 'group', $numgrps), get_string('groupmembers', 'group'), get_string('usercounttotal', 'group', $usercnt));
153             $table->size  = array('20%', '70%', '10%');
154             $table->align = array('left', 'left', 'center');
155             $table->width = '90%';
156         }
157         $table->data  = array();
159         foreach ($groups as $group) {
160             $line = array();
161             if (groups_get_group_by_name($courseid, $group['name'])) {
162                 $line[] = '<span class="notifyproblem">'.get_string('groupnameexists', 'group', $group['name']).'</span>';
163                 $error = get_string('groupnameexists', 'group', $group['name']);
164             } else {
165                 $line[] = $group['name'];
166             }
167             if ($data->allocateby != 'no') {
168                 $unames = array();
169                 foreach ($group['members'] as $user) {
170                     $unames[] = fullname($user, true);
171                 }
172                 $line[] = implode(', ', $unames);
173                 $line[] = count($group['members']);
174             }
175             $table->data[] = $line;
176         }
178         $preview .= print_table($table, true);
180     } else {
181         $grouping = null;
182         $createdgrouping = null;
183         $createdgroups = array();
184         $failed = false;
186         // prepare grouping
187         if (!empty($data->grouping)) {
188             $groupingname = trim($data->groupingname);
189             if ($data->grouping < 0) {
190                 $grouping = new object();
191                 $grouping->courseid = $COURSE->id;
192                 $grouping->name     = $groupingname;
193                 if (!$grouping->id = groups_create_grouping(addslashes_recursive($grouping))) {
194                     $error = 'Can not create grouping'; //should not happen
195                     $failed = true;
196                 }
197                 $createdgrouping = $grouping->id;
198             } else {
199                 $grouping = groups_get_grouping($data->grouping);
200             }
201         }
203         // Save the groups data
204         foreach ($groups as $key=>$group) {
205             if (groups_get_group_by_name($courseid, $group['name'])) {
206                 $error = get_string('groupnameexists', 'group', $group['name']);
207                 $failed = true;
208                 break;
209             }
210             $newgroup = new object();
211             $newgroup->courseid = $data->courseid;
212             $newgroup->name     = $group['name'];
213             if (!$groupid = groups_create_group(addslashes_recursive($newgroup))) {
214                 $error = 'Can not create group!'; // should not happen
215                 $failed = true;
216                 break;
217             }
218             $createdgroups[] = $groupid;
219             foreach($group['members'] as $user) {
220                 groups_add_member($groupid, $user->id);
221             }
222             if ($grouping) {
223                 groups_assign_grouping($grouping->id, $groupid);
224             }
225         }
227         if ($failed) {
228             foreach ($createdgroups as $groupid) {
229                 groups_delete_group($groupid);
230             }
231             if ($createdgrouping) {
232                 groups_delete_grouping($createdgrouping);
233             }
234         } else {
235             redirect($returnurl);
236         }
237     }
240 /// Print header
241 print_header_simple($strgroups, ': '.$strgroups, $navigation, '', '', true, '', navmenu($course));
242 print_heading($strautocreategroups);
244 if ($error != '') {
245     notify($error);
248 /// Display the form
249 $editform->display();
251 if($preview !== '') {
252         print_heading(get_string('groupspreview', 'group'));
254     echo $preview;
257 print_footer($course);
258 ?>