Fixes #223 allow student attendance to be disabled at site-level
[moodle-mod_attendance.git] / locallib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17 /**
18 * local functions and constants for module attendance
19 *
20 * @package mod_attendance
21 * @copyright 2011 Artem Andreev <andreev.artem@gmail.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25 defined('MOODLE_INTERNAL') || die();
26
27 require_once($CFG->libdir . '/gradelib.php');
28 require_once(dirname(__FILE__).'/renderhelpers.php');
29
30 define('ATT_VIEW_DAYS', 1);
31 define('ATT_VIEW_WEEKS', 2);
32 define('ATT_VIEW_MONTHS', 3);
33 define('ATT_VIEW_ALLPAST', 4);
34 define('ATT_VIEW_ALL', 5);
35 define('ATT_VIEW_NOTPRESENT', 6);
36
37 define('ATT_SORT_LASTNAME', 1);
38 define('ATT_SORT_FIRSTNAME', 2);
39
40 function attendance_get_statuses($attid, $onlyvisible=true, $statusset = -1) {
41 global $DB;
42
43 // Set selector.
44 $params = array('aid' => $attid);
45 $setsql = '';
46 if ($statusset >= 0) {
47 $params['statusset'] = $statusset;
48 $setsql = ' AND setnumber = :statusset ';
49 }
50
51 if ($onlyvisible) {
52 $statuses = $DB->get_records_select('attendance_statuses', "attendanceid = :aid AND visible = 1 AND deleted = 0 $setsql",
53 $params, 'setnumber ASC, grade DESC');
54 } else {
55 $statuses = $DB->get_records_select('attendance_statuses', "attendanceid = :aid AND deleted = 0 $setsql",
56 $params, 'setnumber ASC, grade DESC');
57 }
58
59 return $statuses;
60 }
61
62 /**
63 * Get the name of the status set.
64 *
65 * @param int $attid
66 * @param int $statusset
67 * @param bool $includevalues
68 * @return string
69 */
70 function attendance_get_setname($attid, $statusset, $includevalues = true) {
71 $statusname = get_string('statusset', 'mod_attendance', $statusset + 1);
72 if ($includevalues) {
73 $statuses = attendance_get_statuses($attid, true, $statusset);
74 $statusesout = array();
75 foreach ($statuses as $status) {
76 $statusesout[] = $status->acronym;
77 }
78 if ($statusesout) {
79 if (count($statusesout) > 6) {
80 $statusesout = array_slice($statusesout, 0, 6);
81 $statusesout[] = '&helip;';
82 }
83 $statusesout = implode(' ', $statusesout);
84 $statusname .= ' ('.$statusesout.')';
85 }
86 }
87
88 return $statusname;
89 }
90
91 function attendance_get_user_taken_sessions_count($attid, $coursestartdate, $userid, $coursemodule, $startdate = '', $enddate = '') {
92 global $DB, $COURSE;
93 $groupmode = groups_get_activity_groupmode($coursemodule, $COURSE);
94 if (!empty($groupmode)) {
95 $qry = "SELECT count(*) as cnt
96 FROM {attendance_log} al
97 JOIN {attendance_sessions} ats ON al.sessionid = ats.id
98 LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid
99 WHERE ats.attendanceid = :aid AND
100 ats.sessdate >= :cstartdate AND
101 al.studentid = :uid AND
102 (ats.groupid = 0 or gm.id is NOT NULL)";
103 } else {
104 $qry = "SELECT count(*) as cnt
105 FROM {attendance_log} al
106 JOIN {attendance_sessions} ats
107 ON al.sessionid = ats.id
108 WHERE ats.attendanceid = :aid AND
109 ats.sessdate >= :cstartdate AND
110 al.studentid = :uid";
111 }
112 $params = array(
113 'aid' => $attid,
114 'cstartdate' => $coursestartdate,
115 'uid' => $userid);
116
117 if (!empty($startdate) && !empty($enddate)) {
118 $qry .= ' AND sessdate >= :sdate AND sessdate < :edate ';
119 $params['sdate'] = $startdate;
120 $params['edate'] = $enddate;
121 }
122
123 return $DB->count_records_sql($qry, $params);
124 }
125
126 function attendance_get_user_statuses_stat($attid, $coursestartdate, $userid, $coursemodule) {
127 global $DB, $COURSE;
128 $groupmode = groups_get_activity_groupmode($coursemodule, $COURSE);
129 if (!empty($groupmode)) {
130 $qry = "SELECT al.statusid, count(al.statusid) AS stcnt
131 FROM {attendance_log} al
132 JOIN {attendance_sessions} ats ON al.sessionid = ats.id
133 LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid
134 WHERE ats.attendanceid = :aid AND
135 ats.sessdate >= :cstartdate AND
136 al.studentid = :uid AND
137 (ats.groupid = 0 or gm.id is NOT NULL)
138 GROUP BY al.statusid";
139 } else {
140 $qry = "SELECT al.statusid, count(al.statusid) AS stcnt
141 FROM {attendance_log} al
142 JOIN {attendance_sessions} ats
143 ON al.sessionid = ats.id
144 WHERE ats.attendanceid = :aid AND
145 ats.sessdate >= :cstartdate AND
146 al.studentid = :uid
147 GROUP BY al.statusid";
148 }
149 $params = array(
150 'aid' => $attid,
151 'cstartdate' => $coursestartdate,
152 'uid' => $userid);
153
154 return $DB->get_records_sql($qry, $params);
155 }
156
157 function attendance_get_user_grade($userstatusesstat, $statuses) {
158 $sum = 0;
159 foreach ($userstatusesstat as $stat) {
160 $sum += $stat->stcnt * $statuses[$stat->statusid]->grade;
161 }
162
163 return $sum;
164 }
165
166 function attendance_get_user_max_grade($sesscount, $statuses) {
167 reset($statuses);
168 return current($statuses)->grade * $sesscount;
169 }
170
171 function attendance_get_user_courses_attendances($userid) {
172 global $DB;
173
174 $usercourses = enrol_get_users_courses($userid);
175
176 list($usql, $uparams) = $DB->get_in_or_equal(array_keys($usercourses), SQL_PARAMS_NAMED, 'cid0');
177
178 $sql = "SELECT att.id as attid, att.course as courseid, course.fullname as coursefullname,
179 course.startdate as coursestartdate, att.name as attname, att.grade as attgrade
180 FROM {attendance} att
181 JOIN {course} course
182 ON att.course = course.id
183 WHERE att.course $usql
184 ORDER BY coursefullname ASC, attname ASC";
185
186 $params = array_merge($uparams, array('uid' => $userid));
187
188 return $DB->get_records_sql($sql, $params);
189 }
190
191 /**
192 * Used to caclulate usergrade based on rawgrade and max grade.
193 *
194 * @param float $grade - raw grade for user
195 * @param float $maxgrade - maxgrade for this session.
196 * @return float the calculated grade.
197 */
198 function attendance_calc_user_grade_fraction($grade, $maxgrade) {
199 if ($maxgrade == 0) {
200 return 0;
201 } else {
202 return $grade / $maxgrade;
203 }
204 }
205
206 /**
207 * Update all user grades - used when settings have changed.
208 *
209 * @param mod_attendance_structure $attendance - Full attendance class.
210 * @param stdclass $coursemodule - full coursemodule record
211 * @return float the calculated grade.
212 */
213 function attendance_update_all_users_grades(mod_attendance_structure $attendance, $coursemodule) {
214 global $DB;
215 $grades = array();
216 $course = $attendance->course;
217
218 $userids = array_keys(get_enrolled_users($attendance->context, 'mod/attendance:canbelisted', 0, 'u.id'));
219 $attgrades = grade_get_grades($course->id, 'mod', 'attendance', $attendance->id, $userids);
220
221 $usergrades = [];
222 if (!empty($attgrades->items[0]) and !empty($attgrades->items[0]->grades)) {
223 $usergrades = $attgrades->items[0]->grades;
224 }
225 $statuses = attendance_get_statuses($attendance->id);
226 if ($attendance->grade < 0) {
227 $dbparams = array('id' => -($attendance->grade));
228 $scale = $DB->get_record('scale', $dbparams);
229 $scalearray = explode(',', $scale->scale);
230 $gradebookmaxgrade = count($scalearray);
231 } else {
232 $gradebookmaxgrade = $attendance->grade;
233 }
234 foreach ($usergrades as $userid => $existinggrade) {
235 if (is_null($existinggrade->grade)) {
236 // Don't update grades where one doesn't exist yet.
237 continue;
238 }
239 $grade = new stdClass;
240 $grade->userid = $userid;
241 $userstatusesstat = attendance_get_user_statuses_stat($attendance->id, $course->startdate, $userid, $coursemodule);
242 $usertakensesscount = attendance_get_user_taken_sessions_count($attendance->id, $course->startdate, $userid, $coursemodule);
243 $usergrade = attendance_get_user_grade($userstatusesstat, $statuses);
244 $usermaxgrade = attendance_get_user_max_grade($usertakensesscount, $statuses);
245 $grade->rawgrade = attendance_calc_user_grade_fraction($usergrade, $usermaxgrade) * $gradebookmaxgrade;
246 $grades[$userid] = $grade;
247 }
248
249 if (!empty($grades)) {
250 $result = grade_update('mod/attendance', $course->id, 'mod', 'attendance',
251 $attendance->id, 0, $grades);
252 } else {
253 $result = true;
254 }
255
256 return $result;
257 }
258
259 /**
260 * Check to see if statusid in use to help prevent deletion etc.
261 *
262 * @param integer $statusid
263 */
264 function attendance_has_logs_for_status($statusid) {
265 global $DB;
266 return $DB->record_exists('attendance_log', array('statusid' => $statusid));
267 }
268
269 /**
270 * Helper function to add sessiondate_selector to add/update forms.
271 *
272 * @param MoodleQuickForm $mform
273 */
274 function attendance_form_sessiondate_selector (MoodleQuickForm $mform) {
275
276 $mform->addElement('date_selector', 'sessiondate', get_string('sessiondate', 'attendance'));
277
278 for ($i = 0; $i <= 23; $i++) {
279 $hours[$i] = sprintf("%02d", $i);
280 }
281 for ($i = 0; $i < 60; $i += 5) {
282 $minutes[$i] = sprintf("%02d", $i);
283 }
284
285 $sesendtime = array();
286 $sesendtime[] =& $mform->createElement('static', 'from', '', get_string('from', 'attendance'));
287 $sesendtime[] =& $mform->createElement('select', 'starthour', get_string('hour', 'form'), $hours, false, true);
288 $sesendtime[] =& $mform->createElement('select', 'startminute', get_string('minute', 'form'), $minutes, false, true);
289 $sesendtime[] =& $mform->createElement('static', 'to', '', get_string('to', 'attendance'));
290 $sesendtime[] =& $mform->createElement('select', 'endhour', get_string('hour', 'form'), $hours, false, true);
291 $sesendtime[] =& $mform->createElement('select', 'endminute', get_string('minute', 'form'), $minutes, false, true);
292 $mform->addGroup($sesendtime, 'sestime', get_string('time', 'attendance'), array(' '), true);
293 }
294
295 /**
296 * Count the number of status sets that exist for this instance.
297 *
298 * @param int $attendanceid
299 * @return int
300 */
301 function attendance_get_max_statusset($attendanceid) {
302 global $DB;
303
304 $max = $DB->get_field_sql('SELECT MAX(setnumber) FROM {attendance_statuses} WHERE attendanceid = ? AND deleted = 0',
305 array($attendanceid));
306 if ($max) {
307 return $max;
308 }
309 return 0;
310 }