mirror of
https://github.com/moodle/moodle.git
synced 2025-08-08 02:16:41 +02:00
250 lines
No EOL
9.9 KiB
PHP
250 lines
No EOL
9.9 KiB
PHP
<?PHP
|
|
|
|
/************************************
|
|
* Automatic group generataion
|
|
************************************/
|
|
|
|
// @@@ TO DO - Some of this code could be simplified a lot I realised
|
|
// after I wrote it and got it working!
|
|
|
|
/**
|
|
* Seeds the random number generator used by groups_create_automatic_grouping.
|
|
* This must be called before using groups_create_automatic_grouping and should
|
|
* only be called once in each script even if you are calling
|
|
* groups_create_automatic_grouping more than once.
|
|
*/
|
|
function groups_seed_random_number_generator() {
|
|
$seed = (double)microtime()*1234567 ;
|
|
srand($seed);
|
|
}
|
|
|
|
|
|
/**
|
|
* Distributes students into groups randomly and creates a grouping with those
|
|
* groups.
|
|
*
|
|
* You need to call groups_seed_random_number_generator() at some point in your
|
|
* script before calling this function.
|
|
*
|
|
* Note that this function does not distribute teachers into groups - this still
|
|
* needs to be done manually.
|
|
*
|
|
* @param int $courseid The id of the course that the grouping should belong to
|
|
* @param int $nostudentspergroup The number of students to put in each group -
|
|
* this can be set to false if you prefer to specify the number of groups
|
|
* instead
|
|
* @param int $nogroups The number of groups - this can be set to false if you
|
|
* prefer to specify the number of student in each group. If both are specified
|
|
* then $nostudentspergroup takes precedence. If neither is
|
|
* specified then the function does nothing and returns false.
|
|
* @param boolean $distribevenly If $noofstudentspergroup is specified, then
|
|
* if this is set to true, any leftover students are distributed evenly among
|
|
* the groups, whereas if it is set to false then they are put in a separate
|
|
* group.
|
|
* @param object $groupsettings The default settings to give each group.
|
|
* This should contain prefix and defaultgroupdescription fields. The groups
|
|
* are named with the prefix followed by 1, 2, etc. and given the
|
|
* default group description set.
|
|
* @param int $groupid If this is not set to false, then only students in the
|
|
* specified group are distributed into groups, not all the students enrolled on
|
|
* the course.
|
|
* @param boolean $alphabetical If this is set to true, then the students are
|
|
* not distributed randomly but in alphabetical order of last name.
|
|
* @return int The id of the grouping
|
|
*/
|
|
function groups_create_automatic_grouping($courseid, $nostudentspergroup,
|
|
$nogroups, $distribevenly,
|
|
$groupingsettings,
|
|
$groupid = false,
|
|
$alphabetical = false) {
|
|
|
|
if (!$nostudentspergroup and !$noteacherspergroup and !$nogroups) {
|
|
$groupingid = false;
|
|
} else {
|
|
// Set $userids to the list of students that we want to put into groups
|
|
// in the grouping
|
|
if (!$groupid) {
|
|
$users = get_course_students($courseid);
|
|
$userids = groups_users_to_userids($users);
|
|
} else {
|
|
$userids = groups_get_members($groupid);
|
|
}
|
|
|
|
// Distribute the users into sets according to the parameters specified
|
|
$userarrays = groups_distribute_in_random_sets($userids,
|
|
$nostudentspergroup, $nogroups, $distribevenly, !$alphabetical);
|
|
|
|
if (!$userarrays) {
|
|
$groupingid = false;
|
|
} else {
|
|
// Create the grouping that the groups we create will go into
|
|
$groupingid = groups_create_grouping($courseid, $groupingsettings);
|
|
|
|
// Get the prefix for the names of each group and default group
|
|
// description to give each group
|
|
if (!$groupingsettings->prefix) {
|
|
$prefix = get_string('defaultgroupprefix', 'groups');
|
|
} else {
|
|
$prefix = $groupingsettings->prefix;
|
|
}
|
|
|
|
if (!$groupingsettings->defaultgroupdescription) {
|
|
$defaultgroupdescription = '';
|
|
} else {
|
|
$defaultgroupdescription = $groupingsettings->defaultgroupdescription;
|
|
}
|
|
|
|
// Now create a group for each set of students, add the group to the
|
|
// grouping and then add the students
|
|
$i = 1;
|
|
foreach ($userarrays as $userids) {
|
|
$groupsettings->name = $prefix.' '.$i;
|
|
$groupsettings->description = $defaultgroupdescription;
|
|
$i++;
|
|
$groupid = groups_create_group($courseid, $groupsettings);
|
|
$groupadded = groups_add_group_to_grouping($groupid,
|
|
$groupingid);
|
|
if (!$groupid or !$groupadded) {
|
|
$groupingid = false;
|
|
} else {
|
|
if ($userids) {
|
|
foreach($userids as $userid) {
|
|
$usersadded = groups_add_member($userid, $groupid);
|
|
// If unsuccessful just carry on I guess
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $groupingid;
|
|
}
|
|
|
|
|
|
/**
|
|
* Takes an array and a set size, puts the elements of the array into an array
|
|
* of arrays of size $setsize randomly.
|
|
* @param array $array The array to distribute into random sets
|
|
* @param int $setsize The size of each set - this can be set to false, if you
|
|
* would prefer to specify the number of sets.
|
|
* @param int $nosets The number of sets - this can be set to false if you would
|
|
* prefer to specify the setsize.
|
|
* If both $setsize and $nosets are set then $setsize takes precedence. If both
|
|
* are set to false then the function does nothing and returns false.
|
|
* @param $distribevenly boolean Determines how extra elements are distributed
|
|
* if $setsize doesn't divide exactly into the number of elements if $setsize is
|
|
* specified. If it is true then extra elements will be distributed evenly
|
|
* amongst the sets, whereas if it is set to false then the remaining elements
|
|
* will be put into a separate set.
|
|
* @param boolean $randomise If this is true then the elements of array will be
|
|
* put into the arrays in a random order, otherwise they will be put into the
|
|
* array in the same order as the original array.
|
|
* @return array The array of arrays of elements generated.
|
|
*/
|
|
function groups_distribute_in_random_sets($array, $setsize, $nosets,
|
|
$distribevenly = true,
|
|
$randomise = true) {
|
|
$noelements = count($array);
|
|
|
|
// Create a list of the numbers 1,..., $noelements, in either random order
|
|
// or in numerical order depending on whether $randomise has been set.
|
|
if ($randomise) {
|
|
$orderarray = groups_random_list($noelements);
|
|
} else {
|
|
// Just create the array (1,2,3,....)
|
|
$orderarray = array();
|
|
for($i = 0; $i < $noelements; $i++) {
|
|
array_push($orderarray, $i);
|
|
}
|
|
}
|
|
|
|
// Now use the ordering in $orderarray to generate the new arrays
|
|
$arrayofrandomsets = array(); //
|
|
|
|
for ($i = 0; $i < $noelements; $i++) {
|
|
$arrayofrandomsets[$arrayno][$i] = $array[$orderarray[$i]];
|
|
if (groups_last_element_in_set($noelements, $setsize, $nosets,
|
|
$distribevenly, $i)
|
|
and $i != $noelements - 1) {
|
|
$arrayno++;
|
|
$arrayofrandomsets[$arrayno] = array();
|
|
}
|
|
|
|
}
|
|
|
|
return $arrayofrandomsets;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of the numbers 0,..,$size - 1 in random order
|
|
* @param int $size the number of numbers to return in a random order
|
|
* @return array The array of numbers in a random order
|
|
*/
|
|
function groups_random_list($size) {
|
|
$orderarray = array();
|
|
$noelementsset = 0;
|
|
while($noelementsset != $size) {
|
|
$newelement = rand() % $size;
|
|
// If the array doesn't already contain the element, add it.
|
|
if (array_search($newelement, $orderarray) === false) {
|
|
array_push($orderarray, $newelement);
|
|
$noelementsset++;
|
|
}
|
|
}
|
|
|
|
return $orderarray;
|
|
}
|
|
|
|
/**
|
|
* A helper function for groups_distribute_in_random_sets().
|
|
* When distributing elements into sets, determines if a given element is the
|
|
* last element in the set.
|
|
* @param int $totalnoelements The total number of elements being distributed.
|
|
* @param int $setsize See groups_distribute_in_random_sets()
|
|
* @param int $nosets See groups_distribute_in_random_sets()
|
|
* @param boolean $distribevenly See groups_distribute_in_random_sets()
|
|
* @param int $elementno The element number that we are considering i.e. if this
|
|
* is the 15th element then this would be 15.
|
|
* @return boolean True if the element under consideration would be the last
|
|
* element in the set, fals otherwise.
|
|
*/
|
|
function groups_last_element_in_set($totalnoelements, $setsize, $nosets,
|
|
$distribevenly, $elementno) {
|
|
$lastelement = false;
|
|
$elementno = $elementno + 1; // Counting from zero is just too confusing!
|
|
|
|
// If $nosets has been specified, make sure $setsize is set to the right
|
|
// value, so that we can treat the two cases identically. Then work out how
|
|
// many extra elements will be left over.
|
|
if (!$setsize) {
|
|
$setsize = floor($totalnoelements / $nosets);
|
|
$noextra = $totalnoelements % $nosets;
|
|
} else {
|
|
$noextra = $totalnoelements % $setsize;
|
|
}
|
|
|
|
if (!$distribevenly) {
|
|
// If we're putting our extra elements in a set at the end, everything
|
|
// is easy!
|
|
if ($elementno % $setsize == 0) {
|
|
$lastelement = true;
|
|
}
|
|
} else {
|
|
// Work out the number of elements that will be in the bigger sets that
|
|
// have the leftover elements in
|
|
// them.
|
|
$noinbiggersets = $noextra * ($setsize + 1);
|
|
// Work out if this element is a last element in a set or not - we need
|
|
// to separate the case where the element is one of the ones that goes
|
|
// into the bigger sets at the beginning
|
|
// and the case where it's one of the elements in the normal sized sets.
|
|
if (($elementno <= $noinbiggersets and $elementno % ($setsize + 1) == 0)
|
|
or ($elementno > $noinbiggersets and
|
|
($elementno - $noinbiggersets ) % $setsize == 0) ) {
|
|
$lastelement = true;
|
|
}
|
|
}
|
|
|
|
return $lastelement;
|
|
}
|
|
?>
|