MDL-35984 grade: Recalculate min/max for sum of grades when hidden grades are involved.

This commit is contained in:
Damyon Wiese 2014-08-04 15:03:26 +08:00
parent d2e9fc5845
commit 5232d3f2c9
6 changed files with 154 additions and 29 deletions

View file

@ -612,10 +612,11 @@ class grade_category extends grade_object {
}
// do the maths
$agg_grade = $this->aggregate_values($grade_values, $items);
$result = $this->aggregate_values_and_adjust_bounds($grade_values, $items);
$agg_grade = $result['grade'];
// recalculate the grade back to requested range
$finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $this->grade_item->grademin, $this->grade_item->grademax);
$finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $result['grademin'], $result['grademax']);
$grade->finalgrade = $this->grade_item->bounded_grade($finalgrade);
@ -628,15 +629,22 @@ class grade_category extends grade_object {
}
/**
* Internal function that calculates the aggregated grade for this grade category
* Internal function that calculates the aggregated grade and new min/max for this grade category
*
* Must be public as it is used by grade_grade::get_hiding_affected()
*
* @param array $grade_values An array of values to be aggregated
* @param array $items The array of grade_items
* @return float The aggregate grade for this grade category
* @return array containing values for:
* 'grade' => the new calculated grade
* 'grademin' => the new calculated min grade for the category
* 'grademax' => the new calculated max grade for the category
*/
public function aggregate_values($grade_values, $items) {
public function aggregate_values_and_adjust_bounds($grade_values, $items) {
$category_item = $this->get_grade_item();
$grademin = $category_item->grademin;
$grademax = $category_item->grademax;
switch ($this->aggregation) {
case GRADE_AGGREGATE_MEDIAN: // Middle point value in the set: ignores frequencies
@ -752,6 +760,19 @@ class grade_category extends grade_object {
}
break;
case GRADE_AGGREGATE_SUM: // Add up all the items.
$num = count($grade_values);
$sum = array_sum($grade_values);
$agg_grade = $sum / $num;
// Excluded items can affect the grademax for this grade_item.
$grademin = 0;
$grademax = 0;
foreach ($grade_values as $itemid => $grade_value) {
$grademin += $items[$itemid]->grademin;
$grademax += $items[$itemid]->grademax;
}
break;
case GRADE_AGGREGATE_MEAN: // Arithmetic average of all grade items (if ungraded aggregated, NULL counted as minimum)
default:
$num = count($grade_values);
@ -760,7 +781,24 @@ class grade_category extends grade_object {
break;
}
return $agg_grade;
return array('grade' => $agg_grade, 'grademin' => $grademin, 'grademax' => $grademax);
}
/**
* Internal function that calculates the aggregated grade for this grade category
*
* Must be public as it is used by grade_grade::get_hiding_affected()
*
* @deprecated since Moodle 2.8
* @param array $grade_values An array of values to be aggregated
* @param array $items The array of grade_items
* @return float The aggregate grade for this grade category
*/
public function aggregate_values($grade_values, $items) {
debugging('grade_category::aggregate_values() is deprecated.
Call grade_category::aggregate_values_and_adjust_bounds() instead.', DEBUG_DEVELOPER);
$result = $this->aggregate_values_and_adjust_bounds($grade_values, $items);
return $result['grade'];
}
/**

View file

@ -572,7 +572,10 @@ class grade_grade extends grade_object {
*
* @param array $grade_grades all course grades of one user, & used for better internal caching
* @param array $grade_items array of grade items, & used for better internal caching
* @return array
* @return array This is an array of 3 arrays:
* unknown => list of item ids that may be affected by hiding (with the calculated grade as the value)
* altered => list of item ids that are definitely affected by hiding (with the calculated grade as the value)
* alteredgrademax => for each item in altered or unknown, the new value of the grademax
*/
public static function get_hiding_affected(&$grade_grades, &$grade_items) {
global $CFG;
@ -585,6 +588,8 @@ class grade_grade extends grade_object {
$todo = array();
$unknown = array(); // can not find altered
$altered = array(); // altered grades
$alteredgrademax = array(); // Altered grade max values.
$alteredgrademin = array(); // Altered grade min values.
$hiddenfound = false;
foreach($grade_grades as $itemid=>$unused) {
@ -604,7 +609,10 @@ class grade_grade extends grade_object {
}
}
if (!$hiddenfound) {
return array('unknown'=>array(), 'altered'=>array());
return array('unknown' => array(),
'altered' => array(),
'alteredgrademax' => array(),
'alteredgrademin' => array());
}
$max = count($todo);
@ -646,6 +654,7 @@ class grade_grade extends grade_object {
if (array_key_exists($itemid, $altered)) {
//nulling an altered precursor
$values[$itemid] = $altered[$itemid];
unset($values[$itemid]);
} elseif (empty($values[$itemid])) {
$values[$itemid] = $grade_grades[$itemid]->finalgrade;
}
@ -686,12 +695,18 @@ class grade_grade extends grade_object {
continue;
}
$agg_grade = $grade_category->aggregate_values($values, $grade_items);
$adjustedgrade = $grade_category->aggregate_values_and_adjust_bounds($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);
$finalgrade = grade_grade::standardise_score($adjustedgrade['grade'],
0,
1,
$adjustedgrade['grademin'],
$adjustedgrade['grademax']);
$finalgrade = $grade_items[$do]->bounded_grade($finalgrade);
$alteredgrademin[$do] = $adjustedgrade['grademin'];
$alteredgrademax[$do] = $adjustedgrade['grademax'];
$altered[$do] = $finalgrade;
unset($todo[$key]);
@ -706,7 +721,10 @@ class grade_grade extends grade_object {
}
}
return array('unknown'=>$unknown, 'altered'=>$altered);
return array('unknown' => $unknown,
'altered' => $altered,
'alteredgrademax' => $alteredgrademax,
'alteredgrademin' => $alteredgrademin);
}
/**