--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Class that computes summary of users points
+ *
+ * @package mod_attendance
+ * @copyright 2016 Antonio Carlos Mariani http://antonio.c.mariani@gmail.com
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class mod_attendance_summary {
+
+ /** @var int attendance instance identifier */
+ private $attendanceid;
+
+ /** @var stdclass course course data*/
+ private $course;
+
+ /** @var int groupmode*/
+ private $groupmode;
+
+ /** @var array userspoints (userid, numtakensessions, points, maxpoints) */
+ private $userspoints;
+
+ /** @var array pointsbygroup (groupid, numsessions, maxpoints) */
+ private $maxpointsbygroupsessions;
+
+ /**
+ * Initializes the class
+ *
+ * @param int attendance instance identifier
+ * @param array userids user instances identifier
+ * @param int $startdate Attendance sessions startdate
+ * @param int $enddate Attendance sessions enddate
+ */
+ public function __construct($attendanceid, $userids=array(), $startdate = '', $enddate = '') {
+ $this->attendanceid = $attendanceid;
+
+ $this->compute_users_points($userids, $startdate, $enddate);
+ }
+
+ /**
+ * Returns true if the user has some session with points
+ *
+ * @param int userid User instance id
+ *
+ * @return boolean
+ */
+ public function has_taken_sessions($userid) {
+ return isset($this->userspoints[$userid]);
+ }
+
+ /**
+ * Returns true if the corresponding attendance instance is currently configure to work with grades (points)
+ *
+ * @return boolean
+ */
+ public function with_groups() {
+ return $this->groupmode > 0;
+ }
+
+ /**
+ * Returns the groupmode of the corresponding attendance instance
+ *
+ * @return int
+ */
+ public function get_groupmode() {
+ return $this->groupmode;
+ }
+
+ /**
+ * Returns a summary of the points assigned to the user related to the taken sessions
+ *
+ * @param int userid User instance id
+ *
+ * @return array
+ */
+ public function get_taken_sessions_summary_for($userid) {
+ $usersummary = new stdClass();
+ if ($this->has_taken_sessions($userid)) {
+ $usersummary->numtakensessions = $this->userspoints[$userid]->numtakensessions;
+ $usersummary->takensessionspoints = $this->userspoints[$userid]->points;
+ $usersummary->takensessionsmaxpoints = $this->userspoints[$userid]->maxpoints;
+ } else {
+ $usersummary->numtakensessions = 0;
+ $usersummary->takensessionspoints = 0;
+ $usersummary->takensessionsmaxpoints = 0;
+ }
+ $usersummary->takensessionspercentage = attendance_calc_fraction($usersummary->takensessionspoints, $usersummary->takensessionsmaxpoints);
+
+ return $usersummary;
+ }
+
+ /**
+ * Returns a summary of the points assigned to the user, both related to taken sessions and related to all sessions
+ *
+ * @param int userid User instance id
+ *
+ * @return array
+ */
+ public function get_all_sessions_summary_for($userid) {
+ $usersummary = $this->get_taken_sessions_summary_for($userid);
+
+ if (!isset($this->maxpointsbygroupsessions)) {
+ $this->compute_maxpoints_by_group_session();
+ }
+
+ $usersummary->numallsessions = $this->maxpointsbygroupsessions[0]->numsessions;
+ $usersummary->allsessionsmaxpoints = $this->maxpointsbygroupsessions[0]->maxpoints;
+
+ if ($this->with_groups()) {
+ $groupids = array_keys(groups_get_all_groups($this->course->id, $userid));
+ foreach ($groupids as $gid) {
+ if (isset($this->maxpointsbygroupsessions[$gid])) {
+ $usersummary->numallsessions += $this->maxpointsbygroupsessions[$gid]->numsessions;
+ $usersummary->allsessionsmaxpoints += $this->maxpointsbygroupsessions[$gid]->maxpoints;
+ }
+ }
+ }
+ $usersummary->allsessionspercentage = attendance_calc_fraction($usersummary->takensessionspoints, $usersummary->allsessionsmaxpoints);
+
+ $deltapoints = $usersummary->allsessionsmaxpoints - $usersummary->takensessionsmaxpoints;
+ $usersummary->maxpossiblepoints = $usersummary->takensessionspoints + $deltapoints;
+ $usersummary->maxpossiblepercentage = attendance_calc_fraction($usersummary->maxpossiblepoints, $usersummary->allsessionsmaxpoints);
+
+ return $usersummary;
+ }
+
+ /**
+ * Computes the summary of points for the users that have some taken session
+ *
+ * @param array userids user instances identifier
+ * @param int $startdate Attendance sessions startdate
+ * @param int $enddate Attendance sessions enddate
+ * @return (userid, numtakensessions, points, maxpoints)
+ */
+ private function compute_users_points($userids=array(), $startdate = '', $enddate = '') {
+ global $DB;
+
+ list($this->course, $cm) = get_course_and_cm_from_instance($this->attendanceid, 'attendance');
+ $this->groupmode = $cm->effectivegroupmode;
+
+ $params = array(
+ 'attid' => $this->attendanceid,
+ 'attid2' => $this->attendanceid,
+ 'cstartdate' => $this->course->startdate,
+ );
+
+ $where = '';
+ if (!empty($userids)) {
+ list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
+ $where .= ' AND atl.studentid ' . $insql;
+ $params = array_merge($params, $inparams);
+ }
+ if (!empty($startdate)) {
+ $where .= ' AND ats.sessdate >= :startdate';
+ $params['startdate'] = $startdate;
+ }
+ if (!empty($enddate)) {
+ $where .= ' AND ats.sessdate < :enddate ';
+ $params['enddate'] = $enddate;
+ }
+
+ $joingroup = '';
+ if ($this->with_groups()) {
+ $joingroup = 'LEFT JOIN {groups_members} gm ON (gm.userid = atl.studentid AND gm.groupid = ats.groupid)';
+ $where .= ' AND (ats.groupid = 0 or gm.id is NOT NULL)';
+ } else {
+ $where .= ' AND ats.groupid = 0';
+ }
+
+ $sql = "SELECT userid, COUNT(*) AS numtakensessions, SUM(grade) AS points, SUM(maxgrade) AS maxpoints
+ FROM (SELECT atl.studentid AS userid, ats.id AS sessionid, stg.grade, stm.maxgrade
+ FROM {attendance_sessions} ats
+ JOIN {attendance_log} atl ON (atl.sessionid = ats.id)
+ JOIN {attendance_statuses} stg ON (stg.id = atl.statusid AND stg.deleted = 0 AND stg.visible = 1)
+ JOIN (SELECT setnumber, MAX(grade) AS maxgrade
+ FROM {attendance_statuses}
+ WHERE attendanceid = :attid2
+ AND deleted = 0
+ AND visible = 1
+ GROUP BY setnumber) stm
+ ON (stm.setnumber = ats.statusset)
+ {$joingroup}
+ WHERE ats.attendanceid = :attid
+ AND ats.sessdate >= :cstartdate
+ AND ats.lasttakenby != 0
+ {$where}
+ ) sess
+ GROUP BY userid";
+ $this->userspoints = $DB->get_records_sql($sql, $params);
+ }
+
+ /**
+ * Computes and store the maximum points possible for each group session
+ *
+ * @return null
+ */
+ private function compute_maxpoints_by_group_session() {
+ global $DB;
+
+ $params = array(
+ 'attid' => $this->attendanceid,
+ 'attid2' => $this->attendanceid,
+ 'cstartdate' => $this->course->startdate,
+ );
+
+ $where = '';
+ if (!$this->with_groups()) {
+ $where = 'AND sess.groupid = 0';
+ }
+
+ $sql = "SELECT sess.groupid, COUNT(*) AS numsessions, SUM(stamax.maxgrade) AS maxpoints
+ FROM {attendance_sessions} sess
+ JOIN (SELECT setnumber, MAX(grade) AS maxgrade
+ FROM {attendance_statuses}
+ WHERE attendanceid = :attid2
+ AND deleted = 0
+ AND visible = 1
+ GROUP BY setnumber) stamax
+ ON (stamax.setnumber = sess.statusset)
+ WHERE sess.attendanceid = :attid
+ AND sess.sessdate >= :cstartdate
+ {$where}
+ GROUP BY sess.groupid";
+ $this->maxpointsbygroupsessions = $DB->get_records_sql($sql, $params);
+
+ if (!isset($this->maxpointsbygroupsessions[0])) {
+ $gpoints = new stdClass();
+ $gpoints->numsessions = 0;
+ $gpoints->maxpoints = 0;
+ $this->maxpointsbygroupsessions[0] = $gpoints;
+ }
+ }
+}
}
/**
- * Used to caclulate usergrade based on rawgrade and max grade.
+ * Used to calculate a fraction based on the part and total values
*
- * @param float $grade - raw grade for user
- * @param float $maxgrade - maxgrade for this session.
- * @return float the calculated grade.
+ * @param float $part - part of the total value
+ * @param float $total - total value.
+ * @return float the calculated fraction.
*/
-function attendance_calc_user_grade_fraction($grade, $maxgrade) {
- if ($maxgrade == 0) {
+function attendance_calc_fraction($part, $total) {
+ if ($total == 0) {
return 0;
} else {
- return $grade / $maxgrade;
+ return $part / $total;
}
}
/**
- * Update all user grades - used when settings have changed.
- *
- * @param mod_attendance_structure $attendance - Full attendance class.
- * @param stdclass $coursemodule - full coursemodule record
- * @return float the calculated grade.
- */
-function attendance_update_all_users_grades(mod_attendance_structure $attendance, $coursemodule) {
- global $DB;
- $grades = array();
- $course = $attendance->course;
-
- $userids = array_keys(get_enrolled_users($attendance->context, 'mod/attendance:canbelisted', 0, 'u.id'));
- $attgrades = grade_get_grades($course->id, 'mod', 'attendance', $attendance->id, $userids);
-
- $usergrades = [];
- if (!empty($attgrades->items[0]) and !empty($attgrades->items[0]->grades)) {
- $usergrades = $attgrades->items[0]->grades;
- }
- $statuses = attendance_get_statuses($attendance->id);
- if ($attendance->grade < 0) {
- $dbparams = array('id' => -($attendance->grade));
- $scale = $DB->get_record('scale', $dbparams);
- $scalearray = explode(',', $scale->scale);
- $gradebookmaxgrade = count($scalearray);
- } else {
- $gradebookmaxgrade = $attendance->grade;
- }
- foreach ($usergrades as $userid => $existinggrade) {
- if (is_null($existinggrade->grade)) {
- // Don't update grades where one doesn't exist yet.
- continue;
- }
- $grade = new stdClass;
- $grade->userid = $userid;
- $userstatusesstat = attendance_get_user_statuses_stat($attendance->id, $course->startdate, $userid, $coursemodule);
- $usertakensesscount = attendance_get_user_taken_sessions_count($attendance->id, $course->startdate, $userid, $coursemodule);
- $usergrade = attendance_get_user_grade($userstatusesstat, $statuses);
- $usermaxgrade = attendance_get_user_max_grade($usertakensesscount, $statuses);
- $grade->rawgrade = attendance_calc_user_grade_fraction($usergrade, $usermaxgrade) * $gradebookmaxgrade;
- $grades[$userid] = $grade;
- }
-
- if (!empty($grades)) {
- $result = grade_update('mod/attendance', $course->id, 'mod', 'attendance',
- $attendance->id, 0, $grades);
- } else {
- $result = true;
- }
-
- return $result;
-}
-
-/**
* Check to see if statusid in use to help prevent deletion etc.
*
* @param integer $statusid
}
return 0;
}
+
+/**
+ * Update user grades
+ *
+ * @param mixed mod_attendance_structure|stdClass $attendance
+ * @param array $userids
+ */
+function attendance_update_users_grade($attendance, $userids=array()) {
+ global $DB;
+
+ if (empty($attendance->grade)) {
+ return false;
+ }
+
+ list($course, $cm) = get_course_and_cm_from_instance($attendance->id, 'attendance');
+
+ $summary = new mod_attendance_summary($attendance->id, $userids);
+
+ if (empty($userids)) {
+ $context = context_module::instance($cm->id);
+ $userids = array_keys(get_enrolled_users($context, 'mod/attendance:canbelisted', 0, 'u.id'));
+ }
+
+ if ($attendance->grade < 0) {
+ $dbparams = array('id' => -($attendance->grade));
+ $scale = $DB->get_record('scale', $dbparams);
+ $scalearray = explode(',', $scale->scale);
+ $attendancegrade = count($scalearray);
+ } else {
+ $attendancegrade = $attendance->grade;
+ }
+
+ $grades = array();
+ foreach ($userids as $userid) {
+ $grades[$userid] = new stdClass();
+ $grades[$userid]->userid = $userid;
+
+ if ($summary->has_taken_sessions($userid)) {
+ $usersummary = $summary->get_taken_sessions_summary_for($userid);
+ $grades[$userid]->rawgrade = $usersummary->takensessionspercentage * $attendancegrade;
+ } else {
+ $grades[$userid]->rawgrade = null;
+ }
+ }
+
+ return grade_update('mod/attendance', $course->id, 'mod', 'attendance', $attendance->id, 0, $grades);
+}