Incorrect variable name used for parameter.
[moodle-linuxchix.git] / mod / attendance / lib.php
blob1d8aa0ca180dff2fcc99ca23698ad6fcd02f9750
1 <?php // $Id$
3 /// Library of functions and constants for attendance module
5 // error_reporting(E_ALL);
7 function attendance_add_module(&$mod) {
8 // global $mod;
9 require_once("../../course/lib.php");
11 if (! $mod->instance = attendance_add_instance($mod)) {
12 error("Could not add a new instance of $mod->modulename"); return 0;
14 // course_modules and course_sections each contain a reference
15 // to each other, so we have to update one of them twice.
17 if (! $mod->coursemodule = add_course_module($mod) ) {
18 error("Could not add a new course module"); return 0;
20 if (! $sectionid = add_mod_to_section($mod) ) {
21 error("Could not add the new course module to that section"); return 0;
23 if (! set_field("course_modules", "section", $sectionid, "id", $mod->coursemodule)) {
24 error("Could not update the course module with the correct section"); return 0;
26 add_to_log($mod->course, "course", "add mod",
27 "../mod/$mod->modulename/view.php?id=$mod->coursemodule",
28 "$mod->modulename $mod->instance");
29 rebuild_course_cache($mod->course);
33 function attendance_add_instance($attendance) {
34 global $mod;
35 $attendance->timemodified = time();
36 $attendance->dynsection = !empty($attendance->dynsection) ? 1 : 0;
37 $attendance->autoattend = !empty($attendance->autoattend) ? 1 : 0;
38 $attendance->grade = !empty($attendance->grade) ? 1 : 0;
39 if (empty($attendance->day)) {
40 $attendance->day = make_timestamp($attendance->theyear,
41 $attendance->themonth, $attendance->theday);
43 $attendance->notes = $attendance->name;
44 $attendance->name=userdate($attendance->day, get_string("strftimedate"));
45 if ($attendance->notes) {
46 $attendance->name = $attendance->name . " - " . $attendance->notes;
48 $attendance->edited = 0;
49 if ($attendance->dynsection) {
50 if ($mod->course) {
51 if (! $course = get_record("course", "id", $mod->course)) {
52 error("Course is misconfigured");
55 if ($course->format =="weeks") {
56 // floor($date_relative / 604800) + 1
57 $attendance->section = floor(($attendance->day - $course->startdate)/604800) +1;
58 if($attendance->section > $course->numsections){
59 $attendance->section = 0;
61 $attendance->section = "$attendance->section";
62 $mod->section = "$attendance->section";
65 // insert the main record first
66 return $attendance->id = insert_record("attendance", $attendance);
70 function attendance_update_instance($attendance) {
71 global $mod;
72 $attendance->edited = 1;
73 $attendance->timemodified = time();
74 // $attendance->oldid=$attendance->id;
75 $attendance->id = $attendance->instance;
76 $attendance->dynsection = !empty($attendance->dynsection) ? 1 : 0;
77 $attendance->autoattend = !empty($attendance->autoattend) ? 1 : 0;
78 $attendance->grade = !empty($attendance->grade) ? 1 : 0;
80 $attendance->day = make_timestamp($attendance->theyear,
81 $attendance->themonth, $attendance->theday);
82 $attendance->notes = $attendance->name;
83 $attendance->name=userdate($attendance->day, get_string("strftimedate"));
84 if ($attendance->notes) {
85 $attendance->name = $attendance->name . " - " . $attendance->notes;
87 if ($attendance->dynsection) {
88 //get info about the course
89 if ($attendance->course) {
90 if (! $course = get_record("course", "id", $attendance->course)) {
91 error("Course is misconfigured");
94 //work out which section this should be in
95 $attendance->section = floor(($attendance->day - $course->startdate)/604800) +1;
96 if (($attendance->section > $course->numsections) || ($attendance->section < 0)){
97 $attendance->section = 0;
99 // $attendance->section = "$attendance->section";
101 // get the data from the attendance grid
102 if ($data = data_submitted()) {
103 // Peel out all the data from variable names.
104 $attrec->dayid = $attendance->id;
105 if ($data) foreach ($data as $key => $val) {
106 $pieces = explode('_',$key);
107 if ($pieces[0] == 'student') {
108 $attrec->userid=$pieces[1];
109 $attrec->hour=$pieces[2];
110 $attrec->status=$val;
111 // clear out any old records for the student
112 delete_records("attendance_roll",
113 "dayid",$attrec->dayid,
114 "hour", $attrec->hour,
115 "userid",$attrec->userid);
116 if ($attrec->status != 0) {
117 // student is registered as absent or tardy
118 insert_record("attendance_roll",$attrec, false);
120 } // if we have a piece of the student roll data
121 } // foreach for all form variables
122 } // if
125 if(!update_record("attendance", $attendance)){
126 error("Couldn't update record");
129 if ($attendance->dynsection) {
130 //get section info
131 $section = get_record("course_sections", "course", $attendance->course, "section", $attendance->section);
133 //remove module from the current section
134 if (! delete_mod_from_section($attendance->coursemodule, $mod->section)) {
135 notify("Could not delete module from existing section");
138 //update course with new module location
139 if(! set_field("course_modules", "section", $section->id, "id", $attendance->coursemodule)){
140 notify("Could not update course module list");
143 //add module to the new section
144 if (! add_mod_to_section($attendance, NULL)) {
145 notify("Could not add module to new section");
148 rebuild_course_cache($section->course);
150 return true;
153 function attendance_delete_instance($id) {
154 if (! $attendance = get_record("attendance", "id", "$id")) {
155 return false;
158 $result = true;
160 /// delete all the rolls for the day
161 delete_records("attendance_roll", "dayid", "$attendance->id");
163 if (! delete_records("attendance", "id", "$attendance->id")) {
164 $result = false;
167 return $result;
170 function attendance_user_outline($course, $user, $mod, $attendance) {
171 /// Return a small object with summary information about what a
172 /// user has done with a given particular instance of this module
173 /// Used for user activity reports.
174 /// $return->time = the time they did it
175 /// $return->info = a short text description
176 /// for attendance, this would be a list present and tardy for every hour of the day
177 $tardies=count_records("attendance_roll", "dayid", $attendance->id, "userid", $user->id, "status", 1);
178 $absences=count_records("attendance_roll", "dayid", $attendance->id, "userid", $user->id, "status", 2);
180 // build longer string for tardies
181 if ($tardies > 0) {
182 $tardyrecs=attendance_get_records("attendance_roll", "dayid", $attendance->id, "userid", $user->id, "status", 1, "hour ASC");
183 if ($tardies == 1) {
184 $tardystring = "Tardy in hour " . $tardyrecs[0]->hour . ". ";
185 } elseif ($tardies == $attendance->hours) {
186 $tardystring = "Tardy in all hours. (" . $attendance->hours . ") ";
187 } else {
188 // build array of all tardies
189 $tarr = array();
190 if ($tardyrecs) foreach ($tardyrecs as $tardyrec) {
191 array_push($tarr, $tardyrec->hour);
192 $tardystring = $tardystring . ", " . $tardyrec->hour;
194 $end=array_pop($tarr);
195 $tardystring = "Tardy in hours " . implode(", ", $tarr) . " and ". $end . ". ";
197 } else { $tardystring = "";}
198 // build longer string for absences
199 if ($absences > 0) {
200 $absrecs=attendance_get_records("attendance_roll", "dayid", $attendance->id, "userid", $user->id, "status", 2, "hour ASC");
201 if ($absences == 1) {
202 $absstring = "Absent in hour " . $absrecs[0]->hour . ".";
203 } elseif ($absences == $attendance->hours) {
204 $absstring = "Absent in all hours. (" . $attendance->hours . ")";
205 } else {
206 // build array of all absences
207 $aarr = array();
208 if ($absrecs) foreach ($absrecs as $absrec) {
209 array_push($aarr, $absrec->hour);
211 $end=array_pop($aarr);
212 $absstring = "Absent in hours " . implode(", ", $aarr) . " and ". $end . ".";
214 } else { $absstring = "";}
215 $return->info=$tardystring . $absstring;
216 if ($return->info == "") $return->info = "No Tardies or Absences";
217 return $return;
220 function attendance_user_complete($course, $user, $mod, $attendance) {
221 /// Print a detailed representation of what a user has done with
222 /// a given particular instance of this module, for user activity reports.
223 // get the attendance record for that day and user
224 $A = get_string("absentshort","attendance");
225 $T = get_string("tardyshort","attendance");
226 $P = get_string("presentshort","attendance");
228 $attrecs=attendance_get_records("attendance_roll", "dayid", $attendance->id, "userid", $user->id, "", "", "hour ASC");
229 // fill an array with the absences and tardies, as those are the only records actually stored
231 $grid = array();
232 if ($attrecs) { foreach ($attrecs as $attrec) { $grid[$attrec->hour]=$attrec->status; } }
233 echo "<table><tr><th>Hour:</th>\n";
234 // echo out the table header
235 for($j=1;$j<=$attendance->hours;$j++) {
236 echo "<th valign=\"top\" align=\"center\" nowrap class=\"generaltableheader\">".$j."</th>\n";
238 echo "</tr><tr><th>Status:</th>";
239 for($j=1;$j<=$attendance->hours;$j++) {
240 // set the attendance defaults for each student
241 if (isset($grid[$j])) {
242 $status = (($grid[$j] == 1) ? $T : $A);
243 } else {$status=$P;}
244 echo "<td align=\"left\" nowrap class=\"generaltablecell\" style=\"border-left: 1px dotted; border-top: 1px solid;\">".$status."</td>\n";
245 } /// for loop
246 echo "</tr></table>\n";
249 return true;
253 function attendance_cron () {
254 /// Function to be run periodically according to the moodle cron
255 /// This function searches for things that need to be done, such
256 /// as sending out mail, toggling flags etc ...
257 global $CFG;
258 echo "Attendance: Performing automatic attendance logging\n";
259 // look for all attendance instances set to autoattend
260 if (!$attendances = get_records("attendance", "autoattend", 1, "course ASC")) {
261 return true;
263 $td = attendance_find_today(time());
264 $tm = attendance_find_tomorrow(time());
265 if ($attendances) foreach($attendances as $attendance) {
266 if (($attendance->day >=$td ) && ($attendance->day < $tm)) {
267 echo "Attendance: Taking attendance for $attendance->name\n";
269 if(!isset($courses[$attendance->course]->students)) {
270 $courses[$attendance->course]->students =
271 attendance_get_course_students($attendance->course, "u.lastname ASC");
273 if ($courses[$attendance->course]->students) {
274 foreach ($courses[$attendance->course]->students as $student) {
275 // first, clear out the records that may be there already
276 delete_records("attendance_roll",
277 "dayid",$attendance->id,
278 "userid",$student->id);
279 $wc = "userid = " . $student->id . " AND course = " . $attendance->course .
280 " AND time >= " . $td . " AND time < " . $tm;
281 $count = get_record_select("log",$wc,"COUNT(*) as c");
282 if ($count->c == "0") { // then the student hasn't done anything today, so mark him absent
283 $attrec->dayid = $attendance->id;
284 $attrec->userid = $student->id;
285 $attrec->status = 2; // status 2 is absent
286 // mark ALL hours as absent for first version
287 for ($i=1;$i<=$attendance->hours;$i++) {
288 $attrec->hour = $i;
289 insert_record("attendance_roll",$attrec, false);
290 } // for loop to mark all hours absent
291 } // if student has no activity
292 } // foreach student in the list
293 } // if students exist
294 } // if the attendance roll is for today
295 } // for each attendance in the system
296 return true;
297 } // function cron
300 function attendance_grades($attendanceid) {
301 /// Must return an array of grades for a given instance of this module,
302 /// indexed by user. It also returns a maximum allowed grade.
303 $attendance = get_record("attendance", "id", $attendanceid);
304 if ($attendance->grade == "1") {
305 $students = get_course_students($attendance->course);
306 if ($students) {
307 foreach ($students as $student) {
308 $rolls = attendance_get_records("attendance_roll",
309 "dayid",$attendance->id,
310 "userid",$student->id);
311 $abs=$tar=0;
312 if ($rolls) {
313 foreach ($rolls as $roll) {
314 if ($roll->status == 1) {$tar++;}
315 elseif ($roll->status == 2) {$abs++;}
316 } // if rolls
317 $total = $attendance->hours - attendance_tally_overall_absences_decimal($abs, $tar);
318 $percent = ($total != 0)?$total/$attendance->hours:0;
319 $return->grades[$student->id] = ($percent == 0)?0.0:$attendance->maxgrade * $percent;
320 } else { $return->grades[$student->id] = $attendance->maxgrade; }
321 } // foreach student
322 } // if students
323 $return->maxgrade = $attendance->maxgrade;
324 } else { // if attendance->grade == "1"
325 $return = NULL;
326 }// else for if attendance->grade == "1"
327 return $return;
331 * Returns user records for all users who have DATA in a given attendance instance
333 * This function is present only for the backup routines. It won't return meaningful data
334 * for an attendance roll because it only returns records for users who have been counted as
335 * tardy or absent in the rolls for a single attendance instance, since these are the only
336 * records I store in the database - for brevity's sake of course.
338 * @param int $attendanceid the id of the attendance record we're looging for student data from
339 * @return (object)recordset associative array of records containing the student records we wanted
341 function attendance_get_participants($attendanceid) {
342 //Returns the users with data in one attendance
343 //(users with records in attendance_roll, students)
345 global $CFG;
347 //Get students
348 $students = get_records_sql("SELECT DISTINCT u.id, u.id
349 FROM {$CFG->prefix}user u,
350 {$CFG->prefix}attendance_roll a
351 WHERE a.dayid = '$attendanceid' and
352 u.id = a.userid");
354 //Return students array (it contains an array of unique users)
355 return ($students);
359 //////////////////////////////////////////////////////////////////////////////////////
360 /// Any other attendance functions go here. Each of them must have a name that
361 /// starts with attendance_
364 * get a list of all students enrolled in a given course - modified version
366 * THIS IS JUST THE GET_COURSE_STUDENTS FUNCTION WITH THE INCLUSION OF THE
367 * STUDENT ID INTO THE RECORDSET
368 * if courseid = 0 then return ALL students in all courses
370 * @param int $courseid the id of the course
371 * @param string $sort a field name and ASC or DESC for a SQL 'ORDER BY' clause (optional)
372 * @return array(recorset) a list of all students in the specified course
373 Returns
375 function attendance_get_course_students($courseid, $sort="u.lastaccess DESC") {
377 global $CFG;
379 // make sure it works on the site course
380 $select = "s.course = '$courseid' AND";
381 if ($courseid == SITEID) {
382 $select = '';
384 return get_records_sql("SELECT u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat,
385 u.email, u.city, u.country, u.lastaccess, u.lastlogin, u.picture, u.idnumber
386 FROM {$CFG->prefix}user u,
387 {$CFG->prefix}user_students s
388 WHERE $select s.userid = u.id AND u.deleted = '0'
389 ORDER BY $sort");
394 * Find total absences based on number of tardies per absence
396 * Given a number of tardies and absences, determine the total
397 * number of equivalent absences it adds up to.
399 * @param int $absences the total number of absences for a span of time
400 * @param int $tardies the total number of tardies for a span of time
401 * @return float the number of absences it adds up to - may be a decimal!
403 function attendance_tally_overall_absences_decimal($absences, $tardies) {
404 global $CFG;
405 if (isset($CFG->attendance_tardies_per_absence) && ($CFG->attendance_tardies_per_absence>0)) {
406 return $absences + ($tardies/$CFG->attendance_tardies_per_absence);
407 } else { return $absences; }
411 * Find total absences based on number of tardies per absence and put it in a string
413 * Given a number of tardies and absences, determine the total
414 * number of equivalent absences it adds up to and express it as a string with
415 * a possible fractional remainder
417 * @param int $absences the total number of absences for a span of time
418 * @param int $tardies the total number of tardies for a span of time
419 * @return string the number of absences it adds up to - may have a fractional component!
421 function attendance_tally_overall_absences_fraction($absences, $tardies) {
422 global $CFG;
423 if (isset($CFG->attendance_tardies_per_absence) && ($CFG->attendance_tardies_per_absence>0)) {
424 $whole = floor($tardies/$CFG->attendance_tardies_per_absence);
425 $fractional=$tardies-($whole * $CFG->attendance_tardies_per_absence);
426 if ($absences + $whole > 0) {
427 return ($absences + $whole) . (($fractional > 0) ? " ". $fractional. "/". $CFG->attendance_tardies_per_absence : "");
428 } else {
429 return (($fractional > 0) ? $fractional. "/". $CFG->attendance_tardies_per_absence : "0");
431 } else {
432 return $absences."";
437 * get a list of records from a table with multiple criteria
439 * This one is different from the datalib.php one (called get_records) in the sense that it
440 * allows for multiple criteria to be easily supplied as parameters, but doesn't
441 * give the ability to specify sort, fields, or limits
444 function attendance_get_records($table, $field1="", $value1="", $field2="", $value2="", $field3="", $value3="", $sort="", $fields="*", $limitfrom="", $limitnum="") {
446 global $CFG;
448 if ($field1) {
449 $select = "WHERE $field1 = '$value1'";
450 if ($field2) {
451 $select .= " AND $field2 = '$value2'";
452 if ($field3) {
453 $select .= " AND $field3 = '$value3'";
456 } else {
457 $select = "";
460 if ($limitfrom !== "") {
461 switch ($CFG->dbtype) {
462 case "mysql":
463 $limit = "LIMIT $limitfrom,$limitnum";
464 break;
465 case "postgres7":
466 $limit = "LIMIT $limitnum OFFSET $limitfrom";
467 break;
468 default:
469 $limit = "LIMIT $limitnum,$limitfrom";
471 } else {
472 $limit = "";
475 if ($sort != "") {
476 $sort = "ORDER BY $sort";
479 return get_records_sql("SELECT $fields FROM $CFG->prefix$table $select $sort $limit");
483 * Return all attendance records that are in the same section as the instance specified
485 * This function uses course_modules, modules, and attendance tables together to determine
486 * first what section the specified attendance instance in the course is in, then all the
487 * attendance records that are in the same section, regardless of the format of the course
489 * @param int $instance id of the attendance instance in course_modules
490 * @param int $courseid the id of the course for which we're getting records
491 * @return (object)recordset associative array of records containing the attendance records we wanted
493 function get_attendance_for_section($instance, $courseid) {
494 global $CFG;
495 // first, get the section for the instance specified
496 $sql = "SELECT cm.section
497 FROM {$CFG->prefix}course_modules cm,
498 {$CFG->prefix}modules md,
499 {$CFG->prefix}attendance a
500 WHERE cm.course = '$courseid' AND
501 cm.deleted = '0' AND
502 cm.instance = a.id AND
503 md.name = 'attendance' AND
504 md.id = cm.module AND
505 a.id = '$instance'";
506 $sectarray = get_record_sql($sql);
507 // echo "<pre>$sql \n</pre>";
508 $section = $sectarray->section;
510 select cm.section from
511 mdl_course_modules cm, mdl_modules md, mdl_attendance m
512 where cm.course = '7' AND cm.deleted = '0' AND cm.instance = m.id
513 AND md.name = 'attendance' AND md.id = cm.module AND m.id = '119';
515 // then get all the attendance instances in that section
516 $sql = "SELECT a.*
517 FROM {$CFG->prefix}course_modules cm,
518 {$CFG->prefix}modules md,
519 {$CFG->prefix}attendance a
520 WHERE cm.course = '$courseid' AND
521 cm.deleted = '0' AND
522 cm.section = '$section' AND
523 md.name = 'attendance' AND
524 md.id = cm.module AND
525 a.id = cm.instance order by a.day ASC";
526 // echo "<pre>$sql \n</pre>";
527 return get_records_sql($sql);
529 select m.* from mdl_course_modules cm, mdl_modules md, mdl_attendance m
530 where cm.course = '7' AND cm.deleted = '0' AND cm.section = '85'
531 AND md.name = 'attendance' AND md.id = cm.module AND m.id = cm.instance;
536 * Return all attendance records that are in the same 7 day span as the instance specified
538 * This function uses the course and attendance tables together to find all the attendance
539 * records that are for days within the same week span as the instance specified. The week is
540 * determined based NOT on calendar week, but instead on the week span as it occurs in a
541 * weekly formatted course - I find this by starting with the startdate of the course and
542 * then skipping ahead by weeks til I find the range that fits the instance, then I use that
543 * range as min and max to query the attendance table for all the other records. Note that this
544 * function will work with non-weekly formatted courses, though the results won't easily
545 * correlate with the course view. But it will work regardless.
547 * @param int $id the id of the attendance record we're using as a basis for the query
548 * @param int $courseid the id of the course for which we're getting records
549 * @return (object)recordset associative array of records containing the attendance records we wanted
551 function get_attendance_for_week($id, $courseid) {
552 global $CFG;
553 if (! $attendance = get_record("attendance", "id", $id)) {
554 error("Course module is incorrect");
556 if (! $course = get_record("course", "id", $courseid)) {
557 error("Course module is incorrect");
559 // the offset is for weeks that don't start on Monday
560 $day = $attendance->day;
561 // determine the week range for the select, based on the day
562 for ($maxday=$course->startdate;$day>$maxday;$maxday=$maxday+604800)
563 {;}$minday = $maxday-608400;
564 $sql = "SELECT * FROM {$CFG->prefix}attendance
565 WHERE course = '$courseid' AND day<$maxday AND day>=$minday order by day ASC;";
566 // echo "<pre>$sql \n</pre>";
567 return get_records_sql($sql);
571 * Finds the beginning of the day for the date specified
573 * This function returns the timestamp for midnight of the day specified in the timestamp
575 * @param timestamp $d The time to find the beginning of the day for
576 * @return timestamp midnight for that day
578 function attendance_find_today($d) {
579 // $da = getdate($d);
580 $damon = gmdate("m",$d);
581 $daday = gmdate("d",$d);
582 $dayear = gmdate("Y",$d);
583 // now return midnight of that day
584 // return mktime(0,0,0,$da["mon"], $da["mday"], $da["year"]);
585 return gmmktime(0,0,0,$damon, $daday, $dayear);
589 * Finds the beginning of the day following the date specified
591 * This function returns the timestamp for midnight of the day after the timestamp specified
593 * @param timestamp $d The time to find the next day of
594 * @return timestamp midnight of the next day
596 function attendance_find_tomorrow($d) {
597 // add 24 hours to the current time - to solve end of month date issues
598 return attendance_find_today($d+86400);