diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php index d9232ed..4490586 100644 --- a/grade/report/user/lib.php +++ b/grade/report/user/lib.php @@ -299,15 +299,135 @@ class grade_report_user extends grade_report { } } + // 20130411 Colin. Added $emptygrades, get_gradeitems_with_empty_grades, + // adjust_max_sum_of_grades, and related code in order to + // address issues with the grade data displayed on this report. + + private $emptygrades; + function fill_table() { //print "
";
//print_r($this->gtree->top_element);
+
+ // adjust_max_sum_of_grades will need to know which grades are empty.
+ $this->emptygrades = $this->get_gradeitems_with_empty_grades();
+
+ $this->adjust_max_sum_of_grades($this->gtree->top_element);
+
$this->fill_table_recursive($this->gtree->top_element);
//print_r($this->tabledata);
//print "";
return true;
}
+ /**
+ * Returns the gradeitem ids for grade items for which this user has no grade.
+ */
+ private function get_gradeitems_with_empty_grades() {
+ global $DB;
+
+ $sql = "SELECT gi.id
+ FROM {grade_items} gi
+ LEFT JOIN {grade_grades} g ON g.itemid = gi.id and g.userid = :userid
+ WHERE gi.courseid = :courseid AND g.finalgrade IS NULL";
+
+ return $DB->get_fieldset_sql($sql,
+ array('userid' => $this->user->id,
+ 'courseid' => $this->courseid));
+ }
+
+ /**
+ * Logic should be similar to that in auto_update_max for GRADE_AGGREGATE_SUM.
+ * According to that function, we do not add in anything with aggregationcoef > 0
+ * because that indicates extra credit. The key difference is that we do not add in
+ * the max for any hidden grades.
+ */
+ private function adjust_max_sum_of_grades(&$element, &$current_category_element=null) {
+ global $CFG;
+
+ // This function evolved quite a bit in the course of development and could probably
+ // use some refactoring. Maybe we should do some of the filtering just prior to the
+ // new grademax assignment. Then it would be in only one place.
+
+ // We don't add in gradeitems with aggregationcoef > 0 because, for sum-of-grades,
+ // that indicates extra credit. We also don't add in any gradeitems if the parent
+ // category is set to aggregate only non-empty grades and the user has an empty
+ // grade for that item.
+
+ if ($element['type'] == 'category') {
+
+ // Using both of these to mimic the way that auto_update_max calls apply_limit_rules.
+ $element['gradeitems'] = array();
+ $element['newgrademaxes'] = array();
+
+ $category = $element['object'];
+ $gradeitem = $category->load_grade_item();
+ foreach($element['children'] as &$child) {
+ $this->adjust_max_sum_of_grades($child, $element);
+ }
+ if ($category->aggregation == GRADE_AGGREGATE_SUM) {
+ $newgrademaxes = $element['newgrademaxes'];
+ if (empty($newgrademaxes)) {
+ $gradeitem->grademax = 0;
+ } else {
+ $category->apply_limit_rules($newgrademaxes, $element['gradeitems']);
+ if (empty($newgrademaxes)) {
+ $gradeitem->grademax = 0; # TODO: Will array_sum return empty array as 0?
+ } else {
+ $gradeitem->grademax = array_sum($newgrademaxes);
+ }
+ }
+ }
+ if (empty($current_category_element)) {
+ return;
+ }
+
+ if ($this->include_in_range($gradeitem, $current_category_element)) {
+ $current_category_element['gradeitems'][$gradeitem->id] = $gradeitem;
+ $current_category_element['newgrademaxes'][$gradeitem->id] = $gradeitem->grademax;
+ }
+ } else if ($element['type'] == 'courseitem' or $element['type'] == 'categoryitem') {
+ $gradeitem = $element['object'];
+ $current_category = $current_category_element['object'];
+ if ($gradeitem->id === $current_category->grade_item->id) {
+ // Course and category items each appear twice in the tree. They appear as
+ // the grade_item on the category object and as one of the children in the
+ // in the element array. Use the same object for both.
+ $element['object'] = $current_category->grade_item;
+ }
+ } else if ($element['type'] == 'item') {
+ $gradeitem = $element['object'];
+ if ($this->include_in_range($gradeitem, $current_category_element)) {
+ $current_category_element['gradeitems'][$gradeitem->id] = $gradeitem;
+ $current_category_element['newgrademaxes'][$gradeitem->id] = $gradeitem->grademax;
+ }
+ }
+ }
+
+ private function include_in_range($gradeitem, $current_category_element) {
+ global $CFG;
+
+ // We don't include in the range if
+ // - item is extra credit (related to aggregationcoef)
+ // - the grade is hidden and we must display the total without it
+ // - the grade is empty and we must not display empty grades
+ // - the grade is neither a value type nor a scale type with grade_includescalesinaggregation set
+
+ if ($gradeitem->aggregationcoef <= 0
+ and ! ($this->showtotalsifcontainhidden[$this->courseid]==GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN
+ and
+ $gradeitem->is_hidden())
+ and ! ($current_category_element['object']->aggregateonlygraded
+ and
+ in_array($gradeitem->id, $this->emptygrades))
+ and ($gradeitem->gradetype == GRADE_TYPE_VALUE or ($gradeitem->gradetype == GRADE_TYPE_SCALE
+ and $CFG->grade_includescalesinaggregation)))
+ {
+ return true;
+ }
+ return false;
+ }
+
private function fill_table_recursive(&$element) {
global $DB, $CFG;
@@ -337,6 +457,10 @@ class grade_report_user extends grade_report {
/// Process those items that have scores associated
if ($type == 'item' or $type == 'categoryitem' or $type == 'courseitem') {
+
+ // Use (sometimes, anyway) the grade_item object that we processed in adjust_max_sum_of_grades.
+ $grade_item = $element['object'];
+
if (! $grade_grade = grade_grade::fetch(array('itemid'=>$grade_object->id,'userid'=>$this->user->id))) {
$grade_grade = new grade_grade();
$grade_grade->userid = $this->user->id;
@@ -425,15 +549,15 @@ class grade_report_user extends grade_report {
$data['grade']['content'] = '-';
} else {
$data['grade']['class'] = $class;
- $gradeval = $this->blank_hidden_total($this->courseid, $grade_grade->grade_item, $gradeval);
- $data['grade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true);
+ $gradeval = $this->blank_hidden_total($this->courseid, $grade_item, $gradeval);
+ $data['grade']['content'] = grade_format_gradevalue($gradeval, $grade_item, true);
}
}
// Range
if ($this->showrange) {
$data['range']['class'] = $class;
- $data['range']['content'] = $grade_grade->grade_item->get_formatted_range(GRADE_DISPLAY_TYPE_REAL, $this->rangedecimals);
+ $data['range']['content'] = $grade_item->get_formatted_range(GRADE_DISPLAY_TYPE_REAL, $this->rangedecimals);
}
// Percentage
@@ -446,7 +570,7 @@ class grade_report_user extends grade_report {
$data['percentage']['content'] = '-';
} else {
$data['percentage']['class'] = $class;
- $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE);
+ $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE);
}
}
@@ -460,11 +584,11 @@ class grade_report_user extends grade_report {
if (!$this->canviewhidden) {
$data['lettergrade']['content'] = '-';
} else {
- $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
+ $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
}
} else {
$data['lettergrade']['class'] = $class;
- $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
+ $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
}
}
diff --git a/lib/grade/grade_grade.php b/lib/grade/grade_grade.php
index a51586b..b5bd84b 100644
--- a/lib/grade/grade_grade.php
+++ b/lib/grade/grade_grade.php
@@ -651,12 +651,16 @@ class grade_grade extends grade_object {
}
}
+ // 20130411 Colin. Added code specific to GRADE_AGGREGATE_SUM to make this logic
+ // more consistent with that used to calculate persisted grades.
foreach ($values as $itemid=>$value) {
if ($grade_grades[$itemid]->is_excluded()) {
unset($values[$itemid]);
continue;
}
- $values[$itemid] = grade_grade::standardise_score($value, $grade_items[$itemid]->grademin, $grade_items[$itemid]->grademax, 0, 1);
+ if ($grade_category->aggregation != GRADE_AGGREGATE_SUM) {
+ $values[$itemid] = grade_grade::standardise_score($value, $grade_items[$itemid]->grademin, $grade_items[$itemid]->grademax, 0, 1);
+ }
}
if ($grade_category->aggregateonlygraded) {
@@ -686,10 +690,14 @@ class grade_grade extends grade_object {
continue;
}
- $agg_grade = $grade_category->aggregate_values($values, $grade_items);
+ if ($grade_category->aggregation == GRADE_AGGREGATE_SUM) {
+ $finalgrade = array_sum($values);
+ } else {
+ $agg_grade = $grade_category->aggregate_values($values, $grade_items);
- // recalculate the rawgrade back to requested range
- $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $grade_items[$do]->grademin, $grade_items[$do]->grademax);
+ // recalculate the rawgrade back to requested range
+ $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $grade_items[$do]->grademin, $grade_items[$do]->grademax);
+ }
$finalgrade = $grade_items[$do]->bounded_grade($finalgrade);