Fixes bug MDL-9753, "THEME->larrow, rarrow don't work in stock IE6"
[moodle-pu.git] / grade / lib.php
blobd52193afd9ce08631dc15dd80f0199d2f60fc254
1 <?php // $Id$
3 if (!defined('MOODLE_INTERNAL')) {
4 die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
7 require_once($CFG->dirroot.'/course/lib.php');
9 define('UNCATEGORISED', 'uncategorised');
11 global $GRADEPREFS, $GRADEPREFSDEFAULTS; // This variables are going to be global... :-/
13 $GRADEPREFS = array('use_advanced', // Only add new preferences to the end of this array!
14 'use_weighted_for_letter', // as the order counts and will affect backward compatibility
15 'display_weighted',
16 'display_points',
17 'display_percent',
18 'display_letters',
19 'reprint_headers',
20 'show_hidden',
24 $GRADEPREFSDEFAULTS = array('use_advanced' => 0,
25 'use_weighted_for_letter' => 0,
26 'display_weighted' => 0,
27 'display_points' => 2,
28 'display_percent' => 1,
29 'display_letters' => 0,
30 'reprint_headers' => 0,
31 'show_hidden' => 1
35 //******************************************************************
36 // SQL FUNCTIONS
37 //******************************************************************
39 function grade_get_category_weight($course, $category) {
40 global $CFG;
41 $sql = "SELECT id, weight, drop_x_lowest, bonus_points, hidden, c.id AS cat_id
42 FROM {$CFG->prefix}grade_category c
43 WHERE c.courseid=$course
44 AND c.name='$category'";
45 $temp = get_record_sql($sql);
46 return $temp;
49 function grade_get_grade_items($course) {
50 global $CFG;
51 $sql = "SELECT i.id, c.name as cname, i.modid, mm.name as modname, i.cminstance, c.hidden, cm.visible, i.sort_order
52 FROM {$CFG->prefix}grade_item i,
53 {$CFG->prefix}grade_category c,
54 {$CFG->prefix}course_modules cm,
55 {$CFG->prefix}modules mm
56 WHERE c.id=i.category
57 AND i.courseid=c.courseid
58 AND c.courseid=$course
59 AND cm.course=c.courseid
60 AND cm.module=mm.id
61 AND i.modid=mm.id
62 AND cm.instance=i.cminstance";
63 $temp = get_records_sql($sql);
64 return $temp;
67 function grade_get_module_link($course, $cminstance, $modid) {
68 global $CFG;
69 $sql = "SELECT cm.id, 1 FROM {$CFG->prefix}course_modules cm, {$CFG->prefix}modules mm, {$CFG->prefix}grade_item i
70 WHERE i.modid='".$modid."'
71 AND i.modid=mm.id
72 AND cm.instance = i.cminstance
73 AND i.cminstance=".$cminstance."
74 AND i.courseid=cm.course AND cm.module=mm.id AND i.courseid=$course";
75 $temp = get_record_sql($sql);
76 return $temp;
79 function grade_get_grade_letter($course, $grade) {
80 global $CFG;
81 $sql = "SELECT id, letter FROM {$CFG->prefix}grade_letter WHERE courseid=$course AND grade_high >= $grade AND grade_low <= $grade";
82 $temp = get_record_sql($sql);
83 return $temp;
86 function grade_get_exceptions($course) {
87 global $CFG;
88 $sql = "SELECT e.id, e.userid, gi.cminstance, gi.modid, c.name as catname, mm.name as modname
89 FROM {$CFG->prefix}grade_exceptions e,
90 {$CFG->prefix}grade_item gi,
91 {$CFG->prefix}grade_category c,
92 {$CFG->prefix}course_modules cm,
93 {$CFG->prefix}modules mm
94 WHERE e.courseid=$course
95 AND gi.id = e.grade_itemid
96 AND c.id = gi.category
97 AND cm.course=c.courseid
98 AND cm.module=mm.id
99 AND gi.modid=mm.id";
101 $temp = get_records_sql($sql);
102 return $temp;
105 function grade_get_exceptions_user($course, $userid) {
106 global $CFG;
107 $sql = "SELECT e.id, e.userid, gi.cminstance, gi.modid, c.name as catname, mm.name as modname
108 FROM {$CFG->prefix}grade_exceptions e,
109 {$CFG->prefix}grade_item gi,
110 {$CFG->prefix}grade_category c,
111 {$CFG->prefix}course_modules cm,
112 {$CFG->prefix}modules mm
113 WHERE e.courseid=$course
114 AND e.userid=$userid
115 AND gi.id = e.grade_itemid
116 AND c.id = gi.category
117 AND cm.course=c.courseid
118 AND cm.module=mm.id
119 AND gi.modid=mm.id";
121 $temp = get_records_sql($sql);
122 return $temp;
124 function grade_letters_set($course) {
125 global $CFG;
126 $sql = "SELECT * FROM {$CFG->prefix}grade_letter WHERE courseid=$course";
127 $letters_set = get_records_sql($sql);
128 if ($letters_set) {
129 return true;
131 else {
132 return false;
136 function grade_get_users_by_group($course, $group) {
137 global $CFG;
138 $sql = "SELECT userid FROM {$CFG->prefix}groups_members WHERE courseid=$course AND groupid = $group";
139 $members = get_records_sql($sql);
140 if ($members) {
141 foreach($members as $member) {
142 // FIX ME: there is no $userid defined!!! - from where is this function used anyway??
143 $group->$userid = true;
145 return $group;
147 else {
148 return NULL;
152 //******************************************************************
153 // END SQL FUNCTIONS
154 //******************************************************************
156 function grade_get_formatted_grades() {
157 global $CFG;
158 global $COURSE;
159 global $preferences;
160 $course = $COURSE;
161 $i = 2; // index to differentiate activities with the same name MDL-6876
162 $grades = grade_get_grades();
163 if (isset($grades)) {
164 // iterate through all students
165 foreach($grades as $cur_category=>$grade_category) {
166 // $cur_category holds the value of the current category name
167 // $grade_category holds an array of all the mod types that are in this category
168 if (isset($grade_category)) {
169 foreach($grade_category as $cur_mod=>$mod_category) {
170 // $cur_mod is the id of the current moodle module type
171 // $mod_category holds the grades for $cur_mod (current mod type)
172 $module_info = get_record('modules', 'id', $cur_mod);
173 $cur_modname = $module_info->name;
174 if (isset($mod_category)) {
175 foreach($mod_category as $cur_cminstance=>$students_grade) {
176 // $cur_cminstance is the course module instance for the cur_mod
177 $instance = get_record($cur_modname, 'id',$cur_cminstance, 'course',$course->id);
178 // it's necessary to check if the name is blank because some mods don't clean up the grades when the instance is deleted
179 // this is a bug. as it is plausible that some item could get created and have old data from a previous mod laying around
180 if ($instance->name != '') {
181 // duplicate grade item name, the user should know better than to name to things by the same name, but to make sure grades don't disappear lets modify the name slightly
182 if (isset($all_categories["$cur_category"]["$instance->name"])) {
183 $instance->name= $instance->name.' #'.$i++;
186 if (isset($students_grade->grades) && $students_grade->grades != '') {
187 foreach($students_grade->grades as $student=>$grade) {
188 // add an entry for any student that has a grade
189 $grades_by_student["$student"]["$cur_category"]["$instance->name"]['grade'] = $grade;
190 $grades_by_student["$student"]["$cur_category"]["$instance->name"]['sort_order'] = $students_grade->sort_order;
192 if (!isset($grades_by_student["$student"]["$cur_category"]['stats'])) {
193 $grades_by_student["$student"]["$cur_category"]['stats'] = array();
196 if (!isset($grades_by_student["$student"]["$cur_category"]['stats']['points'])) {
197 $grades_by_student["$student"]["$cur_category"]['stats']['points'] = $grade;
199 else {
200 $grades_by_student["$student"]["$cur_category"]['stats']['points'] = $grades_by_student["$student"]["$cur_category"]['stats']['points'] + $grade;
203 // This next block just creates a comma seperated list of all grades for the category
204 if (isset($grades_by_student["$student"]["$cur_category"]['stats']['allgrades'])) {
205 $grades_by_student["$student"]["$cur_category"]['stats']['allgrades'] .= ','.$grade;
207 else {
208 $grades_by_student["$student"]["$cur_category"]['stats']['allgrades'] = $grade;
215 // set up a list of all categories and assignments (adjusting things for extra credit where necessary)
216 $all_categories["$cur_category"]["$instance->name"]['hidden'] = $students_grade->hidden;
217 $all_categories["$cur_category"]["$instance->name"]['sort_order'] = $students_grade->sort_order;
219 $all_categories["$cur_category"]["$instance->name"]['extra_credit'] = $students_grade->extra_credit;
221 if ($all_categories["$cur_category"]["$instance->name"]['extra_credit'] != 1) {
222 $all_categories["$cur_category"]["$instance->name"]['maxgrade'] = $students_grade->maxgrade;
224 else {
225 $all_categories["$cur_category"]["$instance->name"]['maxgrade'] = 0;
227 $all_categories["$cur_category"]["$instance->name"]['scale_grade'] = $students_grade->scale_grade;
228 if ($students_grade->scale_grade != 0) {
229 $all_categories["$cur_category"]["$instance->name"]['scaled_max'] = round($all_categories["$cur_category"]["$instance->name"]['maxgrade']/$students_grade->scale_grade);
231 else {
232 // avoids divide by zero... scale_grade shouldn't be set to 0 anyway
233 $all_categories["$cur_category"]["$instance->name"]['scaled_max'] = $all_categories["$cur_category"]["$instance->name"]['maxgrade'];
234 $all_categories["$cur_category"]["$instance->name"]['scale_grade'] = 1.0;
236 if (! isset($all_categories["$cur_category"]['stats']) ) {
237 $all_categories["$cur_category"]['stats'] = array();
239 $all_categories["$cur_category"]["$instance->name"]['grade_against'] = $all_categories["$cur_category"]["$instance->name"]['scaled_max'];
240 if (!isset($all_categories["$cur_category"]['stats']['weight'])) {
241 $weight = grade_get_category_weight($course->id, $cur_category);
242 $all_categories["$cur_category"]['stats']['weight'] = $weight->weight;
245 $all_categories["$cur_category"]["$instance->name"]['cminstance'] = $cur_cminstance;
246 $all_categories["$cur_category"]["$instance->name"]['modid'] = $cur_mod;
247 $modname = get_record('modules','id',$cur_mod);
248 $all_categories["$cur_category"]["$instance->name"]['modname'] = $modname->name;
250 // get bonus points and drop the x lowest
251 $drop = get_record('grade_category', 'courseid', $course->id, 'name', $cur_category);
252 $all_categories["$cur_category"]['stats']['drop'] = $drop->drop_x_lowest;
253 $all_categories["$cur_category"]['stats']['bonus_points'] = $drop->bonus_points;
260 if (!$students = grade_get_course_students($course->id)) {
261 return false;
265 if (isset($students) && $students) {
266 foreach ($students as $userid => $student) {
267 $grades_by_student["$userid"]['student_data']['firstname'] = $student->firstname;
268 $grades_by_student["$userid"]['student_data']['lastname'] = $student->lastname;
269 $grades_by_student["$userid"]['student_data']['email'] = $student->email;
270 if (isset($student->location)) {
271 $grades_by_student["$userid"]['student_data']['location'] = $student->location;
273 $grades_by_student["$userid"]['student_data']['department'] = $student->department;
274 $grades_by_student["$userid"]['student_data']['idnumber'] = $student->idnumber;
278 // unset any item that has a "" for a name at this point this inludes instructors who have grades or any student formerly enrolled.
279 if (isset($grades_by_student)) {
280 foreach ($grades_by_student as $student => $assignments) {
281 if (!isset($grades_by_student["$student"]['student_data']['firstname']) && !isset($grades_by_student["$student"]['student_data']['lastname'])) {
282 unset($grades_by_student["$student"]);
288 // set the totalpoints for each category taking into account drop_x_lowest
289 // also set the number of grade items for the category to make calculating grades for students who have not taken anything easier
290 foreach($all_categories as $category => $assignments) {
291 $dropcount = 0;
292 $all_categories["$category"]['stats']['totalpoints'] = 0;
293 $all_categories["$category"]['stats']['grade_items'] = 0;
294 if (isset($assignments)) {
295 foreach($assignments as $assignment=>$grade) {
296 if ($assignment != 'stats') {
297 if ($dropcount < $all_categories["$category"]['stats']['drop']) {
298 // skip a grade in the total
299 $dropcount++;
301 else {
302 // make sure the current assignment is not extra credit and then add it to the totalpoints
303 if ($all_categories["$category"][$assignment]['extra_credit'] != 1) {
304 $all_categories["$category"]['stats']['totalpoints'] = $all_categories["$category"]['stats']['totalpoints'] + $assignments["$assignment"]['grade_against'];
305 $all_categories["$category"]['stats']['grade_items'] = $all_categories["$category"]['stats']['grade_items'] + 1;
314 if (isset($_REQUEST['group'])) {
315 $group = clean_param($_REQUEST['group'], PARAM_INT);
317 // if the user has selected a group to view by get the group members
318 if (isset($group) && $group != 0) {
319 $groupmembers = get_group_users($group);
322 // this next block catches any students who do not have a grade for any item in a particular category
323 foreach($all_categories as $category => $main_category) {
324 // make sure each student has an entry for each category
325 if (isset($grades_by_student)) {
326 foreach($grades_by_student as $student=>$categories) {
327 if ( (isset($groupmembers) && isset($groupmembers[$student])) || !isset($groupmembers)) {
329 $grades_by_student["$student"]["$category"]['stats']['totalpoints'] = $main_category['stats']['totalpoints'];
330 $grades_by_student["$student"]["$category"]['stats']['weight'] = $main_category['stats']['weight'];
331 $grades_by_student["$student"]["$category"]['stats']['grade_items'] = $main_category['stats']['grade_items'];
333 foreach($main_category as $assignment => $items) {
334 if ($assignment != 'stats') {
335 if(!isset($grades_by_student["$student"]["$category"]["$assignment"]['grade'])) {
336 if (isset($grades_by_student["$student"]["$category"]['stats']['allgrades'])) {
337 $grades_by_student["$student"]["$category"]['stats']['allgrades'] .= ',0';
338 } else {
339 $grades_by_student["$student"]["$category"]['stats']['allgrades'] = '0';
345 if (!isset($grades_by_student["$student"]["$category"]['stats']['points'])) {
346 $grades_by_student["$student"]["$category"]['stats']['points'] = '-';
350 else {
351 // points are set... see if the current category is using drop the x lowest and do so
352 // also drop exceptions first, so then this grades(s) won't be recoqnized as the x lowest
353 // Get exception scores and assign them in the array
354 if ($main_category['stats']['drop'] != 0) {
355 $exceptions = grade_get_exceptions_user($course->id, $student);
356 if (isset($exceptions) && $exceptions) {
357 foreach($exceptions as $exception) {
358 if (isset($grades_by_student["$exception->userid"])) {
359 if ($grades_by_student["$exception->userid"]["$exception->catname"]) {
360 $assgn = get_record($exception->modname, 'id', $exception->cminstance, 'course', $course->id);
361 $grade = $grades_by_student["$exception->userid"]["$exception->catname"]["$assgn->name"]['grade'];
362 if (isset($grade)) {
363 if (!isset($grades_by_student["$exception->userid"]["$exception->catname"]['stats']['exceptions'])) {
364 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['exceptions'] = $grade;
366 elseif (isset($grades_by_student["$exception->userid"]["$exception->catname"]['stats']['exceptions'])) {
367 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['exceptions'] .= ','. $grade;
374 if (isset($grades_by_student["$student"]["$category"]['stats']['exceptions'])) {
375 $grades_by_student["$student"]["$category"]['stats']['allgrades'] = grade_drop_exceptions($grades_by_student["$student"]["$category"]['stats']['allgrades'], $grades_by_student["$student"]["$category"]['stats']['exceptions']);
378 $grades_by_student["$student"]["$category"]['stats']['allgrades'] = grade_drop_lowest($grades_by_student["$student"]["$category"]['stats']['allgrades'], $main_category['stats']['drop'], $main_category['stats']['grade_items']);
379 if ($grades_by_student["$student"]["$category"]['stats']['points'] != '-') {
380 $cat_points = 0;
381 $count_grades = explode(',',$grades_by_student["$student"]["$category"]['stats']['allgrades']);
382 foreach($count_grades as $grade) {
383 $cat_points = $cat_points + $grade;
385 $grades_by_student["$student"]["$category"]['stats']['points'] = $cat_points;
390 // add any bonus points for the category
391 if ($all_categories["$category"]['stats']['bonus_points'] != 0) {
392 $grades_by_student["$student"]["$category"]['stats']['points'] = $grades_by_student["$student"]["$category"]['stats']['points'] + $all_categories["$category"]['stats']['bonus_points'];
395 foreach($main_category as $assignment => $items) {
396 if ($assignment != 'stats') {
397 if(!isset($grades_by_student["$student"]["$category"]["$assignment"]['maxgrade'])) {
398 $grades_by_student["$student"]["$category"]["$assignment"]['maxgrade'] = $all_categories["$category"]["$assignment"]['grade_against'];
400 if(!isset($grades_by_student["$student"]["$category"]["$assignment"]['grade'])) {
401 $grades_by_student["$student"]["$category"]["$assignment"]['grade'] = '-';
402 $grades_by_student["$student"]["$category"]["$assignment"]['sort_order'] = $all_categories["$category"]["$assignment"]['sort_order'];
406 } // end groupmember if
407 else {
408 // unset grade since they are not in the selected group.
409 unset($grades_by_student["$student"]);
414 // set the total coursepoints
415 $all_categories['stats']['weight'] = 0;
416 $all_categories['stats']['totalpoints'] = 0;
417 foreach($all_categories as $category => $info) {
418 if ($category != 'stats') {
419 $all_categories['stats']['weight'] = $all_categories['stats']['weight'] + $all_categories["$category"]['stats']['weight'];
420 $all_categories['stats']['totalpoints'] = $all_categories['stats']['totalpoints'] + $all_categories["$category"]['stats']['totalpoints'];
424 // set each individuals total points by category so we can then exclude some grades if set to use exceptions
425 if (isset($grades_by_student)) {
426 foreach($grades_by_student as $student => $categories) {
427 foreach($all_categories as $category => $assignments) {
428 if ($category != 'stats') {
429 $grades_by_student["$student"]["$category"]['stats']['totalpoints'] = $all_categories["$category"]['stats']['totalpoints'];
432 $grades_by_student["$student"]['student_data']['totalpoints'] = $all_categories['stats']['totalpoints'];
436 // take into account any excluded grade_items
437 $strexcluded = get_string('excluded', 'grades');
438 $exceptions = grade_get_exceptions($course->id);
439 if (isset($exceptions) && $exceptions) {
440 foreach($exceptions as $exception) {
441 if (isset($grades_by_student["$exception->userid"])) {
442 if ($grades_by_student["$exception->userid"]["$exception->catname"]) {
443 $assgn = get_record($exception->modname, 'id', $exception->cminstance, 'course', $course->id);
444 $grades_by_student["$exception->userid"]['student_data']['totalpoints'] = $grades_by_student["$exception->userid"]['student_data']['totalpoints'] - $all_categories["$exception->catname"]["$assgn->name"]['maxgrade'];
445 //total point should not be smaller than grade against
446 if ($grades_by_student["$exception->userid"]["$exception->catname"]['stats']['totalpoints'] - $all_categories["$exception->catname"]["$assgn->name"]['grade_against'] != 0 ) {
447 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['totalpoints'] = $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['totalpoints'] - $all_categories["$exception->catname"]["$assgn->name"]['grade_against'];
449 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['grade_items'] = $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['grade_items'] - 1;
450 if ($grades_by_student["$exception->userid"]["$exception->catname"]['stats']['grade_items'] < 0) {
451 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['grade_items'] = 0;
453 if ($all_categories["$exception->catname"]['stats']['drop'] == 0) {
454 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['points'] = $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['points'] - $grades_by_student["$exception->userid"]["$exception->catname"]["$assgn->name"]['grade'];
456 $grades_by_student["$exception->userid"]["$exception->catname"]["$assgn->name"]['maxgrade'] = $strexcluded;
457 $grades_by_student["$exception->userid"]["$exception->catname"]["$assgn->name"]['grade'] = $strexcluded;
458 // see if they are excluded entirely from a category
459 if ($grades_by_student["$exception->userid"]["$exception->catname"]['stats']['totalpoints'] == 0) {
460 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['totalpoints'] = $strexcluded;
461 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['percent'] = $strexcluded;
462 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['points'] = $strexcluded;
463 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['weight'] = $strexcluded;
464 $grades_by_student["$exception->userid"]["$exception->catname"]['stats']['weighted'] = $strexcluded;
468 else {
469 // the user had exceptions, but was unenrolled from the course... we could delete it here, but we will leave it because the user may be re-added to the course
474 if (isset($grades_by_student)) {
475 foreach($grades_by_student as $student => $categories) {
476 $grades_by_student["$student"]['student_data']['points'] = '-';
477 $grades_by_student["$student"]['student_data']['totalpoints'] = 0;
478 $grades_by_student["$student"]['student_data']['weight'] = 0;
479 $grades_by_student["$student"]['student_data']['weighted'] = 0;
480 foreach($categories as $category => $assignments) {
481 if ($category != 'student_data') {
482 // set the student's total points earned
483 if ($grades_by_student["$student"]["$category"]['stats']['points'] != $strexcluded) {
484 if ($grades_by_student["$student"]["$category"]['stats']['points'] != '-') {
485 $grades_by_student["$student"]['student_data']['points'] = $grades_by_student["$student"]['student_data']['points'] + $grades_by_student["$student"]["$category"]['stats']['points'];
487 $grades_by_student["$student"]['student_data']['totalpoints'] = $grades_by_student["$student"]['student_data']['totalpoints'] + $grades_by_student["$student"]["$category"]['stats']['totalpoints'];
490 // set percents and weights for each assignment
491 foreach($assignments as $assignment => $info) {
492 if ($assignment != 'stats') {
493 if ($grades_by_student["$student"]["$category"]["$assignment"]['grade'] != $strexcluded) {
494 if ($grades_by_student["$student"]["$category"]["$assignment"]['maxgrade'] != 0) {
495 $grades_by_student["$student"]["$category"]["$assignment"]['percent'] = round($grades_by_student["$student"]["$category"]["$assignment"]['grade']/$grades_by_student["$student"]["$category"]["$assignment"]['maxgrade']*100,2);
497 else {
498 $grades_by_student["$student"]["$category"]["$assignment"]['percent'] = 0;
500 if ($grades_by_student["$student"]["$category"]['stats']['totalpoints'] != 0) {
501 $grades_by_student["$student"]["$category"]["$assignment"]['weight'] = round($all_categories["$category"]['stats']['weight']*($grades_by_student["$student"]["$category"]["$assignment"]['maxgrade']/$grades_by_student["$student"]["$category"]['stats']['totalpoints']),2);
503 else {
504 $grades_by_student["$student"]["$category"]["$assignment"]['weight'] = 0.00;
506 if ($grades_by_student["$student"]["$category"]["$assignment"]['weight'] != 0) {
507 $grades_by_student["$student"]["$category"]["$assignment"]['weighted'] = round($grades_by_student["$student"]["$category"]["$assignment"]['percent']*$grades_by_student["$student"]["$category"]["$assignment"]['weight']/100,2);
509 else {
510 // should only be here if this is extra credit
511 $grades_by_student["$student"]["$category"]["$assignment"]['weighted'] = 0.00;
514 else {
515 $grades_by_student["$student"]["$category"]["$assignment"]['percent'] = $strexcluded;
516 $grades_by_student["$student"]["$category"]["$assignment"]['weight'] = $strexcluded;
517 $grades_by_student["$student"]["$category"]["$assignment"]['weighted'] = $strexcluded;
521 // set the percent and weight per category
522 if ($grades_by_student["$student"]["$category"]['stats']['totalpoints'] != 0 ) {
523 $grades_by_student["$student"]["$category"]['stats']['percent'] = round($grades_by_student["$student"]["$category"]['stats']['points']/$grades_by_student["$student"]["$category"]['stats']['totalpoints']*100,2);
524 $grades_by_student["$student"]["$category"]['stats']['weighted'] = round($grades_by_student["$student"]["$category"]['stats']['points']/$grades_by_student["$student"]["$category"]['stats']['totalpoints']*$grades_by_student["$student"]["$category"]['stats']['weight'],2);
526 else {
527 if ($grades_by_student["$student"]["$category"]['stats']['totalpoints'] != $strexcluded) {
528 $grades_by_student["$student"]["$category"]['stats']['percent'] = 0.00;
529 $grades_by_student["$student"]["$category"]['stats']['weighted'] = 0.00;
533 // set students overall weight (this is what percent they will be graded against)
534 if ($grades_by_student["$student"]["$category"]['stats']['weight'] != $strexcluded) {
535 $grades_by_student["$student"]['student_data']['weight'] = $grades_by_student["$student"]['student_data']['weight'] + $grades_by_student["$student"]["$category"]['stats']['weight'];
538 // set the students total categories towards point total we have to defer the percent calculation until we know what total weight they should be graded against since they may
539 // be excluded from a whole category.
540 if ($all_categories["$category"]['stats']['totalpoints'] != 0) {
541 $grades_by_student["$student"]['student_data']['weighted'] = $grades_by_student["$student"]['student_data']['weighted'] + $grades_by_student["$student"]["$category"]['stats']['weighted'];
548 // set the percent and weight overall
549 if ($grades_by_student["$student"]['student_data']['totalpoints'] != 0 && $grades_by_student["$student"]['student_data']['totalpoints'] != $strexcluded) {
550 $grades_by_student["$student"]['student_data']['percent'] = round($grades_by_student["$student"]['student_data']['points']/$grades_by_student["$student"]['student_data']['totalpoints']*100,2);
551 if ($grades_by_student["$student"]['student_data']['weight'] != 0) {
552 $grades_by_student["$student"]['student_data']['weighted'] = round($grades_by_student["$student"]['student_data']['weighted']/$grades_by_student["$student"]['student_data']['weight']*100,2);
554 else {
555 $grades_by_student["$student"]['student_data']['weighted'] = 0.00;
558 else if ($grades_by_student["$student"]['student_data']['totalpoints'] == 0) {
559 $grades_by_student["$student"]['student_data']['percent'] = 0.00;
565 if (isset($grades_by_student)) {
566 $sort = optional_param('sort','default');
568 switch ($sort) {
569 case 'highgrade_category':
570 uasort($grades_by_student, 'grade_sort_by_highgrade_category');
571 break;
572 case 'highgrade_category_asc':
573 uasort($grades_by_student, 'grade_sort_by_highgrade_category_asc');
574 break;
575 case 'highgrade':
577 if ($preferences->use_weighted_for_letter == 1) {
578 uasort($grades_by_student, 'grade_sort_by_weighted');
580 else {
581 uasort($grades_by_student, 'grade_sort_by_percent');
583 break;
585 case 'points':
586 uasort($grades_by_student, 'grade_sort_by_points');
587 break;
588 case 'points_asc':
589 uasort($grades_by_student, 'grade_sort_by_points_asc');
590 break;
591 case 'weighted':
592 uasort($grades_by_student, 'grade_sort_by_weighted');
593 break;
594 case 'weighted_asc':
595 uasort($grades_by_student, 'grade_sort_by_weighted_asc');
596 break;
597 case 'percent':
598 uasort($grades_by_student, 'grade_sort_by_percent');
599 break;
600 case 'percent_asc':
601 uasort($grades_by_student, 'grade_sort_by_percent_asc');
602 break;
603 case 'highgrade_asc':
605 if ($preferences->use_weighted_for_letter == 1) {
606 uasort($grades_by_student, 'grade_sort_by_weighted_asc');
608 else {
609 uasort($grades_by_student, 'grade_sort_by_percent_asc');
611 break;
613 case 'firstname':
614 uasort($grades_by_student, 'grade_sort_by_firstname');
615 break;
616 default:
617 uasort($grades_by_student, 'grade_sort_by_lastname');
620 else {
621 $grades_by_student = 0;
623 $retval = array($grades_by_student, $all_categories);
625 else {
626 $retval = array(0,0);
627 // echo "<center><font color=red>Could not find any graded items for this course.</font></center>";
629 return $retval;
632 function grade_drop_exceptions($grades, $grades_exceptions) {
633 $grade_array = explode(',',$grades);
634 $grade_exception_array = explode(',',$grades_exceptions);
635 $ret_grades = Array();
636 foreach ($grade_array as $key => $val) {
637 $posb = array_search($val,$grade_exception_array);
638 if (is_integer($posb)) {
639 unset($grade_exception_array[$posb]);
640 } else {
642 $ret_grades[] = $val;
645 $grades = implode(',', $ret_grades);
646 return $grades;
649 function grade_drop_lowest($grades, $drop, $total) {
650 // drops the lowest $drop numbers from the comma seperated $grades making sure that if $grades has
651 // fewer items than $total that we don't drop too many
652 $grade_array = explode(',',$grades);
653 if (count($grade_array) == 1) {
654 $grades = implode('', $grade_array);
656 else if ($drop > 0 AND (count($grade_array) > $drop)) {
657 rsort($grade_array);
659 for($i=0; $i < (count($grade_array) - $drop); $i++) {
660 $ret_grades["$i"] = $grade_array["$i"];
662 if (isset($ret_grades)) {
663 $grades = implode(',',$ret_grades);
666 else {
667 $grades = 0;
669 return $grades;
672 function grade_get_grades() {
673 global $CFG;
674 global $course;
675 $mods = grade_get_grade_items($course->id);
676 $preferences = grade_get_preferences($course->id);
678 if ($mods) {
679 foreach ($mods as $mod) {
680 // hidden is a gradebook setting for an assignment and visible is a course_module setting
681 if (($mod->hidden != 1 && $mod->visible==1) or (has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_MODULE, $mod->id)) && $preferences->show_hidden==1)) {
682 $libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
683 if (file_exists($libfile)) {
684 require_once($libfile);
685 $gradefunction = $mod->modname."_grades";
686 if ($grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"] = $gradefunction($mod->cminstance)) {
687 // added grades for particular mod
688 // now get the grade_item modifiers ie. scale_grade and extra credit
689 $scale_grade = get_record('grade_item', 'courseid', $course->id, 'cminstance', $mod->cminstance, 'modid', $mod->modid);
691 if (isset($scale_grade)) {
692 $grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->scale_grade = $scale_grade->scale_grade;
693 $grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->extra_credit = $scale_grade->extra_credit;
695 else {
696 $grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->scale_grade = 1.00;
697 $grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->extra_credit = 0;
700 if ($mod->hidden != 1 && $mod->visible==1) {
701 $grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->hidden = 0;
703 else {
704 $grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->hidden = 1;
707 $grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->sort_order = $scale_grade->sort_order;
709 // I don't think this should be necessary but it appears that the forum doesn't follow the grades API properly it returns blank or NULL when it
710 // should return a value for maxgrade according to the moodle API... so if it doesn't want to give us a grade let's not use it.
711 // this happens when grading is set to a non-numeric for a forum ie. uses "seperate and connected ways of knowing"
712 if ($grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->maxgrade == '')
714 $grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]->maxgrade = 100;
715 //unset($grades["$mod->cname"]["$mod->modid"]["$mod->cminstance"]);
718 else {
719 // delete this item from the grade_item table since it was deleted through the mod interface
720 delete_records('grade_item', 'modid', $mods->modid, 'courseid', $course->id);
721 delete_records('grade_exceptions', 'grade_itemid', $mod->id, 'courseid', $course->id);
724 else {
725 //echo "<center><font color=red>Could not find lib file for $mod->modid</font></center>";
730 else {
731 // Do something here for no grades
732 //echo "<center><font color=red>No grades returned. It appears that there are no items with grades for this course.</font></center>";
734 if (isset($grades)) {
735 return $grades;
737 else {
738 return NULL;
742 function grade_set_uncategorized() {
743 // this function checks to see if any mods have not been assigned a category and sets them to uncategorized.
744 global $CFG;
745 global $course;
746 $uncat = UNCATEGORISED;
748 $uncat_id = get_record('grade_category', 'courseid', $course->id, 'name', $uncat);
750 if (!$uncat_id) {
751 // insert the uncategorized category
752 $temp->name=$uncat;
753 $temp->courseid=$course->id;
754 $temp->drop_x_lowest = 0;
755 $temp->bonus_points = 0;
756 $temp->hidden = 0;
757 $temp->weight = 100.00;
759 insert_record('grade_category', $temp);
760 $uncat_id = get_record('grade_category', 'courseid', $course->id, 'name', $uncat);
761 if (!$uncat_id) {
762 error(get_string('errornocategorizedid','grades'));
763 exit(0);
768 /// Collect modules data
769 get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
770 $itemcount = 0;
772 // this will let us establish the order for gradebook item display
773 $sort = 0;
775 /// Search through all the modules, pulling out grade data
776 $sections = get_all_sections($course->id); // Sort everything the same as the course
777 for ($i=0; $i<=$course->numsections; $i++) {
778 if (isset($sections["$i"])) { // should always be true
779 $section = $sections["$i"];
780 if ($section->sequence) {
781 $sectionmods = explode(",", $section->sequence);
782 foreach ($sectionmods as $sectionmod) {
783 if (isset($mods["$sectionmod"])) {
784 $mod = $mods["$sectionmod"];
785 $instance = get_record("$mod->modname", "id", "$mod->instance");
786 $libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
787 if (file_exists($libfile)) {
788 require_once($libfile);
789 $gradefunction = $mod->modname."_grades";
790 if (function_exists($gradefunction)) { // Skip modules without grade function
791 if ($modgrades = $gradefunction($mod->instance)) {
792 $itemcount++;
793 //modgrades contains student information with associated grade
794 //echo "<b>modname: $mod->modname id: $mod->id course: $mod->course</b><br/>";
795 // get instance name from db.
796 $instance = get_record($mod->modname, 'id', $mod->instance);
797 // see if the item is already in the category table and if it is call category select with the id so it is selected
798 get_record('modules', 'name', $mod->modname);
799 $item = get_record('grade_item', 'courseid', $course->id, 'modid', $mod->module, 'cminstance', $mod->instance);
800 if (!$item) {
801 // set the item to uncategorized in grade_item
802 $item->courseid = $course->id;
803 $item->category = $uncat_id->id;
804 $item->modid = $mod->module;
805 $item->cminstance = $mod->instance;
806 $item->id = insert_record('grade_item', $item);
808 else if ($item->category == 0) {
809 // this catches any errors where they may have some wierd category set
810 set_field('grade_item', 'category', $uncat_id->id, 'id', $item->id);
812 set_field('grade_item', 'sort_order', $sort, 'id', $item->id);
813 $sort++;
824 // sorting functions for grades
825 function grade_sort_by_lastname($x,$y)
827 //$grades_by_student["$student->userid"]['student_data']['firstname'] = $student->firstname;
828 //$grades_by_student["$student->userid"]['student_data']['lastname'] = $student->lastname;
829 if (strnatcasecmp($x['student_data']['lastname'],$y['student_data']['lastname']) == 0) {
830 return strnatcasecmp($x['student_data']['firstname'],$y['student_data']['firstname']);
832 else {
833 return strnatcasecmp($x['student_data']['lastname'],$y['student_data']['lastname']);
837 function grade_sort_by_firstname($x,$y)
839 //$grades_by_student["$student->userid"]['student_data']['firstname'] = $student->firstname;
840 //$grades_by_student["$student->userid"]['student_data']['lastname'] = $student->lastname;
841 if (strnatcasecmp($x['student_data']['firstname'],$y['student_data']['firstname']) == 0) {
842 return strnatcasecmp($x['student_data']['lastname'],$y['student_data']['lastname']);
844 else {
845 return strnatcasecmp($x['student_data']['firstname'],$y['student_data']['firstname']);
849 function grade_sort_by_points($x,$y) {
850 if ($x['student_data']['points'] == $y['student_data']['points']) {
851 return grade_sort_by_lastname($x,$y);
853 else {
854 if ($x['student_data']['points'] > $y['student_data']['points'])
855 return -1;
856 else
857 return 1;
861 function grade_sort_by_points_asc($x,$y) {
862 if ($x['student_data']['points'] == $y['student_data']['points']) {
863 return grade_sort_by_lastname($x,$y);
865 else {
866 if ($x['student_data']['points'] < $y['student_data']['points'])
867 return -1;
868 else
869 return 1;
873 function grade_sort_by_weighted($x,$y) {
874 if ($x['student_data']['weighted'] == $y['student_data']['weighted']) {
875 return grade_sort_by_lastname($x,$y);
877 else {
878 if ($x['student_data']['weighted'] > $y['student_data']['weighted'])
879 return -1;
880 else
881 return 1;
885 function grade_sort_by_percent($x,$y) {
886 if ($x['student_data']['percent'] == $y['student_data']['percent']) {
887 return grade_sort_by_lastname($x,$y);
889 else {
890 if ($x['student_data']['percent'] > $y['student_data']['percent'])
891 return -1;
892 else
893 return 1;
897 function grade_sort_by_percent_asc($x,$y) {
898 if ($x['student_data']['percent'] == $y['student_data']['percent']) {
899 return grade_sort_by_lastname($x,$y);
901 else {
902 if ($x['student_data']['percent'] < $y['student_data']['percent'])
903 return -1;
904 else
905 return 1;
909 function grade_sort_by_weighted_asc($x,$y) {
910 if ($x['student_data']['weighted'] == $y['student_data']['weighted']) {
911 return grade_sort_by_lastname($x,$y);
913 else {
914 if ($x['student_data']['weighted'] < $y['student_data']['weighted'])
915 return -1;
916 else
917 return 1;
921 function grade_sort_by_highgrade_category($x,$y) {
922 global $cview;
924 if(!$cview) {
925 $cview = optional_param('cview');
928 if ($x["$cview"]['stats']['points'] == $y["$cview"]['stats']['points']) {
929 return grade_sort_by_lastname($x,$y);
931 else {
932 return ($y["$cview"]['stats']['points'] - $x["$cview"]['stats']['points']);
936 function grade_sort_by_highgrade_category_asc($x,$y) {
937 global $cview;
939 if(!$cview)
940 $cview = optional_param('cview');
942 if ($x["$cview"]['stats']['points'] == $y["$cview"]['stats']['points']) {
943 return grade_sort_by_lastname($x,$y);
945 else {
946 return ($x["$cview"]['stats']['points'] - $y["$cview"]['stats']['points']);
951 function grade_set_preference($courseid, $name, $value) {
952 global $GRADEPREFS;
954 if (false !== ($key = array_search($name, $GRADEPREFS))) {
955 if ($record = get_record('grade_preferences', 'courseid', $courseid, 'preference', $key)) {
956 $record->value = $value;
957 update_record('grade_preferences', $record);
958 } else { // Make a new one
959 $record->preference = $key;
960 $record->courseid = $courseid;
961 $record->value = $value;
962 insert_record('grade_preferences', $record);
967 function grade_get_preference($courseid, $name) {
968 global $GRADEPREFS, $GRADEPREFSDEFAULTS;
970 if (false !== ($key = array_search($name, $GRADEPREFS))) {
971 if (!($record = get_record('grade_preferences', 'courseid', $courseid, 'preference', $key))) {
972 // Make a new one
973 $record->preference = $key;
974 $record->courseid = $courseid;
975 $record->value = $GRADEPREFSDEFAULTS[$name];
976 insert_record('grade_preferences', $record);
978 return $record->value;
980 return NULL;
983 function grade_get_preferences($courseid) {
984 global $CFG;
985 global $GRADEPREFS, $GRADEPREFSDEFAULTS;
987 $preferences = NULL;
989 // Get the preferences for the course.
990 if ($rawprefs = get_records('grade_preferences', 'courseid', $courseid)) {
991 foreach ($rawprefs as $pref) {
992 if (isset($GRADEPREFS[$pref->preference])) { // Valid pref
993 $name = $GRADEPREFS[$pref->preference];
994 $preferences->$name = $pref->value;
999 // Check for any missing ones and create them from defaults
1000 // We don't save them in the database so we save space
1001 foreach ($GRADEPREFS as $number => $name) {
1002 if (!isset($preferences->$name)) {
1003 $preferences->$name = $GRADEPREFSDEFAULTS[$name];
1007 // Construct some other ones about which fields are shown
1009 $isteacher = has_capability('moodle/course:managegrades', get_context_instance(CONTEXT_COURSE, $courseid));
1011 $preferences->show_weighted = (($preferences->display_weighted > 0 && $isteacher) ||
1012 ($preferences->display_weighted > 1 && !$isteacher));
1014 $preferences->show_points = (($preferences->display_points > 0 && $isteacher) ||
1015 ($preferences->display_points > 1 && !$isteacher));
1017 $preferences->show_percent = (($preferences->display_percent > 0 && $isteacher) ||
1018 ($preferences->display_percent > 1 && !$isteacher));
1020 $preferences->show_letters = (($preferences->display_letters > 0 && $isteacher) ||
1021 ($preferences->display_letters > 1 && !$isteacher));
1023 return $preferences;
1027 function grade_set_preferences($course, $newprefs) {
1029 if (!isset($newprefs->use_advanced) or ($newprefs->use_advanced == 1)) {
1030 foreach ($newprefs as $name => $value) { /// Just save them all
1031 grade_set_preference($course->id, $name, $value);
1033 return true;
1036 /// We don't need advanced features, and we need to unset all extra features
1037 /// So they don't affect grades (This approach should be revisited because it resets everything!!)
1039 grade_set_preference($course->id, 'use_advanced', 0);
1040 grade_set_preference($course->id, 'use_weighted_for_letter', 0);
1041 grade_set_preference($course->id, 'display_weighted', 0);
1042 grade_set_preference($course->id, 'display_points', 2);
1043 grade_set_preference($course->id, 'display_percent', 0);
1044 grade_set_preference($course->id, 'display_letters', 0);
1046 /// Lose all exceptions
1047 delete_records('grade_exceptions', 'courseid', $course->id);
1049 if (!$uncat = get_record('grade_category', 'courseid', $course->id, 'name', UNCATEGORISED)) {
1050 /// Make a category for uncategorised stuff
1051 $uncat->name=UNCATEGORISED;
1052 $uncat->courseid=$course->id;
1053 if (!$uncat->id = insert_record('grade_category', $uncat)) {
1054 error(get_string('errornocategorizedid','grades'));
1058 set_field('grade_item', 'category', $uncat->id, 'courseid', $course->id);
1059 set_field('grade_item', 'scale_grade', 1.00, 'courseid', $course->id);
1060 set_field('grade_item', 'extra_credit', 0, 'courseid', $course->id);
1062 set_field('grade_category', 'weight', 100.0, 'courseid', $course->id, 'id', $uncat->id);
1063 set_field('grade_category', 'bonus_points', '0', 'courseid', $course->id);
1067 function grade_preferences_menu($action, $course, $group=0) {
1069 if (!has_capability('moodle/course:managegrades', get_context_instance(CONTEXT_COURSE, $course->id))) {
1070 return;
1073 // remap some actions to simplify later code
1074 switch ($action) {
1075 case 'prefs':
1076 case 'set_grade_preferences':
1077 $curraction = 'prefs';
1078 break;
1079 case 'cats':
1080 case 'vcats':
1081 $curraction = '';
1082 break;
1083 case 'insert_category':
1084 case 'assign_categories':
1085 case 'delete_category':
1086 $curraction = 'cats';
1087 break;
1088 case 'set_grade_weights':
1089 case 'weights':
1090 $curraction = 'weights';
1091 break;
1092 case 'letters':
1093 case 'set_letter_grades':
1094 $curraction = 'letters';
1095 break;
1096 case 'view_student_grades':
1097 case 'view_student_category_grades':
1098 case 'grades':
1099 $curraction = 'grades';
1100 break;
1101 case 'excepts':
1102 $curraction = 'excepts';
1103 break;
1105 default:
1106 $curraction = 'grades';
1109 $tabs = $row = array();
1110 $row[] = new tabobject('grades', 'index.php?id='.$course->id,
1111 get_string('viewgrades', 'grades'));
1112 $row[] = new tabobject('prefs', 'index.php?id='.$course->id.'&amp;action=prefs',
1113 get_string('setpreferences', 'grades'));
1114 // only show the extra options if advanced is turned on, they don't do anything otherwise
1115 if (grade_get_preference($course->id, 'use_advanced') == 1) {
1116 $row[] = new tabobject('cats', 'index.php?id='.$course->id.'&amp;action=cats',
1117 get_string('setcategories', 'grades'));
1118 $row[] = new tabobject('weights', 'index.php?id='.$course->id.'&amp;action=weights',
1119 get_string('setweights', 'grades'));
1120 $row[] = new tabobject('letters', 'index.php?id='.$course->id.'&amp;action=letters',
1121 get_string('setgradeletters', 'grades'));
1122 $row[] = new tabobject('excepts', 'exceptions.php?id='.$course->id.'&amp;action=excepts',
1123 get_string('gradeexceptions', 'grades'));
1125 $tabs[] = $row;
1127 print_tabs($tabs, $curraction);
1131 function grade_nav($course, $action='grades') {
1132 global $CFG;
1133 global $USER;
1134 global $cview;
1136 $strgrades = get_string('grades', 'grades');
1137 $gradenav = "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a>";
1139 if (has_capability('moodle/course:managegrades', get_context_instance(CONTEXT_COURSE, $course->id))) {
1140 switch ($action) {
1141 case 'prefs':
1142 case 'set_grade_preferences':
1143 $strcurpage = get_string('setpreferences','grades');
1144 break;
1145 case 'cats':
1146 case 'delete_category':
1147 case 'cats':
1148 case 'insert_category':
1149 case 'assign_categories':
1150 $strcurpage = get_string('setcategories','grades');
1151 break;
1152 case 'weights':
1153 case 'set_grade_weights':
1154 $strcurpage = get_string('setweights','grades');
1155 break;
1156 case 'set_letter_grades':
1157 case 'letters':
1158 $strcurpage = get_string('setgradeletters','grades');
1159 break;
1160 case 'excepts':
1161 $strcurpage = get_string('gradeexceptions', 'grades');
1162 break;
1163 default:
1164 unset($strcurpage);
1165 break;
1168 if ($action=='grades') {
1169 $gradenav .= " -> $strgrades";
1170 } else {
1171 $gradenav .= " -> <a href=\"index.php?id=$course->id&amp;action=grades\">$strgrades</a>";
1174 // if we are on a grades sub-page provide a link back (including grade preferences and grade items
1176 if (isset($strcurpage)) {
1177 $gradenav .= " -> $strcurpage";
1178 } else if($action =='vcats') {
1179 // show sub category
1180 if (isset($cview)) {
1181 $gradenav .= " -> $cview";
1185 } else {
1186 $gradenav .= " -> $strgrades";
1189 return $gradenav;
1192 function grade_download($download, $id) {
1193 global $CFG;
1195 require_login();
1197 if (! $course = get_record("course", "id", $id)) {
1198 error("Course ID was incorrect");
1201 require_capability('moodle/course:viewcoursegrades', get_context_instance(CONTEXT_COURSE, $id));
1203 $strgrades = get_string("grades");
1204 $strgrade = get_string("grade");
1205 $strmax = get_string("maximumshort");
1206 $stractivityreport = get_string("activityreport");
1208 /// Check to see if groups are being used in this course
1209 if ($groupmode = groupmode($course)) { // Groups are being used
1210 if (isset($_GET['group'])) {
1211 $changegroup = $_GET['group']; /// 0 or higher
1212 } else {
1213 $changegroup = -1; /// This means no group change was specified
1216 $currentgroup = get_and_set_current_group($course, $groupmode, $changegroup);
1217 } else {
1218 $currentgroup = false;
1221 if ($currentgroup) {
1222 $students = get_group_students($currentgroup, "u.lastname ASC");
1223 } else {
1224 $students = grade_get_course_students($course->id);
1227 if (!empty($students)) {
1228 foreach ($students as $student) {
1229 $grades[$student->id] = array(); // Collect all grades in this array
1230 $gradeshtml[$student->id] = array(); // Collect all grades html formatted in this array
1231 $totals[$student->id] = array(); // Collect all totals in this array
1234 $columns = array(); // Accumulate column names in this array.
1235 $columnhtml = array(); // Accumulate column html in this array.
1238 /// Collect modules data
1239 get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
1241 /// Search through all the modules, pulling out grade data
1242 $sections = get_all_sections($course->id); // Sort everything the same as the course
1243 for ($i=0; $i<=$course->numsections; $i++) {
1244 if (isset($sections[$i])) { // should always be true
1245 $section = $sections[$i];
1246 if ($section->sequence) {
1247 $sectionmods = explode(",", $section->sequence);
1248 foreach ($sectionmods as $sectionmod) {
1249 $mod = $mods[$sectionmod];
1250 $instance = get_record("$mod->modname", "id", "$mod->instance");
1251 $libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
1253 if (file_exists($libfile)) {
1254 require_once($libfile);
1255 $gradefunction = $mod->modname."_grades";
1256 if (function_exists($gradefunction)) { // Skip modules without grade function
1257 if ($modgrades = $gradefunction($mod->instance)) {
1258 if (!empty($modgrades->maxgrade)) {
1259 if ($mod->visible) {
1260 $maxgrade = "$strmax: $modgrades->maxgrade";
1261 } else {
1262 $maxgrade = "$strmax: $modgrades->maxgrade";
1264 } else {
1265 $maxgrade = "";
1268 $columns[] = "$mod->modfullname: ".format_string($instance->name,true)." - $maxgrade";
1270 if (!empty($students)) {
1271 foreach ($students as $student) {
1272 if (!empty($modgrades->grades[$student->id])) {
1273 $grades[$student->id][] = $currentstudentgrade = $modgrades->grades[$student->id];
1274 } else {
1275 $grades[$student->id][] = $currentstudentgrade = "";
1276 $gradeshtml[$student->id][] = "";
1278 if (!empty($modgrades->maxgrade)) {
1279 $totals[$student->id] = (float)($totals[$student->id]) + (float)($currentstudentgrade);
1280 } else {
1281 $totals[$student->id] = (float)($totals[$student->id]) + 0;
1291 } // a new Moodle nesting record? ;-)
1293 /// OK, we have all the data, now present it to the user
1294 /// OK, we have all the data, now present it to the user
1295 if ($download == "ods" and confirm_sesskey()) {
1296 require_once("../lib/odslib.class.php");
1298 /// Calculate file name
1299 $downloadfilename = clean_filename("$course->shortname $strgrades.ods");
1300 /// Creating a workbook
1301 $workbook = new MoodleODSWorkbook("-");
1302 /// Sending HTTP headers
1303 $workbook->send($downloadfilename);
1304 /// Adding the worksheet
1305 $myxls =& $workbook->add_worksheet($strgrades);
1307 /// Print names of all the fields
1308 $myxls->write_string(0,0,get_string("firstname"));
1309 $myxls->write_string(0,1,get_string("lastname"));
1310 $myxls->write_string(0,2,get_string("idnumber"));
1311 $myxls->write_string(0,3,get_string("institution"));
1312 $myxls->write_string(0,4,get_string("department"));
1313 $myxls->write_string(0,5,get_string("email"));
1314 $pos=6;
1315 foreach ($columns as $column) {
1316 $myxls->write_string(0,$pos++,strip_tags($column));
1318 $myxls->write_string(0,$pos,get_string("total"));
1320 /// Print all the lines of data.
1321 $i = 0;
1322 if (!empty($grades)) {
1323 foreach ($grades as $studentid => $studentgrades) {
1324 $i++;
1325 $student = $students[$studentid];
1326 if (empty($totals[$student->id])) {
1327 $totals[$student->id] = '';
1330 $myxls->write_string($i,0,$student->firstname);
1331 $myxls->write_string($i,1,$student->lastname);
1332 $myxls->write_string($i,2,$student->idnumber);
1333 $myxls->write_string($i,3,$student->institution);
1334 $myxls->write_string($i,4,$student->department);
1335 $myxls->write_string($i,5,$student->email);
1336 $j=6;
1337 foreach ($studentgrades as $grade) {
1338 if (is_numeric($grade)) {
1339 $myxls->write_number($i,$j++,strip_tags($grade));
1341 else {
1342 $myxls->write_string($i,$j++,strip_tags($grade));
1345 $myxls->write_number($i,$j,$totals[$student->id]);
1349 /// Close the workbook
1350 $workbook->close();
1352 exit;
1354 } else if ($download == "xls" and confirm_sesskey()) {
1355 require_once("../lib/excellib.class.php");
1357 /// Calculate file name
1358 $downloadfilename = clean_filename("$course->shortname $strgrades.xls");
1359 /// Creating a workbook
1360 $workbook = new MoodleExcelWorkbook("-");
1361 /// Sending HTTP headers
1362 $workbook->send($downloadfilename);
1363 /// Adding the worksheet
1364 $myxls =& $workbook->add_worksheet($strgrades);
1366 /// Print names of all the fields
1367 $myxls->write_string(0,0,get_string("firstname"));
1368 $myxls->write_string(0,1,get_string("lastname"));
1369 $myxls->write_string(0,2,get_string("idnumber"));
1370 $myxls->write_string(0,3,get_string("institution"));
1371 $myxls->write_string(0,4,get_string("department"));
1372 $myxls->write_string(0,5,get_string("email"));
1373 $pos=6;
1374 foreach ($columns as $column) {
1375 $myxls->write_string(0,$pos++,strip_tags($column));
1377 $myxls->write_string(0,$pos,get_string("total"));
1379 /// Print all the lines of data.
1380 $i = 0;
1381 if (!empty($grades)) {
1382 foreach ($grades as $studentid => $studentgrades) {
1383 $i++;
1384 $student = $students[$studentid];
1385 if (empty($totals[$student->id])) {
1386 $totals[$student->id] = '';
1389 $myxls->write_string($i,0,$student->firstname);
1390 $myxls->write_string($i,1,$student->lastname);
1391 $myxls->write_string($i,2,$student->idnumber);
1392 $myxls->write_string($i,3,$student->institution);
1393 $myxls->write_string($i,4,$student->department);
1394 $myxls->write_string($i,5,$student->email);
1395 $j=6;
1396 foreach ($studentgrades as $grade) {
1397 if (is_numeric($grade)) {
1398 $myxls->write_number($i,$j++,strip_tags($grade));
1400 else {
1401 $myxls->write_string($i,$j++,strip_tags($grade));
1404 $myxls->write_number($i,$j,$totals[$student->id]);
1408 /// Close the workbook
1409 $workbook->close();
1411 exit;
1413 } else if ($download == "txt" and confirm_sesskey()) {
1415 /// Print header to force download
1417 header("Content-Type: application/download\n");
1418 $downloadfilename = clean_filename("$course->shortname $strgrades");
1419 header("Content-Disposition: attachment; filename=\"$downloadfilename.txt\"");
1421 /// Print names of all the fields
1423 echo get_string("firstname")."\t".
1424 get_string("lastname")."\t".
1425 get_string("idnumber")."\t".
1426 get_string("institution")."\t".
1427 get_string("department")."\t".
1428 get_string("email");
1429 foreach ($columns as $column) {
1430 $column = strip_tags($column);
1431 echo "\t$column";
1433 echo "\t".get_string("total")."\n";
1435 /// Print all the lines of data.
1436 foreach ($grades as $studentid => $studentgrades) {
1437 $student = $students[$studentid];
1438 if (empty($totals[$student->id])) {
1439 $totals[$student->id] = '';
1441 echo "$student->firstname\t$student->lastname\t$student->idnumber\t$student->institution\t$student->department\t$student->email";
1442 foreach ($studentgrades as $grade) {
1443 $grade = strip_tags($grade);
1444 echo "\t$grade";
1446 echo "\t".$totals[$student->id];
1447 echo "\n";
1450 exit;
1452 }else if ($download == '' and confirm_sesskey()) {
1453 error("No file type specified");
1454 exit;
1458 function grade_get_stats($category='all') {
1459 list($grades_by_student, $all_categories) = grade_get_formatted_grades();
1461 if ($grades_by_student != 0 && $all_categories != 0) {
1462 switch($category) {
1463 case 'all':
1465 //populate the sum of student points, # items and totalpoints for each category
1466 foreach($grades_by_student as $student=>$categories) {
1467 foreach($categories as $cur_category=>$assignments) {
1468 if($category != 'student_data') {
1469 if (isset($assignments['stats'])) {
1470 if (isset($stats[$cur_category]['sum'])) {
1471 $stats[$cur_category]['sum'] = $stats[$cur_category]['sum'] + $assignments['stats']['points'];
1473 else {
1474 $stats[$cur_category]['sum'] = $assignments['stats']['points'];
1476 $stats[$cur_category]['items'] = $assignments['stats']['grade_items'];
1477 $stats[$cur_category]['totalpoints'] = $assignments['stats']['totalpoints'];
1478 $stats[$cur_category]['weight'] = $all_categories[$cur_category]['stats']['weight'];
1483 // populate the overall sum,items and totalpoints
1484 foreach($stats as $cur_category=>$info) {
1485 if($cur_category != 'all' && $cur_category != 'student_data') {
1487 if ($stats[$cur_category]['totalpoints'] == get_string('excluded', 'grades')) {
1488 $stats[$cur_category]['totalpoints'] = 1;
1489 $stats['all']['sum'] = $stats['all']['sum'] + $stats[$cur_category]['sum'];
1490 $stats['all']['items'] = $stats['all']['items'] + $stats[$cur_category]['items'];
1491 $stats['all']['totalpoints'] = $stats['all']['totalpoints'] + $stats[$cur_category]['totalpoints'];
1492 $stats['all']['weighted_sum'] = $stats['all']['weighted_sum'] + ($stats[$cur_category]['sum']/($stats[$cur_category]['totalpoints']))*$stats[$cur_category]['weight'];
1495 else if (isset($stats['all'])) {
1496 $stats['all']['sum'] = $stats['all']['sum'] + $stats[$cur_category]['sum'];
1497 $stats['all']['items'] = $stats['all']['items'] + $stats[$cur_category]['items'];
1498 $stats['all']['totalpoints'] = $stats['all']['totalpoints'] + $stats[$cur_category]['totalpoints'];
1499 $stats['all']['weighted_sum'] = $stats['all']['weighted_sum'] + ($stats[$cur_category]['sum']/($stats[$cur_category]['totalpoints']))*$stats[$cur_category]['weight'];
1501 else {
1502 $stats['all']['sum'] = $stats[$cur_category]['sum'];
1503 $stats['all']['items'] = $stats[$cur_category]['items'];
1504 $stats['all']['totalpoints'] = $stats[$cur_category]['totalpoints'];
1505 $stats['all']['weighted_sum'] = ($stats[$cur_category]['sum']/($stats[$cur_category]['totalpoints']))*$stats[$cur_category]['weight'];
1510 $stats['all']['students'] = count($grades_by_student);
1511 $stats['all']['average'] = $stats['all']['sum'] / $stats['all']['students'];
1512 $stats['all']['average_weighted'] = $stats['all']['weighted_sum']/$stats['all']['students'];
1514 // calculate the average squared deviation and populate a list of all scores while we're at it
1515 $stats['all']['avgsqddev'] = 0;
1516 $stats['all']['avgsqddev_weighted'] = 0;
1517 foreach($grades_by_student as $student=>$categories) {
1518 foreach($categories as $cur_category=>$assignments) {
1519 if ($cur_category != 'student_data') {
1520 $stats['all']['avgsqddev'] = $stats['all']['avgsqddev'] + pow(($grades_by_student[$student]['student_data']['points']-$stats['all']['average']),2);
1521 $stats['all']['avgsqddev_weighted'] = $stats['all']['avgsqddev_weighted'] + pow(($grades_by_student[$student]['student_data']['weighted']-$stats['all']['average_weighted']),2);
1524 if (isset($stats['all']['all_scores'])) {
1525 $stats['all']['all_scores'] .= ','.$grades_by_student[$student]['student_data']['points'];
1526 $stats['all']['all_scores_weighted'] .= ','.$grades_by_student[$student]['student_data']['weighted'];
1528 else {
1529 $stats['all']['all_scores'] = $grades_by_student[$student]['student_data']['points'];
1530 $stats['all']['all_scores_weighted'] = $grades_by_student[$student]['student_data']['weighted'];
1533 $stats['all']['avgsqddev']=$stats['all']['avgsqddev']/$stats['all']['students'];
1534 $stats['all']['avgsqddev_weighted']=$stats['all']['avgsqddev_weighted']/$stats['all']['students'];
1535 $stats['all']['stddev'] = sqrt($stats['all']['avgsqddev']);
1536 $stats['all']['stddev_weighted'] = sqrt($stats['all']['avgsqddev_weighted']);
1537 $stats['all']['mode'] = grade_mode($stats['all']['all_scores']);
1538 $stats['all']['mode_weighted'] = grade_mode($stats['all']['all_scores_weighted']);
1540 // make sure the mode is not set to every score
1541 if(count($stats['all']['mode']) == count($grades_by_student)) {
1542 $stats['all']['mode'] = get_string('nomode','grade');
1544 if(count($stats['all']['mode_weighted']) == count($grades_by_student)) {
1545 $stats['all']['mode_weighted'] = get_string('nomode','grade');
1547 break;
1549 default:
1551 // get the stats for category
1552 //populate the sum of student points, # items and totalpoints for each category
1553 foreach($grades_by_student as $student=>$categories) {
1554 if(isset($grades_by_student[$student][$category]['stats'])) {
1555 if (isset($stats[$category]['sum'])) {
1556 $stats[$category]['sum'] = $stats[$category]['sum'] + $grades_by_student[$student][$category]['stats']['points'];
1558 else {
1559 $stats[$category]['sum'] = $grades_by_student[$student][$category]['stats']['points'];
1561 $stats[$category]['items'] = $grades_by_student[$student][$category]['stats']['grade_items'];
1562 $stats[$category]['totalpoints'] = $grades_by_student[$student][$category]['stats']['totalpoints'];
1565 $stats[$category]['students'] = count($grades_by_student);
1566 $stats[$category]['average'] = $stats[$category]['sum']/$stats[$category]['students'];
1568 // calculate the average squared deviation and populate a list of all scores too
1569 $stats[$category]['avgsqddev'] = 0;
1570 foreach($grades_by_student as $student=>$categories) {
1571 foreach($categories as $cur_category=>$assignment) {
1572 if ($cur_category != 'student_data') {
1573 if ($grades_by_student[$student][$category]['stats']['points'] == '-' || $grades_by_student[$student][$category]['stats']['points'] == get_string('grades','excluded')) {
1574 // count grade as a zero
1575 $stats[$category]['avgsqddev'] = $stats[$category]['avgsqddev'] + pow(($stats[$category]['average']),2);
1577 else {
1578 $stats[$category]['avgsqddev'] = $stats[$category]['avgsqddev'] + pow(($grades_by_student[$student][$category]['stats']['points']-$stats[$category]['average']),2);
1583 if (isset($stats[$category]['all_scores'])) {
1584 $stats[$category]['all_scores'] .= ','.$grades_by_student[$student][$category]['stats']['points'];
1586 else {
1587 $stats[$category]['all_scores'] = $grades_by_student[$student][$category]['stats']['points'];
1590 $stats[$category]['avgsqddev'] = $stats[$category]['avgsqddev']/$stats[$category]['students'];
1591 $stats[$category]['stddev'] = sqrt($stats[$category]['avgsqddev']);
1592 $stats[$category]['mode'] = grade_mode($stats[$category]['all_scores']);
1593 break;
1595 } // end switch
1596 // do a little cleanup
1597 $stats[$category]['stddev'] = sprintf("%0.2f", $stats[$category]['stddev']);
1598 $stats[$category]['average'] = sprintf("%0.2f", $stats[$category]['average']);
1599 $stats[$category]['max'] = max(explode(',',$stats[$category]['all_scores']));
1600 $stats[$category]['min'] = min(explode(',',$stats[$category]['all_scores']));
1601 $stats[$category]['median'] = explode(',',$stats[$category]['all_scores']);
1603 if (isset($stats[$category]['stddev_weighted'])) {
1604 $stats[$category]['stddev_weighted'] = sprintf("%0.2f", $stats[$category]['stddev_weighted']);
1606 if (isset($stats[$category]['average_weighted'])) {
1607 $stats[$category]['average_weighted'] = sprintf("%0.2f", $stats[$category]['average_weighted']);
1609 if (isset($stats[$category]['max_weighted'])) {
1610 $stats[$category]['max_weighted'] = max(explode(',',$stats[$category]['all_scores_weighted']));
1612 if (isset($stats[$category]['min_weighted'])) {
1613 $stats[$category]['min_weighted'] = min(explode(',',$stats[$category]['all_scores_weighted']));
1616 if (isset($stats[$category]['all_scores_weighted'])) {
1617 $stats[$category]['median_weighted'] = explode(',',$stats[$category]['all_scores_weighted']);
1619 else {
1624 sort($stats[$category]['median']);
1626 if (count($stats[$category]['median'])/2 == floor(count($stats[$category]['median'])/2) ) {
1627 // even number of scores
1628 $temp = $stats[$category]['median'][count($stats[$category]['median'])/2-1] + $stats[$category]['median'][count($stats[$category]['median'])/2];
1629 $temp = $temp/2;
1631 else {
1632 // odd number of scores
1633 $temp = $stats[$category]['median'][floor(count($stats[$category]['median'])/2)];
1635 unset($stats[$category]['median']);
1636 $stats[$category]['median'] = $temp;
1638 if (isset($stats[$category]['median_weighted'])) {
1639 if (count($stats[$category]['median_weighted'])/2 == floor(count($stats[$category]['median_weighted'])/2)) {
1640 // even number of scores
1641 $temp = $stats[$category]['median_weighted'][count($stats[$category]['median_weighted'])/2-1] + $stats[$category]['median_weighted'][count($stats[$category]['median_weighted'])/2+1];
1642 $temp = $temp/2;
1644 else {
1645 // odd number of scores
1646 $temp = $stats[$category]['median_weighted'][floor(count($stats[$category]['median_weighted'])/2)];
1648 unset($stats[$category]['median_weighted']);
1649 $stats[$category]['median_weighted'] = $temp;
1652 return $stats;
1655 // returns a comma seperated list of the most common values in $items, $items is expected to be a comma sperated list of numbers
1656 function grade_mode($items) {
1657 $all_scores = explode(',',$items);
1658 foreach($all_scores as $value) {
1659 if (isset($frequency[$value])) {
1660 $frequency[$value]++;
1662 else {
1663 $frequency[$value] = 1;
1666 $max = max($frequency);
1667 foreach($frequency as $key=>$value) {
1668 if ($value == $max) {
1669 if (isset($retval)) {
1670 $retval .= ', '.$key;
1672 else {
1673 $retval = $key;
1677 return $retval;
1681 function grade_stats() {
1682 global $CFG;
1683 global $course;
1684 global $USER;
1685 global $preferences;
1687 if (!isset($category)) {
1688 $category = clean_param($_REQUEST['category'], PARAM_CLEAN);
1691 $stats = grade_get_stats($category);
1693 // output our data
1694 print_header();
1695 echo '<table align="center"><tr><th colspan="3" scope="col">'.$category.' '.get_string('stats','grades').'</th></tr>';
1696 if ($preferences->show_weighted == 1 && $preferences->use_weighted_for_letter == 1 && $category== 'all') {
1697 echo '<tr><th scope="col">&nbsp;</th><th scope="col">'.get_string('points','grades').'<th scope="col">'.get_string('weight','grades').'</th></tr>';
1700 echo '<tr><td align="right">'.get_string('max','grades').':</td><td align="right">'.$stats[$category]['max'].'</td>';
1701 if ($preferences->show_weighted == 1 && $preferences->use_weighted_for_letter == 1 && $category== 'all') {
1702 echo '<td align="right">'.$stats[$category]['max_weighted'].'</td>';
1704 echo '</tr>';
1706 echo '<tr><td align="right">'.get_string('min','grades').':</td><td align="right">'.$stats[$category]['min'].'</td>';
1707 if ($preferences->show_weighted == 1 && $preferences->use_weighted_for_letter == 1 && $category== 'all') {
1708 echo '<td align="right">'.$stats[$category]['min_weighted'].'</td>';
1710 echo '</tr>';
1712 echo '<tr><td align="right">'.get_string('average','grades').':</td><td align="right">'.$stats[$category]['average'].'</td>';
1713 if ($preferences->show_weighted == 1 && $preferences->use_weighted_for_letter == 1 && $category== 'all') {
1714 echo '<td align="right">'.$stats[$category]['average_weighted'].'</td>';
1716 echo '</tr>';
1718 echo '<tr><td align="right">'.get_string('median','grades').':</td><td align="right">'.$stats[$category]['median'].'</td>';
1719 if ($preferences->show_weighted == 1 && $preferences->use_weighted_for_letter == 1 && $category== 'all') {
1720 echo '<td align="right">'.$stats[$category]['median_weighted'].'</td>';
1722 echo '</tr>';
1724 echo '<tr><td align="right">'.get_string('mode','grades').':</td><td align="right">'.$stats[$category]['mode'].'</td>';
1725 if ($preferences->show_weighted == 1 && $preferences->use_weighted_for_letter == 1 && $category== 'all') {
1726 echo '<td align="right">'.$stats[$category]['mode_weighted'].'</td>';
1728 echo '</tr>';
1730 echo '<tr><td align="right">'.get_string('standarddeviation','grades').':</td><td align="right">'.$stats[$category]['stddev'].'</td>';
1731 if ($preferences->show_weighted == 1 && $preferences->use_weighted_for_letter == 1 && $category== 'all') {
1732 echo '<td align="right">'.$stats[$category]['stddev_weighted'].'</td>';
1734 echo '</tr>';
1735 echo '</table>';
1736 print_footer();
1739 function grade_view_category_grades($view_by_student) {
1740 global $CFG;
1741 global $course;
1742 global $USER;
1743 global $preferences;
1744 global $group;
1746 $context = get_context_instance(CONTEXT_COURSE, $course->id);
1748 // if can't see course grades, print single grade view
1749 if (!has_capability('moodle/course:viewcoursegrades', $context)) {
1750 return print_student_grade($USER, $course);
1753 if ($preferences->use_advanced == 0) {
1754 $cview = UNCATEGORISED;
1756 else {
1757 $cview=clean_param($_REQUEST['cview'], PARAM_CLEAN);
1760 if ($cview) {
1761 list($grades_by_student, $all_categories) = grade_get_formatted_grades();
1763 if ($grades_by_student != 0 && $all_categories != 0) {
1764 // output a form for the user to download the grades.
1765 grade_download_form();
1767 if ($view_by_student != -1) {
1768 // unset all grades except for this student
1769 foreach ($grades_by_student as $student=>$junk) {
1770 if($student != $view_by_student) {
1771 unset($grades_by_student[$student]);
1776 $grade_columns = $preferences->show_weighted + $preferences->show_points + $preferences->show_percent;
1778 $first = 0;
1779 //$maxpoints = 0;
1780 $maxpercent = 0;
1781 $reprint = 0;
1782 if (has_capability('moodle/course:viewcoursegrades', $context)) {
1783 $student_heading_link = get_string('student','grades');
1784 //only set sorting links if more than one student displayed.
1785 if ($view_by_student == -1) {
1786 $student_heading_link .='<br /><a href="?id='.$course->id.'&amp;group='.$group.'&amp;action=vcats&amp;cview='.$cview.'&amp;sort=lastname">'.get_string('sortbylastname','grades').'</a>';
1787 $student_heading_link .= '<br /><a href="?id='.$course->id.'&amp;group='.$group.'&amp;action=vcats&amp;cview='.$cview.'&amp;sort=firstname">'.get_string('sortbyfirstname','grades').'</a>';
1789 else {
1790 $student_heading_link .= '<br /><a href="?id='.$course->id.'&amp;group='.$group.'&amp;action=vcats&amp;cview='.$cview.'">'.get_string('showallstudents','grades').'</a>';
1793 echo '<table align="center" class="grades">';
1794 if (has_capability('moodle/course:viewcoursegrades', $context)) {
1795 $header = '<tr class="header"><th rowspan="2" scope="col">'.$student_heading_link.'</th>';
1797 else {
1798 $header = '<tr class="header">';
1800 $header1 = '<tr class="header">';
1802 // to keep track of what we've output
1803 $colcount = 0;
1804 $oddrow = true;
1805 $reprint = 0;
1807 // this next section is to display the items in the course order
1808 foreach($grades_by_student as $student => $categories) {
1809 if (isset($item_order)) {
1810 // we already have the sort order let's jump out
1811 break;
1813 $item_order = array();
1814 foreach($categories as $category => $items) {
1815 if ($category == $cview) {
1816 foreach ($items as $assignment=>$points) {
1817 if ($assignment != 'stats') {
1818 $temp = $points['sort_order'];
1819 $item_order[$temp] = $assignment;
1825 /// Make sure $item_order is initialised (bug 3424)
1826 if (empty($item_order)) $item_order = array();
1828 ksort($item_order);
1830 foreach($grades_by_student as $student => $categories) {
1832 if ($preferences->reprint_headers != 0 && $reprint >= $preferences->reprint_headers) {
1833 echo $header.$header1.'</tr>';
1834 $reprint=0;
1837 // alternate row classes
1838 $row = ($oddrow) ? '<tr class="r0">' : '<tr class="r1">';
1839 $oddrow = !$oddrow;
1841 // reset the col classes
1842 $oddcol = true;
1845 // set the links to student information based on multiview or individual... if individual go to student info... if many go to individual grades view.
1846 if (has_capability('moodle/course:viewcoursegrades', $context)) {
1847 if ($view_by_student != -1) {
1848 $student_link = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$student.'&amp;course='.$course->id.'">';
1850 else {
1851 $student_link = '<a href="?id='.$course->id.'&amp;group='.$group.'&amp;action=vcats&amp;user='.$student.'&amp;cview='.$cview.'">';
1853 $student_link .= $grades_by_student[$student]['student_data']['lastname'].', '.$grades_by_student[$student]['student_data']['firstname'].'</a>';
1854 $row .= '<th class="fullname" scope="row">'.$student_link.'</th>';
1857 foreach($categories as $category => $items) {
1858 if ($category == $cview) {
1859 // make sure that the grades come out in the same order
1860 foreach($item_order as $order=>$assignment) {
1862 $class = $all_categories[$category][$assignment]['modname'];
1864 if ($assignment != 'stats') {
1866 if ($first == 0) {
1867 $colcount++;
1868 $link_id = grade_get_module_link($course->id, $all_categories[$category][$assignment]['cminstance'], $all_categories[$category][$assignment]['modid']);
1870 $link = $CFG->wwwroot.'/mod/'.$all_categories[$category][$assignment]['modname'].'/view.php?id='.$link_id->id;
1871 $all_categories[$category][$assignment]['link'] = $link;
1872 if ($all_categories[$category][$assignment]['hidden'] == 0) {
1873 $header .= '<th class="'.$class.'" colspan="'.$grade_columns.'" scope="col"><a href="'.$link.'">'.format_string($assignment,true).'</a>';
1875 else {
1876 $header .= '<th class="'.$class.'" colspan="'.$grade_columns.'" scope="col"><a class="dimmed" href="'.$link.'">'.format_string($assignment,true).'</a>';
1878 if ($all_categories[$category][$assignment]['extra_credit'] == 1) {
1879 $header .= '<span class="extracredit">('.get_string('extracredit','grades').')</span>';
1881 $header .='</th>';
1882 if ($preferences->show_points) {
1883 $header1 .= '<th class="'.$class.'" scope="col">'. $all_categories[$category][$assignment]['maxgrade'];
1884 if ($all_categories[$category][$assignment]['grade_against'] != $all_categories[$category][$assignment]['maxgrade']) {
1885 $header1 .= '('. $all_categories[$category][$assignment]['grade_against'].')';
1887 $header1 .= '</th>';
1890 if($preferences->show_percent) {
1891 if ($all_categories[$category][$assignment]['grade_against'] != $all_categories[$category][$assignment]['maxgrade']) {
1892 $header1 .= '<th class="'.$class.'" scope="col">'.get_string('scaledpct','grades').'</th>';
1894 else {
1895 $header1 .= '<th class="'.$class.'" scope="col">'.get_string('rawpct','grades').'</th>';
1898 if ($preferences->show_weighted) {
1899 if ($all_categories[$category]['stats']['totalpoints'] != 0) {
1900 $cur_weighted_max = sprintf("%0.2f", $all_categories[$category][$assignment]['grade_against']/$all_categories[$category]['stats']['totalpoints']*$all_categories[$category]['stats']['weight']);
1902 else {
1903 $cur_weighted_max = 0;
1905 $header1 .= '<th scope="col">'.$cur_weighted_max.get_string('pctoftotalgrade','grades').'</th>';
1909 // display points
1910 if ($preferences->show_points) {
1911 $class .= ($oddcol) ? ' c0 points' : ' c1 points';
1912 $oddcol = !$oddcol;
1913 $row .= '<td class="'.$class.'"><a href="'.$all_categories[$category][$assignment]['link'].'">' . $items[$assignment]['grade'] . '</a></td>';
1916 if ($preferences->show_percent) {
1917 $class .= ($oddcol) ? ' c0 percent' : ' c1 percent';
1918 $oddcol = !$oddcol;
1919 $row .= '<td class="'.$class.'">'. $items[$assignment]['percent'].'%</td>';
1922 if ($preferences->show_weighted) {
1923 $class .= ($oddcol) ? ' c0 weighted' : ' c1 weighted';
1924 $oddcol = !$oddcol;
1925 $row .= '<td class="'.$class.'">'.$items[$assignment]['weighted'].'%</td>';
1929 } else {
1930 $class = '';
1934 if ($first == 0) {
1935 if (has_capability('moodle/course:viewcoursegrades', $context) && $view_by_student == -1) {
1936 $total_sort_link = '<a href="?id='.$course->id.'&amp;group='.$group.'&amp;action=vcats&amp;cview='.$cview.'&amp;sort=highgrade_category"><img src="'.$CFG->wwwroot.'/pix/t/down.gif" alt="'.get_string('highgradedescending','grades').'" /></a>';
1937 $total_sort_link .= '<a href="?id='.$course->id.'&amp;group='.$group.'&amp;action=vcats&amp;cview='.$cview.'&amp;sort=highgrade_category_asc"><img src="'.$CFG->wwwroot.'/pix/t/up.gif" alt="'.get_string('highgradeascending','grades').'" /></a>';
1939 else {
1940 $total_sort_link = '';
1943 $stats_link = '<a href="javascript:void(0)" onclick="window.open(\'?id='.$course->id.'&amp;action=stats&amp;group='.$group.'&amp;category='.$cview.'\',\''.get_string('statslink','grades').'\',\'height=200,width=300,scrollbars=no\')">'.get_string('statslink','grades').'</a>';
1944 if ($all_categories[$cview]['stats']['drop'] != 0) {
1945 $header .= '<th class="'.$class.'" colspan="'.$grade_columns.'" scope="col">'.get_string('total','grades').'&nbsp; (Lowest '. $all_categories[$cview]['stats']['drop']. ' Dropped)'.$total_sort_link.' '.$stats_link.'</th>';
1947 else {
1948 $header .= '<th class="'.$class.'" colspan="'.$grade_columns.'" scope="col">'.get_string('total','grades').'&nbsp;'.$total_sort_link.' '.$stats_link.'</th>';
1951 if ($preferences->show_points) {
1952 $header1 .= '<th class="'.$class.'" scope="col">'.$all_categories[$cview]['stats']['totalpoints'];
1953 if ($all_categories[$cview]['stats']['bonus_points'] != 0) {
1954 $header1 .='(+'.$all_categories[$cview]['stats']['bonus_points'].')';
1956 $header1 .='</th>';
1958 if ($preferences->show_percent) {
1959 $header1 .= '<th class="'.$class.'" scope="col">'.get_string('percent','grades').'</th>';
1963 if ($preferences->show_weighted) {
1964 $header1 .= '<th class="'.$class.'" scope="col">'.$all_categories[$cview]['stats']['weight'].get_string('pctoftotalgrade','grades').'</th>';
1967 if (has_capability('moodle/course:viewcoursegrades', $context)) {
1968 $header .= '<th rowspan="2" scope="col">'.$student_heading_link.'</th></tr>';
1970 else {
1971 $header .= '</tr>';
1974 //adjust colcount to reflect the actual number of columns output
1975 $colcount++; // total column
1976 $colcount = $colcount*$grade_columns + 2;
1977 echo '<tr class="title"><th colspan="'.$colcount.'" scope="col">';
1978 if ($preferences->use_advanced != 0) {
1979 echo $cview.' '.get_string('grades','grades');
1981 else {
1982 echo get_string('grades','grades');
1985 if (has_capability('moodle/course:viewcoursegrades', $context)) {
1986 helpbutton('teacher', get_string('gradehelp','grades'), 'grade');
1988 else {
1989 helpbutton('student', get_string('gradehelp','grades'), 'grade');
1991 echo '</th></tr>';
1992 echo $header;
1993 echo $header1.'</tr>';
1994 $first = 1;
1997 // total points for category
1998 if ($preferences->show_points) {
1999 $class .= ($oddcol) ? ' c0 points' : ' c1 points';
2000 $oddcol = !$oddcol;
2001 $row .= '<td class="'.$class.'">'.$grades_by_student[$student][$cview]['stats']['points'].'</td>';
2004 // total percent for category
2005 if ($preferences->show_percent) {
2006 $class .= ($oddcol) ? ' c0 percent' : ' c1 percent';
2007 $oddcol = !$oddcol;
2008 $row .= '<td class="'.$class.'">'.$grades_by_student[$student][$cview]['stats']['percent'].'%</td>';
2012 // total weighted for category
2013 if ($preferences->show_weighted) {
2014 $class .= ($oddcol) ? ' c0 weighted' : ' c1 weighted';
2015 $oddcol = !$oddcol;
2016 $row .= '<td class="'.$class.'">'.$grades_by_student[$student][$cview]['stats']['weighted'].'%</td>';
2019 if (has_capability('moodle/course:viewcoursegrades', $context)) {
2020 $row .= '<td class="fullname">'.$student_link.'</td>';
2022 $row .= '</tr>';
2023 echo $row;
2024 $reprint++;
2026 echo '</table>';
2028 else { // no grades returned
2029 error(get_string('nogradesreturned','grades'), $CFG->wwwroot.'/course/view.php?id='.$course->id);
2032 else {
2033 error(get_string('nocategoryview','grades'), $CFG->wwwroot.'/course/view.php?id='.$course->id);
2037 function grade_view_all_grades($view_by_student) { // if mode=='grade' then we are in user view
2038 // displays all grades for the course
2039 global $CFG;
2040 global $course;
2041 global $USER;
2042 global $group; // yu: fix for 5814
2043 global $preferences;
2045 if (!$context = get_context_instance(CONTEXT_COURSE, $course->id)) {
2046 return false;
2049 // if can't see course grades, print single grade view
2050 if (!has_capability('moodle/course:viewcoursegrades', $context)) {
2051 return print_student_grade($USER, $course);
2054 list($grades_by_student, $all_categories) = grade_get_formatted_grades();
2056 if ($grades_by_student != 0 && $all_categories != 0) {
2058 // output a form for the user to download the grades.
2059 grade_download_form();
2061 if ($view_by_student != -1) {
2062 // unset all grades except for this student
2063 foreach ($grades_by_student as $student=>$junk) {
2064 if($student != $view_by_student) {
2065 unset($grades_by_student[$student]);
2070 $grade_columns = $preferences->show_weighted + $preferences->show_points + $preferences->show_percent;
2072 $first = 0;
2073 $total_course_points = 0;
2074 $maxpercent = 0;
2075 $reprint=0;
2077 echo '<table align="center" class="grades">';
2078 if (has_capability('moodle/course:viewcoursegrades', $context)) {
2079 $student_heading_link = get_string('student','grades');
2080 if ($view_by_student == -1) {
2081 $student_heading_link .='<a href="?id='.$course->id.'&amp;action=grades&amp;sort=lastname&amp;group='.$group.'"><br /><font size="-2">'.get_string('sortbylastname','grades').'</font></a>';
2082 $student_heading_link .= '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=firstname&amp;group='.$group.'"><br /><font size="-2">'.get_string('sortbyfirstname','grades').'</font></a>';
2084 else {
2085 $student_heading_link .= '<br /><a href="?id='.$course->id.'&amp;&amp;action=grades"><font size="-2">'.get_string('showallstudents','grades').'</font></a>';
2087 $header = '<tr><th rowspan="2" scope="col">'.$student_heading_link.'</th>';
2089 else {
2090 $header = '</tr>';
2092 $header1 = '<tr>';
2094 $rowcount = 0;
2095 $oddrow = true;
2096 $colcount = 0;
2098 foreach($grades_by_student as $student => $categories) {
2100 $totalpoints = 0;
2101 $totalgrade = 0;
2102 $total_bonus_points = 0;
2103 if ($preferences->reprint_headers != 0 && $reprint >= $preferences->reprint_headers) {
2104 echo $header.$header1;
2105 $reprint=0;
2108 // alternate row classes
2109 $row = ($oddrow) ? '<tr class="r0">' : '<tr class="r1">';
2110 $oddrow = !$oddrow;
2112 // set the links to student information based on multiview or individual... if individual go to student info... if many go to individual grades view.
2113 if (has_capability('moodle/course:viewcoursegrades', $context)) {
2114 if ($view_by_student != -1) {
2115 $studentviewlink = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$student.'&amp;course='.$course->id.'">'.$grades_by_student[$student]['student_data']['lastname'].', '.$grades_by_student[$student]['student_data']['firstname'].'</a>';
2117 else {
2118 $studentviewlink = '<a href="?id='.$course->id.'&amp;action=view_student_grades&amp;user='.$student.'">'.$grades_by_student[$student]['student_data']['lastname'].', '.$grades_by_student[$student]['student_data']['firstname'].'</a>';
2120 $row .= '<th scope="row">'. $studentviewlink .'</th>';
2122 ksort($categories);
2124 foreach($categories as $category => $items) {
2125 if ($category != 'student_data') {
2127 if ($first == 0) {
2128 $colcount++;
2129 if ($category == UNCATEGORISED) {
2130 $categoryname = get_string(UNCATEGORISED, 'grades');
2131 } else {
2132 $categoryname = $category;
2134 // only print the category headers if something is displayed for them
2135 if ($preferences->show_weighted || $preferences->show_percent || $preferences->show_points) {
2136 $stats_link = '<a href="javascript:void(0)" onclick="window.open(\'?id='.$course->id.'&amp;action=stats&amp;category='.$category.'\',\''.get_string('statslink','grades').'\',\'height=200,width=300,scrollbars=no\')"><font size="-2">'.get_string('statslink','grades').'</font></a>';
2137 $header .= '<th colspan="'.$grade_columns.'" scope="col"><a href="?id='.$course->id.'&amp;action=vcats&amp;cview='.$category;
2138 if ($view_by_student != -1) {
2139 $header .= '&amp;user='.$view_by_student;
2141 $header .='">'. $categoryname .' '.$stats_link.'</a>';
2143 if ($preferences->display_weighted != 0) {
2144 $header .= '('. $all_categories[$category]['stats']['weight'] . '%)';
2146 $header .= '</th>';
2147 if ($preferences->show_points) {
2148 $header1 .= '<th scope="col">'.get_string('points','grades').'('.$all_categories[$category]['stats']['totalpoints'].')';
2149 if ($all_categories[$category]['stats']['bonus_points'] != 0) {
2150 $header1 .='(+'.$all_categories[$category]['stats']['bonus_points'].')';
2152 $header1 .='</th>';
2154 if ($preferences->show_percent) {
2155 $header1 .= '<th scope="col">'.get_string('percent','grades').'</th>';
2157 if ($preferences->show_weighted) {
2158 $header1 .= '<th scope="col">'.get_string('weightedpctcontribution','grades').'</th>';
2160 $maxpercent = $all_categories["$category"]['stats']['weight'] + $maxpercent;
2161 //$total_course_points = $all_categories[$category]['stats']['totalpoints']+ $total_course_points;
2162 //$total_course_points = $all_categories[$category]['stats']['totalpoints']+ $total_course_points;
2165 if ($preferences->show_points) {
2166 $row .= '<td align="right">' . $items['stats']['points'] . '</td>';
2168 if ($preferences->show_percent) {
2169 $row .= '<td align="right">'. $items['stats']['percent'].'%</td>';
2172 if ($preferences->show_weighted) {
2173 $row .= '<td align="right">'. $items['stats']['weighted'] . '%</td>';
2175 $total_bonus_points = $all_categories[$category]['stats']['bonus_points'];
2178 if ($first == 0) {
2179 if ($preferences->show_letters) {
2180 $total_columns = $grade_columns + 1;
2182 else {
2183 $total_columns = $grade_columns;
2186 if (has_capability('moodle/course:viewcoursegrades', $context) && $view_by_student == -1) {
2187 $grade_sort_link = '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=highgrade&amp;group='.$group.'"><img src="'.$CFG->wwwroot.'/pix/t/down.gif" alt="'.get_string('highgradedescending','grades').'" /></a>';
2188 $grade_sort_link .= '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=highgrade_asc&amp;group='.$group.'"><img src="'.$CFG->wwwroot.'/pix/t/up.gif" alt="'.get_string('highgradeascending','grades').'" /></a>';
2189 $points_sort_link = '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=points&amp;group='.$group.'"><img src="'.$CFG->wwwroot.'/pix/t/down.gif" alt="'.get_string('pointsdescending','grades').'" /></a>';
2190 $points_sort_link .= '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=points_asc&amp;group='.$group.'"><img src="'.$CFG->wwwroot.'/pix/t/up.gif" alt="'.get_string('pointsascending','grades').'" /></a>';
2191 $weighted_sort_link = '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=weighted&amp;group='.$group.'"><img src="'.$CFG->wwwroot.'/pix/t/down.gif" alt="'.get_string('weighteddescending','grades').'" /></a>';
2192 $weighted_sort_link .= '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=weighted_asc&amp;group='.$group.'"><img src="'.$CFG->wwwroot.'/pix/t/up.gif" alt="'.get_string('weightedascending','grades').'" /></a>';
2193 $percent_sort_link = '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=percent&amp;group='.$group.'"><img src="'.$CFG->wwwroot.'/pix/t/down.gif" alt="'.get_string('percentdescending','grades').'" /></a>';
2194 $percent_sort_link .= '<a href="?id='.$course->id.'&amp;action=grades&amp;sort=percent_asc&amp;group='.$group.'"><img src="'.$CFG->wwwroot.'/pix/t/up.gif" alt="'.get_string('percentascending','grades').'" /></a>';
2196 $stats_link = '<a href="javascript:void(0)" onclick="window.open(\'?id='.$course->id.'&amp;action=stats&amp;category=all\',\''.get_string('statslink','grades').'\',\'height=200,width=300,scrollbars=no\')"><font size="-2">'.get_string('statslink','grades').'</font></a>';
2197 $header .= '<th colspan="'.$total_columns.'" scope="col">'.get_string('total','grades').'&nbsp;'.$stats_link.'</th>';
2198 if (has_capability('moodle/course:viewcoursegrades', $context) && $view_by_student == -1) {
2199 if ($preferences->show_points) {
2200 $header1 .= '<th scope="col">'.get_string('points','grades').'('.$all_categories['stats']['totalpoints'].')';
2201 if ($category != 'student_data' && $all_categories[$category]['stats']['bonus_points'] != 0) {
2203 $header1 .='(+'.$total_bonus_points.')';
2205 $header1 .= '<br />'.$points_sort_link.' '.'</th>';
2207 if ($preferences->show_percent) {
2208 $header1 .= '<th scope="col">'.get_string('percentshort','grades').'<br />'.$percent_sort_link.' '.'</th>';
2210 if ($preferences->show_weighted) {
2211 $header1 .= '<th scope="col">'.get_string('weightedpct','grades').'('.$all_categories['stats']['weight'].')'.'<br />'.$weighted_sort_link.' '.'</th>';
2213 if ($preferences->show_letters) {
2214 $header1 .= '<th scope="col">'.get_string('lettergrade','grades').'<br />'.$grade_sort_link.' '.'</th>';
2216 $header1 .= '</tr>';
2218 else {
2219 if ($preferences->show_points) {
2220 $header1 .= '<th scope="col">'.get_string('points','grades').'('.$all_categories['stats']['totalpoints'].')';
2221 if ($category != 'student_data' && $all_categories[$category]['stats']['bonus_points'] != 0) {
2222 $header1 .='(+'.$total_bonus_points.')';
2224 $header1 .= '</th>';
2226 if ($preferences->show_percent) {
2227 $header1 .= '<th scope="col">'.get_string('percentshort','grades').'</th>';
2229 if ($preferences->show_weighted) {
2230 $header1 .= '<th scope="col">'.get_string('weightedpct','grades').'('.$all_categories['stats']['weight'].')</th>';
2232 if ($preferences->show_letters) {
2233 $header1 .= '<th scope="col">'.get_string('lettergrade','grades').'</th>';
2235 $header1 .= '</tr>';
2237 if (has_capability('moodle/course:viewcoursegrades', $context)) {
2238 $header .= '<th rowspan="2" scope="col">'.$student_heading_link.'</th></tr>';
2240 // adjust colcount to reflect actual number of columns output
2241 $colcount = $colcount * $grade_columns + $total_columns + 2;
2243 echo '<tr><th colspan="'.$colcount.'" scope="col"><font size="+1">'.get_string('allgrades','grades').'</font>';
2244 if (has_capability('moodle/course:viewcoursegrades', $context)) {
2245 helpbutton('teacher', get_string('gradehelp','grades'), 'grade');
2247 else {
2248 helpbutton('student', get_string('gradehelp','grades'), 'grade');
2250 echo '</th></tr>';
2253 echo $header;
2254 echo $header1;
2255 $first = 1;
2257 if ($preferences->show_points) {
2258 $row .= '<td align="right">'.$grades_by_student[$student]['student_data']['points'].'</td>';
2260 if ($preferences->show_percent) {
2261 $row .= '<td align="right">'.$grades_by_student[$student]['student_data']['percent'].'%</td>';
2263 if ($preferences->show_weighted) {
2264 $row .= '<td align=right>'.$grades_by_student[$student]['student_data']['weighted'].'%</td>';
2266 if ($preferences->show_letters) {
2267 if ($preferences->use_weighted_for_letter == 1) {
2268 $grade = $grades_by_student[$student]['student_data']['weighted'];
2270 else {
2271 $grade = $grades_by_student[$student]['student_data']['percent'];
2273 $letter_grade = grade_get_grade_letter($course->id, $grade);
2274 if ($letter_grade) {
2275 $row .= '<td align="right">'.$letter_grade->letter.'</td>';
2277 else {
2278 // there wasn't an appropriate entry to use in the gradebook.
2279 if (grade_letters_set($course->id)) {
2280 $row .= '<td align="right">'.get_string('nolettergrade','grades').' '.$grade.'</td>';
2282 else {
2283 $row .= '<td align="right">'.get_string('nogradeletters','grades').'</td>';
2287 if (has_capability('moodle/course:viewcoursegrades', $context)) {
2288 $row .= '<td>'. $studentviewlink .'</td></tr>';
2290 else {
2291 $row .= '</tr>';
2294 echo $row;
2295 $reprint++;
2297 echo '</table>';
2299 else { // no grades returned
2300 error(get_string('nogradesreturned','grades'));
2305 function grade_set_grade_weights() {
2306 // set the grade weights as submitted from the form generated by display_grade_weights
2307 global $CFG;
2308 global $course;
2309 global $USER;
2311 if (!empty($USER->id)) {
2312 if (!confirm_sesskey()) {
2313 error(get_string('confirmsesskeybad', 'error'));
2317 // get list of all categories
2318 $categories = get_records('grade_category', 'courseid', $course->id);
2319 if ($categories) {
2320 foreach ($categories as $category) {
2321 $form_catname = preg_replace('/[.| ]/', '_', $category->name);
2323 $submitted_category = optional_param($form_catname);
2324 if (is_numeric($submitted_category)) {
2325 // see if there is a weight if so see if it needs to be updated
2326 $weight = grade_get_category_weight($course->id, $category->name);
2327 if ($weight) {
2328 if ($weight->weight != $submitted_category)
2330 set_field('grade_category', 'weight', $submitted_category, 'id', $weight->id);
2333 $cur_drop = optional_param("drop_x_lowest$form_catname");
2334 $cur_bonus_points = optional_param("bonus_points$form_catname");
2335 $cur_hidden = optional_param("hidden$form_catname");
2336 if ($cur_hidden) {
2337 $cur_hidden = true;
2339 else {
2340 $cur_hidden = false;
2343 if ($weight->drop_x_lowest != $cur_drop) {
2344 set_field('grade_category', 'drop_x_lowest', $cur_drop, 'id', $weight->cat_id);
2346 if ($weight->bonus_points != $cur_bonus_points) {
2347 set_field('grade_category', 'bonus_points', $cur_bonus_points, 'id', $weight->cat_id);
2349 if ($cur_hidden) {
2350 set_field('grade_category', 'hidden', 1, 'id', $weight->cat_id);
2352 else {
2353 set_field('grade_category', 'hidden', 0, 'id', $weight->cat_id);
2356 else {
2357 // insert the new record... we shouldn't reach this point anymore
2358 //$new_weight->course = $course->id;
2359 //$new_weight->category = $category->id;
2360 //$new_weight->weight = $submitted_category;
2361 //insert_record('grade_weight', $new_weight);
2364 else {
2365 echo '<center><font color="red">'.get_string('nonumericweight','grades').
2366 format_string($category->name) .': "'.$submitted_category.'"</font></center><br />';
2372 function grade_display_grade_weights() {
2373 // get all categories with weights
2374 // then set and display that entry.
2375 global $CFG;
2376 global $course;
2377 global $USER;
2379 $categories = get_records('grade_category', 'courseid', $course->id);
2380 if ($categories) {
2381 echo '<form id="grade_weights" action="./index.php" method="post">';
2382 echo '<table border="0" cellspacing="2" cellpadding="5" align="center" class="generalbox">';
2383 echo '<tr><th colspan="5" class="header" scope="col">'.get_string('setweights','grades');
2384 helpbutton('weight', get_string('gradeweighthelp','grades'), 'grade');
2385 echo '</th></tr>';
2386 echo '<tr><td align="center" class="generaltableheader">'.get_string('category','grades').'</td>';
2387 echo '<td align="center" class="generaltableheader">'.get_string('weight','grades').'</td>';
2388 echo '<td align="center" class="generaltableheader">'.get_string('dropxlowest','grades').'</td>';
2389 echo '<td align="center" class="generaltableheader">'.get_string('bonuspoints','grades').'</td>';
2390 echo '<td align="center" class="generaltableheader">'.get_string('hidecategory','grades').'</td>';
2391 echo '</tr>';
2392 echo '<input type="hidden" name="id" value="'.$course->id.'" />';
2393 echo '<input type="hidden" name="action" value="set_grade_weights" />';
2394 echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
2396 $sum = 0;
2398 foreach($categories as $category) {
2399 $val = $category->weight;
2400 $sum = $sum + $val;
2402 // make names form safe
2403 $form_catname = str_replace(' ', '_', $category->name);
2404 if ($category->name == UNCATEGORISED) {
2405 $category->name = get_string(UNCATEGORISED, 'grades');
2407 echo '<tr><td align="center" class="generalboxcontent">'. format_string($category->name) .'</td>';
2408 echo '<td align="center" class="generalboxcontent"><input type="text" size="5" name="'.$form_catname.'" value="'.$val.'" /></td>';
2409 echo '<td align="center" class="generalboxcontent"><input type="text" size="5" name="drop_x_lowest'.$form_catname.'" value="'.$category->drop_x_lowest.'" /></td>';
2410 echo '<td align="center" class="generalboxcontent"><input type="text" size="5" name="bonus_points'.$form_catname.'" value="'.$category->bonus_points.'" /></td>';
2411 echo '<td align="center" class="generalboxcontent"><input type="checkbox" name="hidden'.$form_catname.'" ';
2412 if ($category->hidden == 1) {
2413 echo ' checked="checked"';
2415 echo ' /></td></tr>';
2417 echo '<tr><td colspan="5" align="center" class="generalboxcontent">';
2418 echo '<input type="submit" value="'.get_string('savechanges','grades').'" />';
2419 echo '</td></tr>';
2420 if ($sum != 100) {
2421 echo '<tr><td colspan="5" align="center" class="generalboxcontent"><font color="red">'.get_string('totalweightnot100','grades').'</font></td></tr>';
2423 else {
2424 echo '<tr><td colspan="5" align="center" class="generalboxcontent"><font color="green">'.get_string('totalweight100','grades').'</font></td></tr>';
2427 else {
2428 /// maybe this should just do the default population of the categories instead?
2429 echo '<font color="red">'.get_string('setcategorieserror','grades').'</font>';
2431 echo '</table>';
2432 echo '</form>';
2433 echo '<center>'.get_string('dropxlowestwarning','grades').'</center><br />';
2436 function grade_set_categories() {
2437 global $CFG;
2438 global $course;
2439 global $USER;
2442 /// Collect modules data
2443 get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
2445 echo '<table border="0" cellspacing="2" cellpadding="5" align="center" class="generalbox">';
2446 echo '<tr><th colspan="5" class="header" scope="col">'.get_string('setcategories','grades');
2447 helpbutton('category', get_string('gradecategoryhelp','grades'), 'grade');
2448 echo '</th></tr>';
2449 echo '<tr><td align="center" class="generaltableheader">'.get_string('gradeitem','grades').'</td>';
2450 echo '<td align="center" class="generaltableheader">'.get_string('category','grades').'</td>';
2451 echo '<td align="center" class="generaltableheader">'.get_string('maxgrade','grades').'</td>';
2452 echo '<td align="center" class="generaltableheader">'.get_string('curveto','grades').'</td>';
2453 echo '<td align="center" class="generaltableheader">'.get_string('extracredit','grades').'</td></tr>';
2454 echo '<form id="set_categories" method="post" action="./index.php" >';
2455 echo '<input type="hidden" name="action" value="assign_categories" />';
2456 echo '<input type="hidden" name="id" value="'.$course->id.'" />';
2457 echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
2459 $itemcount = 0;
2461 /// Search through all the modules, pulling out grade data
2462 $sections = get_all_sections($course->id); // Sort everything the same as the course
2463 for ($i=0; $i<=$course->numsections; $i++) {
2464 if (isset($sections[$i])) { // should always be true
2465 $section = $sections[$i];
2466 if ($section->sequence) {
2467 $sectionmods = explode(",", $section->sequence);
2468 foreach ($sectionmods as $sectionmod) {
2469 if (empty($mods[$sectionmod])) {
2470 continue;
2472 $mod = $mods[$sectionmod];
2473 $instance = get_record("$mod->modname", "id", "$mod->instance");
2474 $libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
2475 if (file_exists($libfile)) {
2476 require_once($libfile);
2477 $gradefunction = $mod->modname."_grades";
2478 if (function_exists($gradefunction)) { // Skip modules without grade function
2479 if ($modgrades = $gradefunction($mod->instance)) {
2481 if ($modgrades->maxgrade != '')
2482 // this block traps out broken modules that don't return a maxgrade according to the moodle API
2484 $itemcount++;
2485 //modgrades contains student information with associated grade
2486 //echo "<b>modname: $mod->modname id: $mod->id course: $mod->course</b><br />";
2487 echo '<input type="hidden" name="modname'.$itemcount.'" value="'.$mod->modname.'" />';
2488 echo '<input type="hidden" name="mod'.$itemcount.'" value="'.$mod->instance.'" />';
2489 echo '<input type="hidden" name="course'.$itemcount.'" value="'.$mod->course.'" />';
2490 echo '<tr><td align="center" class="generalboxcontent">';
2491 // get instance name from db.
2492 $instance = get_record($mod->modname, 'id', $mod->instance);
2493 echo format_string($instance->name)."</td>";
2494 // see if the item is already in the category table and if it is call category select with the id so it is selected
2495 echo '<td align="center" class="generalboxcontent"><select name="category'.$itemcount.'">';
2496 $item_cat_id = get_record('grade_item', 'modid', $mod->module, 'courseid', $course->id, 'cminstance', $mod->instance);
2497 //print_object($item_cat_id);
2498 if (isset($item_cat_id)) {
2499 grade_category_select($item_cat_id->category);
2501 else {
2502 grade_category_select(-1);
2504 echo '</select></td><td align="center" class="generalboxcontent">'.$modgrades->maxgrade.'<input type="hidden" name="maxgrade'.$itemcount.'" value="'.$modgrades->maxgrade.'" /></td>';
2506 if (isset($item_cat_id)) {
2507 // the value held in scale_grade is a scaling percent. The next line just formats it so it is easier for the user (they just enter the point value they want to be 100%)
2508 if ($item_cat_id->scale_grade == '' || $item_cat_id->scale_grade == 0)
2509 $scale_to = $modgrades->maxgrade;
2510 else
2511 $scale_to = round($modgrades->maxgrade/$item_cat_id->scale_grade);
2512 echo '<td align="center" class="generalboxcontent"><input type="text" size="5" name="scale_grade'.$itemcount.'" value="'.$scale_to.'" /></td>';
2514 else {
2515 echo '<td align="center" class="generalboxcontent"><input type="text" size="5" name="scale_grade'.$itemcount.'" value="'.$modgrades->maxgrade.'" /></td>';
2518 echo '<td align="center" class="generalboxcontent"><input type="checkbox" name="extra_credit'.$itemcount.'" ';
2519 if ($item_cat_id->extra_credit == 1) {
2520 echo ' checked="checked"';
2522 echo ' /></td></tr>';
2531 echo '<input type="hidden" name="totalitems" value="'.$itemcount.'" />';
2532 echo '<tr><td colspan="5" align="center" class="generalboxcontent"><input type="submit" value="'.get_string('savechanges','grades').'" /></td></tr>';
2533 echo '</form>';
2534 echo '<tr><td colspan="5" align="center" class="generalboxcontent">';
2535 grade_add_category_form();
2536 echo '</td></tr><tr><td colspan="5" align="center" class="generalboxcontent">';
2537 grade_delete_category_form();
2538 echo '</td></tr></table>';
2539 echo '<center>'.get_string('extracreditwarning','grades').'</center>';
2542 function grade_delete_category() {
2543 global $CFG;
2544 global $course;
2545 global $USER;
2547 if (!empty($USER->id)) {
2548 if (!confirm_sesskey()) {
2549 error(get_string('confirmsesskeybad', 'error'));
2553 $cat_id = optional_param('category_id');
2554 if ($cat_id != 'blank') {
2555 // delete the record
2556 delete_records('grade_category', 'id', $cat_id, 'courseid', $course->id);
2557 // set grade_item category field=0 where it was the deleted category (set uncategorized will clean this up)
2558 set_field('grade_item', 'category', 0, 'category', $cat_id);
2562 function grade_assign_categories() {
2563 global $CFG;
2564 global $course;
2565 global $USER;
2566 $num_categories = optional_param('totalitems');
2568 if (!empty($USER->id)) {
2569 if (!confirm_sesskey()) {
2570 error(get_string('confirmsesskeybad', 'error'));
2574 for ($i = 1; $i <= $num_categories; $i++) {
2576 // these next sets of lines are a bit obtuse, but it lets there be a dynamic number of grade items
2577 // in the grade category form (maybe there's a better way?)
2578 $cur_cat_id = '$_REQUEST[\'category'.$i.'\'];';
2579 eval( "\$cur_cat_id = $cur_cat_id;" );
2580 $cur_modname = '$_REQUEST[\'modname'.$i.'\'];';
2581 eval( "\$cur_modname = $cur_modname;" );
2582 $cur_mod = '$_REQUEST[\'mod'.$i.'\'];';
2583 eval( "\$cur_mod = $cur_mod;" );
2584 $cur_maxgrade = '$_REQUEST[\'maxgrade'.$i.'\'];';
2585 eval( "\$cur_maxgrade = $cur_maxgrade;" );
2586 $cur_scale_grade = '$_REQUEST[\'scale_grade'.$i.'\'];';
2587 eval( "\$cur_scale_grade = $cur_scale_grade;" );
2588 $cur_extra_credit = '$_REQUEST[\'extra_credit'.$i.'\'];';
2589 $temp = 'extra_credit'.$i;
2590 $junk = get_record('modules','name',$cur_modname);
2591 $cur_modid = $junk->id;
2592 if (isset($_REQUEST[$temp])) {
2593 eval( "\$cur_extra_credit = $cur_extra_credit;" );
2595 else {
2596 $cur_extra_credit = false;
2598 if ($cur_extra_credit) {
2599 $cur_extra_credit = 1;
2600 } else {
2601 $cur_extra_credit = 0;
2603 if ($cur_scale_grade == 0 || $cur_scale_grade == '') {
2604 $cur_scale_grade = 1.0;
2607 $db_cat = get_record('grade_item', 'modid', $cur_modid, 'cminstance', $cur_mod, 'courseid', $course->id);
2608 if ( $db_cat ) {
2609 if ($db_cat->category != $cur_cat_id) {
2610 // item doesn't match in the db so update it to point to the new category
2611 set_field('grade_item', 'category', $cur_cat_id, 'id', $db_cat->id);
2614 if ($db_cat->scale_grade != $cur_maxgrade/$cur_scale_grade) {
2615 // scale_grade doesn't match
2616 set_field('grade_item', 'scale_grade', ($cur_maxgrade/$cur_scale_grade), 'id', $db_cat->id);
2619 set_field('grade_item', 'extra_credit', $cur_extra_credit, 'id', $db_cat->id);
2621 else {
2622 // add a new record
2623 $item->courseid = $course->id;
2624 $item->category = $cur_cat_id;
2625 $item->modid = $cur_modid;
2626 $item->cminstance = $cur_mod;
2627 $item->scale_grade = $cur_scale_grade;
2628 $item->extra_credit = $cur_extra_credit;
2629 insert_record('grade_item', $item);
2634 function grade_add_category_form() {
2635 /// outputs a form to add a category
2636 /// just a simple text box with submit
2637 global $course;
2638 global $USER;
2639 echo '<form id="new_category">';
2640 echo get_string('addcategory','grades').':<input type="text" name="name" size="20" />';
2641 echo '<input type="hidden" name="id" value="'.$course->id.'" />';
2642 echo '<input type="hidden" name="action" value="insert_category" />';
2643 echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
2644 echo '<input type="submit" value="'.get_string('addcategory','grades').'" />';
2645 echo '</form>';
2648 function grade_delete_category_form() {
2649 // outputs a form to delete a category
2650 global $course;
2651 global $USER;
2652 echo '<form id="delete_category">';
2653 echo get_string('deletecategory','grades').': <select name="category_id">';
2654 grade_category_select();
2655 echo '</select><input type="hidden" name="id" value="'.$course->id.'" />';
2656 echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
2657 echo '<input type="hidden" name="action" value="delete_category" />';
2658 echo '<input type="submit" value="'.get_string('deletecategory','grades').'" /></form>';
2661 function grade_insert_category() {
2662 global $CFG;
2663 global $course;
2664 global $USER;
2666 $category->name=optional_param('name');
2667 $category->courseid=$course->id;
2669 if (!empty($USER->id)) {
2670 if (!confirm_sesskey()) {
2671 error(get_string('confirmsesskeybad', 'error'));
2675 // make sure the record isn't already there and insert if okay
2676 if (record_exists('grade_category', 'name', $category->name, 'courseid', $category->courseid)) {
2677 // category already exists
2679 elseif ($category->name != ''){
2680 if (!insert_record('grade_category', $category) ) {
2681 echo '<font color="red">'.get_string('addcategoryerror','grades').'</font>';
2686 function grade_category_select($id_selected = 0) {
2687 /// prints out a select box containing categories.
2688 global $CFG;
2689 global $course;
2692 echo '<option value="blank">'.get_string('choosecategory','grades').'</option>';
2694 $categories = get_records('grade_category', 'courseid', $course->id, 'name');
2696 if (!isset($categories)) {
2697 error(get_string("nocategories"));
2699 else {
2700 foreach($categories as $category) {
2701 if ($category->name == UNCATEGORISED) {
2702 $category->name = get_string('uncategorised', 'grades');
2704 if ($category->id == $id_selected) {
2705 echo '<option value="'.$category->id.'" selected="selected">'. format_string($category->name) .'</option>';
2707 else {
2708 echo '<option value="'.$category->id.'">'. format_string($category->name) .'</option>';
2714 function grade_display_grade_preferences($course, $preferences) {
2715 global $CFG;
2716 global $USER;
2718 if ($preferences->use_advanced == 0) {
2719 $useadvanced = 1;
2720 $buttonlabel = get_string('useadvanced', 'grades');
2721 } else {
2722 $useadvanced = 0;
2723 $buttonlabel = get_String('hideadvanced', 'grades');
2726 $buttonoptions = array('action' => 'set_grade_preferences',
2727 'id' => $course->id,
2728 'sesskey' => sesskey(),
2729 'use_advanced' => $useadvanced);
2732 print_heading_with_help(get_string('setpreferences','grades'), 'preferences', 'grade');
2734 echo '<center>';
2735 print_single_button('index.php', $buttonoptions, $buttonlabel, 'post');
2736 echo '<br /></center>';
2738 echo '<form id="set_grade_preferences" method="post" action="./index.php">';
2739 echo '<input type="hidden" name="action" value="set_grade_preferences" />';
2740 echo '<input type="hidden" name="id" value="'.$course->id.'" />';
2741 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
2742 echo '<table border="0" cellspacing="2" cellpadding="5" align="center" class="gradeprefs generalbox">';
2744 $optionsyesno = NULL;
2745 $optionsyesno[0] = get_string('no');
2746 $optionsyesno[1] = get_string('yes');
2749 if ($preferences->use_advanced) {
2750 $options = NULL;
2751 $options[0] = get_string('no');
2752 $options[1] = get_string('toonly', 'moodle', $course->teachers);
2753 $options[2] = get_string('toeveryone', 'moodle');
2755 // display grade weights
2756 echo '<tr><td class="c0">'.get_string('displayweighted','grades').':</td>';
2757 echo '<td class="c1">';
2758 choose_from_menu($options, 'display_weighted', $preferences->display_weighted, '');
2759 echo '</td></tr>';
2761 // display points
2762 echo '<tr><td class="c0">'.get_string('displaypoints','grades').':</td>';
2763 echo '<td class="c1">';
2764 choose_from_menu($options, 'display_points', $preferences->display_points, '');
2765 echo '</td></tr>';
2767 // display percent
2768 echo '<tr><td class="c0">'.get_string('displaypercent','grades').':</td>';
2769 echo '<td class="c1">';
2770 choose_from_menu($options, 'display_percent', $preferences->display_percent, '');
2771 echo '</td></tr>';
2773 // display letter grade
2774 echo '<tr><td class="c0">'.get_string('displaylettergrade','grades').':</td>';
2775 echo '<td class="c1">';
2776 choose_from_menu($options, 'display_letters', $preferences->display_letters, '');
2777 echo '</td></tr>';
2779 // letter grade uses weighted percent
2780 $options = NULL;
2781 $options[0] = get_string('usepercent','grades');
2782 $options[1] = get_string('useweighted','grades');
2784 echo '<tr><td class="c0">'.get_string('lettergrade','grades').':</td>';
2785 echo '<td class="c1">';
2786 choose_from_menu($options, 'use_weighted_for_letter', $preferences->use_weighted_for_letter, '');
2787 echo '</td></tr>';
2790 $headerlist[0] = get_string('none');
2791 for ($i=1; $i<=100; $i++) {
2792 $headerlist[$i] = $i;
2795 // reprint headers every n lines default n=0
2796 echo '<tr><td class="c0">'.get_string('reprintheaders','grades').':</td>';
2797 echo '<td class="c1">';
2798 choose_from_menu($headerlist, 'reprint_headers', $preferences->reprint_headers, '');
2799 echo '</td></tr>';
2801 // show hidden grade items to teacher
2802 echo '<tr><td class="c0">'.get_string('showhiddenitems','grades').'</td>';
2803 echo '<td class="c1">';
2804 choose_from_menu($optionsyesno, 'show_hidden', $preferences->show_hidden, '');
2805 echo '</td></tr>';
2807 echo '<tr><td colspan="3" align="center"><input type="submit" value="'.get_string('savepreferences','grades').'" /></td></tr></table></form>';
2812 function grade_display_letter_grades() {
2813 global $CFG;
2814 global $course;
2815 global $USER;
2817 $db_letters = get_records('grade_letter', 'courseid', $course->id, 'grade_high DESC');
2819 if ($db_letters) {
2820 $using_defaults = false;
2821 foreach ($db_letters as $letter) {
2822 $letters[$letter->id]->letter = $letter->letter;
2823 $letters[$letter->id]->grade_low = $letter->grade_low;
2824 $letters[$letter->id]->grade_high = $letter->grade_high;
2825 $letters[$letter->id]->courseid = $course->id;
2828 else {
2829 $using_defaults = true;
2830 // default A
2831 $letters[0]->letter='A';
2832 $letters[0]->grade_low=93.00;
2833 $letters[0]->grade_high=100.00;
2834 $letters[0]->courseid = $course->id;
2835 // default A-
2836 $letters[1]->letter='A-';
2837 $letters[1]->grade_low=90.00;
2838 $letters[1]->grade_high=92.99;
2839 $letters[1]->courseid = $course->id;
2840 // default B+
2841 $letters[2]->letter='B+';
2842 $letters[2]->grade_low=87.00;
2843 $letters[2]->grade_high=89.99;
2844 $letters[2]->courseid = $course->id;
2845 // default B
2846 $letters[3]->letter='B';
2847 $letters[3]->grade_low=83.00;
2848 $letters[3]->grade_high=86.99;
2849 $letters[3]->courseid = $course->id;
2850 // default B-
2851 $letters[4]->letter='B-';
2852 $letters[4]->grade_low=80.00;
2853 $letters[4]->grade_high=82.99;
2854 $letters[4]->courseid = $course->id;
2855 // default C+
2856 $letters[5]->letter='C+';
2857 $letters[5]->grade_low=77.00;
2858 $letters[5]->grade_high=79.99;
2859 $letters[5]->courseid = $course->id;
2860 // default C
2861 $letters[6]->letter='C';
2862 $letters[6]->grade_low=73.00;
2863 $letters[6]->grade_high=76.99;
2864 $letters[6]->courseid = $course->id;
2865 // default C-
2866 $letters[7]->letter='C-';
2867 $letters[7]->grade_low=70.00;
2868 $letters[7]->grade_high=72.99;
2869 $letters[7]->courseid = $course->id;
2870 // default D+
2871 $letters[8]->letter='D+';
2872 $letters[8]->grade_low=67.00;
2873 $letters[8]->grade_high=69.99;
2874 $letters[8]->courseid = $course->id;
2875 // default D
2876 $letters[9]->letter='D';
2877 $letters[9]->grade_low=60.00;
2878 $letters[9]->grade_high=66.99;
2879 $letters[9]->courseid = $course->id;
2880 // default F
2881 $letters[10]->letter='F';
2882 $letters[10]->grade_low=0.00;
2883 $letters[10]->grade_high=59.99;
2884 $letters[10]->courseid = $course->id;
2887 echo '<form id="grade_letter"><input type="hidden" name="id" value="'.$course->id.'" />';
2888 echo '<table border="0" cellspacing="2" cellpadding="5" align="center" class="generalbox"><tr>';
2889 echo '<th colspan="3" class="header" scope="col">'.get_string('setgradeletters','grades');
2890 helpbutton('letter', get_string('gradeletterhelp','grades'), 'grade');
2891 echo '</th></tr>';
2892 echo '<tr><td align="center" class="generaltableheader">'.get_string('gradeletter','grades').'</td>';
2893 echo '<td align="center" class="generaltableheader">'.get_string('lowgradeletter','grades').'</td>';
2894 echo '<td align="center" class="generaltableheader">'.get_string('highgradeletter','grades').'</td></tr>';
2895 echo '<input type="hidden" name="action" value="set_letter_grades" />';
2896 echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
2897 $i=0;
2898 foreach ($letters as $id=>$items) {
2899 if ($id !='' && !$using_defaults) {
2900 // send the record id so if the user deletes the values we can delete the row.
2901 echo '<input type="hidden" name="id'.$i.'" value="'.$id.'" />';
2903 echo '<tr><td align="center" class="generalboxcontent"><input size="8" type="text" name="letter'.$i.'" value="'.$items->letter.'" /></td>'."\n";
2904 echo '<td align="center" class="generalboxcontent"><input size="8" type="text" name="grade_low'.$i.'" value="'.$items->grade_low.'" /></td>'."\n";
2905 echo '<td align="center" class="generalboxcontent"><input size="8" type="text" name="grade_high'.$i.'" value="'.$items->grade_high.'" /></td></tr>'."\n";
2906 $i++;
2908 echo '<tr><td align="center" class="generalboxcontent"><input size="8" type="text" name="letter'.$i.'" value="" /></td><td align="center" class="generalboxcontent"><input size="8" type="text" name="grade_low'.$i.'" value="" /></td><td align="center" class="generalboxcontent"><input type="text" size="8" name="grade_high'.$i.'" value="" /></td></tr>';
2909 echo '<tr><td colspan="3" align="center" class="generalboxcontent"><input type="submit" value="'.get_string('savechanges','grades').'" /></td></tr>';
2910 echo '<input type="hidden" name="totalitems" value="'.$i.'" />';
2911 echo '<tr><td colspan="3" align="center" class="generalboxcontent">'.get_string('gradeletternote','grades').'</td></tr></table>';
2912 echo '</form>';
2915 function grade_set_letter_grades() {
2916 global $CFG;
2917 global $course;
2918 global $USER;
2920 if (!empty($USER->id)) {
2921 if (!confirm_sesskey()) {
2922 error(get_string('confirmsesskeybad', 'error'));
2926 $totalitems= clean_param($_REQUEST['totalitems'], PARAM_CLEAN);
2928 for($i=0; $i<=$totalitems; $i++) {
2929 if (isset($_REQUEST["id$i"])) {
2930 // item submitted was already in database
2931 $letterid = $_REQUEST["id$i"];
2932 $updateletters[$letterid]->letter = clean_param($_REQUEST["letter$i"], PARAM_CLEAN);
2933 // grade_low && grade_high don't need cleaning as they are possibly floats (no appropriate clean method) so we check is_numeric
2934 $updateletters[$letterid]->grade_low = $_REQUEST["grade_low$i"];
2935 $updateletters[$letterid]->grade_high = $_REQUEST["grade_high$i"];
2936 $updateletters[$letterid]->id = $letterid;
2938 else {
2939 // its a new item
2940 $newletter->letter = clean_param($_REQUEST["letter$i"], PARAM_CLEAN);
2941 $newletter->grade_low = $_REQUEST["grade_low$i"];
2942 $newletter->grade_high = $_REQUEST["grade_high$i"];
2943 $newletter->courseid = $course->id;
2944 if (is_numeric($newletter->grade_high) && is_numeric($newletter->grade_low)) {
2945 insert_record('grade_letter', $newletter);
2947 else {
2948 if ($i < $totalitems) {
2949 if ($newletter->grade_high != '' or $newletter->grade_low != '') {
2950 echo '<center>'.get_string('lettergradenonnumber','grades').' '.$newletter->letter.' item number: '.$i.'<br /></center>';
2957 if (isset($updateletters)) {
2958 foreach($updateletters as $id=>$items) {
2959 // see if any of the values are blank... if so delete them
2960 if ($items->letter == '' || $items->grade_low == '' || $items->grade_high == '') {
2961 delete_records('grade_letter', 'id', $id);
2963 else {
2964 if (is_numeric($items->grade_high) && is_numeric($items->grade_low)) {
2965 update_record('grade_letter', $items);
2967 else {
2968 echo '<center><font color="red">'.get_string('errorgradevaluenonnumeric','grades').$letter.'</font></center>';
2975 function grade_download_form($type='both') {
2976 global $course,$USER, $action, $cview;
2977 if ($type != 'both' and $type != 'ods' and $type != 'excel' and $type != 'text') {
2978 $type = 'both';
2981 if (has_capability('moodle/course:viewcoursegrades', get_context_instance(CONTEXT_COURSE, $course->id))) {
2982 echo '<table align="center"><tr>';
2983 $options['id'] = $course->id;
2984 $options['sesskey'] = $USER->sesskey;
2986 if ($type == 'both' || $type == 'ods') {
2987 $options['action'] = 'ods';
2988 echo '<td align="center">';
2989 print_single_button("index.php", $options, get_string("downloadods"));
2990 echo '</td>';
2992 if ($type == 'both' || $type == 'excel') {
2993 $options['action'] = 'excel';
2994 echo '<td align="center">';
2995 print_single_button("index.php", $options, get_string("downloadexcel"));
2996 echo '</td>';
2998 if ($type == 'both' || $type == 'text') {
2999 $options['action'] = 'text';
3000 echo '<td align="center">';
3001 print_single_button("index.php", $options, get_string("downloadtext"));
3002 echo '</td>';
3004 echo '<td>';
3006 $url = 'index.php?id='.$course->id;
3007 if (!empty($action)) {
3008 $url .= '&amp;action='.$action;
3009 if ($action == 'vcats') {
3010 $url .= '&amp;cview='.$cview;
3013 setup_and_print_groups($course, $course->groupmode, $url);
3014 echo '</td>';
3016 echo '</tr></table>';
3024 /**
3025 * Simply prints all grade of one student from all modules from a given course
3026 * used in the grade book for student view, and grade button under user profile
3027 * @param int $userid;
3028 * @param int $courseid;
3030 function print_student_grade($user, $course) {
3032 global $CFG;
3034 if (!empty($user)) {
3035 $grades[$user->id] = array(); // Collect all grades in this array
3036 $gradeshtml[$user->id] = array(); // Collect all grades html formatted in this array
3037 $totals[$user->id] = array(); // Collect all totals in this array
3040 $strmax = get_string("maximumshort");
3041 /// Collect modules data
3042 get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
3044 /// Search through all the modules, pulling out grade data
3045 $sections = get_all_sections($course->id); // Sort everything the same as the course
3047 // prints table
3049 // flag for detecting whether to print table header or not
3050 $nograde = 0;
3052 for ($i=0; $i<=$course->numsections; $i++) {
3053 if (isset($sections[$i])) { // should always be true
3054 $section = $sections[$i];
3055 if ($section->sequence) {
3056 $sectionmods = explode(",", $section->sequence);
3057 foreach ($sectionmods as $sectionmod) {
3059 $mod = $mods[$sectionmod];
3060 if (empty($mod->modname)) {
3061 continue; // Just in case, see MDL-7150
3063 $instance = get_record($mod->modname, 'id', $mod->instance);
3064 $libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
3066 if (file_exists($libfile)) {
3067 require_once($libfile);
3068 $gradefunction = $mod->modname.'_grades';
3069 if (function_exists($gradefunction)) { // Skip modules without grade function
3070 if ($modgrades = $gradefunction($mod->instance)) {
3071 if (!empty($modgrades->maxgrade)) {
3072 if ($mod->visible) {
3073 $maxgrade = $modgrades->maxgrade;
3074 } else {
3075 $maxgrade = $modgrades->maxgrade;
3077 } else {
3078 $maxgrade = '';
3081 if ($maxgrade) {
3082 if (!$nograde) {
3083 echo ('<table align="center" class="grades"><tr><th scope="col">'.get_string('activity').'</th><th scope="col">'.get_string('yourgrade','grades').'</th><th scope="col">'.get_string('maxgrade','grades').'</th></tr>');
3085 $nograde++;
3087 $link_id = grade_get_module_link($course->id, $mod->instance, $mod->module);
3088 $link = $CFG->wwwroot.'/mod/'.$mod->modname.'/view.php?id='.$link_id->id;
3090 echo '<tr>';
3091 if (!empty($modgrades->grades[$user->id])) {
3092 $currentgrade = $modgrades->grades[$user->id];
3093 echo "<td><a href='$link'>$mod->modfullname: ".format_string($instance->name,true)."</a></td><td>$currentgrade</td><td>$maxgrade</td>";
3094 } else {
3095 echo "<td><a href='$link'>$mod->modfullname: ".format_string($instance->name,true)."</a></td><td>".get_string('nograde')."</td><td>$maxgrade</td>";
3097 echo '</tr>';
3105 } // a new Moodle nesting record? ;-)
3107 if ($nograde) {
3108 echo '</table>';
3112 function grade_get_course_students($courseid) {
3113 global $CFG;
3114 // The list of roles to display is stored in CFG->gradebookroles
3115 if (!$context = get_context_instance(CONTEXT_COURSE, $courseid)) {
3116 return false;
3119 $configvar = get_config('', 'gradebookroles');
3120 if (empty($configvar)) {
3121 notify ('no roles defined in admin->appearance->graderoles');
3122 return false; // no roles to displayreturn false;
3125 if ($rolestoget = explode(',', $configvar)) {
3126 foreach ($rolestoget as $crole) {
3127 if ($tempstudents = get_role_users($crole, $context, true)) {
3128 foreach ($tempstudents as $tempuserid=>$tempstudent) {
3129 $students[$tempuserid] = $tempstudent;
3133 } else {
3134 notify ('no roles defined in admin->appearance->graderoles');
3135 return false; // no roles to displayreturn false;
3137 return isset($students)?$students:'';