MDL-67752 course: Improve the average_number_of_participants function

The patch adds two new optional parameters that control the function
behaviour. With default values, the function is backwards compatible and
it simply uses the number of enrolment records. The new parameters allow
to include only active enrolments and/or only recently active users.
This commit is contained in:
David Mudrák 2020-02-26 15:36:26 +01:00
parent 37b2ee3f64
commit c268c1bd3f
2 changed files with 129 additions and 18 deletions

View File

@ -2612,31 +2612,68 @@ function update_course($data, $editoroptions = NULL) {
}
/**
* Average number of participants
* @return integer
* Calculate the average number of enrolled participants per course.
*
* This is intended for statistics purposes during the site registration. Only visible courses are taken into account.
* Front page enrolments are excluded.
*
* @param bool $onlyactive Consider only active enrolments in enabled plugins and obey the enrolment time restrictions.
* @param int $lastloginsince If specified, count only users who logged in after this timestamp.
* @return float
*/
function average_number_of_participants() {
global $DB, $SITE;
function average_number_of_participants(bool $onlyactive = false, int $lastloginsince = null): float {
global $DB;
$params = [
'siteid' => SITEID,
];
$sql = "SELECT DISTINCT ue.userid, e.courseid
FROM {user_enrolments} ue
JOIN {enrol} e ON e.id = ue.enrolid
JOIN {course} c ON c.id = e.courseid ";
if ($onlyactive || $lastloginsince) {
$sql .= "JOIN {user} u ON u.id = ue.userid ";
}
$sql .= "WHERE e.courseid <> :siteid
AND c.visible = 1 ";
if ($onlyactive) {
$sql .= "AND ue.status = :active
AND e.status = :enabled
AND ue.timestart < :now1
AND (ue.timeend = 0 OR ue.timeend > :now2) ";
// Same as in the enrollib - the rounding should help caching in the database.
$now = round(time(), -2);
$params += [
'active' => ENROL_USER_ACTIVE,
'enabled' => ENROL_INSTANCE_ENABLED,
'now1' => $now,
'now2' => $now,
];
}
if ($lastloginsince) {
$sql .= "AND u.lastlogin > :lastlogin ";
$params['lastlogin'] = $lastloginsince;
}
$sql = "SELECT COUNT(*)
FROM ($sql) total";
//count total of enrolments for visible course (except front page)
$sql = 'SELECT COUNT(*) FROM (
SELECT DISTINCT ue.userid, e.courseid
FROM {user_enrolments} ue, {enrol} e, {course} c
WHERE ue.enrolid = e.id
AND e.courseid <> :siteid
AND c.id = e.courseid
AND c.visible = 1) total';
$params = array('siteid' => $SITE->id);
$enrolmenttotal = $DB->count_records_sql($sql, $params);
// Get the number of visible courses (exclude the front page).
$coursetotal = $DB->count_records('course', ['visible' => 1]);
$coursetotal = $coursetotal - 1;
//count total of visible courses (minus front page)
$coursetotal = $DB->count_records('course', array('visible' => 1));
$coursetotal = $coursetotal - 1 ;
//average of enrolment
if (empty($coursetotal)) {
$participantaverage = 0;
} else {
$participantaverage = $enrolmenttotal / $coursetotal;
}

View File

@ -6945,4 +6945,78 @@ class core_course_courselib_testcase extends advanced_testcase {
// Manager has permissions.
$this->assertTrue(course_allowed_module($course, 'assign', $manager));
}
/**
* Test the {@link average_number_of_participants()} function.
*/
public function test_average_number_of_participants() {
global $DB;
$this->resetAfterTest(true);
$generator = $this->getDataGenerator();
$now = time();
// If there are no courses, expect zero number of participants per course.
$this->assertEquals(0, average_number_of_participants());
$c1 = $generator->create_course();
$c2 = $generator->create_course();
// If there are no users, expect zero number of participants per course.
$this->assertEquals(0, average_number_of_participants());
$t1 = $generator->create_user(['lastlogin' => $now]);
$s1 = $generator->create_user(['lastlogin' => $now]);
$s2 = $generator->create_user(['lastlogin' => $now - WEEKSECS]);
$s3 = $generator->create_user(['lastlogin' => $now - WEEKSECS]);
$s4 = $generator->create_user(['lastlogin' => $now - YEARSECS]);
// We have courses, we have users, but no enrolments yet.
$this->assertEquals(0, average_number_of_participants());
// Front page enrolments are ignored.
$generator->enrol_user($t1->id, SITEID, 'teacher');
$this->assertEquals(0, average_number_of_participants());
// The teacher enrolled into one of the two courses.
$generator->enrol_user($t1->id, $c1->id, 'editingteacher');
$this->assertEquals(0.5, average_number_of_participants());
// The teacher enrolled into both courses.
$generator->enrol_user($t1->id, $c2->id, 'editingteacher');
$this->assertEquals(1, average_number_of_participants());
// Student 1 enrolled in the Course 1 only.
$generator->enrol_user($s1->id, $c1->id, 'student');
$this->assertEquals(1.5, average_number_of_participants());
// Student 2 enrolled in both courses, but the enrolment in the Course 2 not active yet (enrolment starts in the future).
$generator->enrol_user($s2->id, $c1->id, 'student');
$generator->enrol_user($s2->id, $c2->id, 'student', 'manual', $now + WEEKSECS);
$this->assertEquals(2.5, average_number_of_participants());
$this->assertEquals(2, average_number_of_participants(true));
// Student 3 enrolled in the Course 1, but the enrolment already expired.
$generator->enrol_user($s3->id, $c1->id, 'student', 'manual', 0, $now - YEARSECS);
$this->assertEquals(3, average_number_of_participants());
$this->assertEquals(2, average_number_of_participants(true));
// Student 4 enrolled in both courses, but the enrolment has been suspended.
$generator->enrol_user($s4->id, $c1->id, 'student', 'manual', 0, 0, ENROL_USER_SUSPENDED);
$generator->enrol_user($s4->id, $c2->id, 'student', 'manual', $now - DAYSECS, $now + YEARSECS, ENROL_USER_SUSPENDED);
$this->assertEquals(4, average_number_of_participants());
$this->assertEquals(2, average_number_of_participants(true));
// Consider only t1 and s1 who logged in recently.
$this->assertEquals(1.5, average_number_of_participants(false, $now - DAYSECS));
// Consider only t1, s1, s2 and s3 who logged in in recent weeks.
$this->assertEquals(3, average_number_of_participants(false, $now - 4 * WEEKSECS));
// Hidden courses are excluded from stats.
$DB->set_field('course', 'visible', 0, ['id' => $c1->id]);
$this->assertEquals(3, average_number_of_participants());
$this->assertEquals(1, average_number_of_participants(true));
}
}