mirror of
https://github.com/moodle/moodle.git
synced 2025-04-14 13:02:07 +02:00
MDL-46139 Grades: Add a column to grade_grades to record how a grade is aggregated
This commit is contained in:
parent
2e19f5e8e7
commit
bfe969e8b3
@ -37,15 +37,7 @@ class edit_category_form extends moodleform {
|
||||
|
||||
$category = $this->_customdata['current'];
|
||||
|
||||
$this->aggregation_options = array(GRADE_AGGREGATE_MEAN =>get_string('aggregatemean', 'grades'),
|
||||
GRADE_AGGREGATE_WEIGHTED_MEAN =>get_string('aggregateweightedmean', 'grades'),
|
||||
GRADE_AGGREGATE_WEIGHTED_MEAN2 =>get_string('aggregateweightedmean2', 'grades'),
|
||||
GRADE_AGGREGATE_EXTRACREDIT_MEAN=>get_string('aggregateextracreditmean', 'grades'),
|
||||
GRADE_AGGREGATE_MEDIAN =>get_string('aggregatemedian', 'grades'),
|
||||
GRADE_AGGREGATE_MIN =>get_string('aggregatemin', 'grades'),
|
||||
GRADE_AGGREGATE_MAX =>get_string('aggregatemax', 'grades'),
|
||||
GRADE_AGGREGATE_MODE =>get_string('aggregatemode', 'grades'),
|
||||
GRADE_AGGREGATE_SUM =>get_string('aggregatesum', 'grades'));
|
||||
$this->aggregation_options = grade_helper::get_aggregation_strings();
|
||||
|
||||
// visible elements
|
||||
$mform->addElement('header', 'headercategory', get_string('gradecategory', 'grades'));
|
||||
|
@ -661,15 +661,7 @@ class grade_edit_tree_column_aggregation extends grade_edit_tree_column_category
|
||||
throw new Exception('Array key (id) missing from 3rd param of grade_edit_tree_column_aggregation::get_category_cell($category, $levelclass, $params)');
|
||||
}
|
||||
|
||||
$options = array(GRADE_AGGREGATE_MEAN => get_string('aggregatemean', 'grades'),
|
||||
GRADE_AGGREGATE_WEIGHTED_MEAN => get_string('aggregateweightedmean', 'grades'),
|
||||
GRADE_AGGREGATE_WEIGHTED_MEAN2 => get_string('aggregateweightedmean2', 'grades'),
|
||||
GRADE_AGGREGATE_EXTRACREDIT_MEAN => get_string('aggregateextracreditmean', 'grades'),
|
||||
GRADE_AGGREGATE_MEDIAN => get_string('aggregatemedian', 'grades'),
|
||||
GRADE_AGGREGATE_MIN => get_string('aggregatemin', 'grades'),
|
||||
GRADE_AGGREGATE_MAX => get_string('aggregatemax', 'grades'),
|
||||
GRADE_AGGREGATE_MODE => get_string('aggregatemode', 'grades'),
|
||||
GRADE_AGGREGATE_SUM => get_string('aggregatesum', 'grades'));
|
||||
$options = grade_helper::get_aggregation_strings();
|
||||
|
||||
$visible = explode(',', $CFG->grade_aggregations_visible);
|
||||
foreach ($options as $constant => $string) {
|
||||
@ -751,7 +743,7 @@ class grade_edit_tree_column_weight extends grade_edit_tree_column {
|
||||
public function get_header_cell() {
|
||||
global $OUTPUT;
|
||||
$headercell = clone($this->headercell);
|
||||
$headercell->text = get_string('weightuc', 'grades').$OUTPUT->help_icon('aggregationcoefweight', 'grades');
|
||||
$headercell->text = get_string('weights', 'grades').$OUTPUT->help_icon('aggregationcoefweight', 'grades');
|
||||
return $headercell;
|
||||
}
|
||||
|
||||
|
@ -1171,17 +1171,17 @@ class grade_structure {
|
||||
|
||||
} else if (($is_course or $is_category) and ($is_scale or $is_value)) {
|
||||
if ($category = $element['object']->get_item_category()) {
|
||||
$aggrstrings = grade_helper::get_aggregation_strings();
|
||||
$stragg = $aggrstrings[$category->aggregation];
|
||||
switch ($category->aggregation) {
|
||||
case GRADE_AGGREGATE_MEAN:
|
||||
case GRADE_AGGREGATE_MEDIAN:
|
||||
case GRADE_AGGREGATE_WEIGHTED_MEAN:
|
||||
case GRADE_AGGREGATE_WEIGHTED_MEAN2:
|
||||
case GRADE_AGGREGATE_EXTRACREDIT_MEAN:
|
||||
$stragg = get_string('aggregation', 'grades');
|
||||
return '<img src="'.$OUTPUT->pix_url('i/agg_mean') . '" ' .
|
||||
'class="icon itemicon" title="'.s($stragg).'" alt="'.s($stragg).'"/>';
|
||||
case GRADE_AGGREGATE_SUM:
|
||||
$stragg = get_string('aggregation', 'grades');
|
||||
return '<img src="'.$OUTPUT->pix_url('i/agg_sum') . '" ' .
|
||||
'class="icon itemicon" title="'.s($stragg).'" alt="'.s($stragg).'"/>';
|
||||
}
|
||||
@ -2449,6 +2449,11 @@ abstract class grade_helper {
|
||||
* @var array
|
||||
*/
|
||||
protected static $pluginstrings = null;
|
||||
/**
|
||||
* Cached grade aggregation strings
|
||||
* @var array
|
||||
*/
|
||||
protected static $aggregationstrings = null;
|
||||
|
||||
/**
|
||||
* Gets strings commonly used by the describe plugins
|
||||
@ -2481,6 +2486,29 @@ abstract class grade_helper {
|
||||
}
|
||||
return self::$pluginstrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets strings describing the available aggregation methods.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_aggregation_strings() {
|
||||
if (self::$aggregationstrings === null) {
|
||||
self::$aggregationstrings = array(
|
||||
GRADE_AGGREGATE_MEAN => get_string('aggregatemean', 'grades'),
|
||||
GRADE_AGGREGATE_WEIGHTED_MEAN => get_string('aggregateweightedmean', 'grades'),
|
||||
GRADE_AGGREGATE_WEIGHTED_MEAN2 => get_string('aggregateweightedmean2', 'grades'),
|
||||
GRADE_AGGREGATE_EXTRACREDIT_MEAN => get_string('aggregateextracreditmean', 'grades'),
|
||||
GRADE_AGGREGATE_MEDIAN => get_string('aggregatemedian', 'grades'),
|
||||
GRADE_AGGREGATE_MIN => get_string('aggregatemin', 'grades'),
|
||||
GRADE_AGGREGATE_MAX => get_string('aggregatemax', 'grades'),
|
||||
GRADE_AGGREGATE_MODE => get_string('aggregatemode', 'grades'),
|
||||
GRADE_AGGREGATE_SUM => get_string('aggregatesum', 'grades')
|
||||
);
|
||||
}
|
||||
return self::$aggregationstrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get grade_plugin_info object for managing settings if the user can
|
||||
*
|
||||
|
@ -408,10 +408,12 @@ class grade_report_user extends grade_report {
|
||||
|
||||
if (!$hide) {
|
||||
/// Excluded Item
|
||||
/**
|
||||
if ($grade_grade->is_excluded()) {
|
||||
$fullname .= ' ['.get_string('excluded', 'grades').']';
|
||||
$excluded = ' excluded';
|
||||
}
|
||||
**/
|
||||
|
||||
/// Other class information
|
||||
$class = "$hidden $excluded";
|
||||
@ -456,8 +458,14 @@ class grade_report_user extends grade_report {
|
||||
$data['weight']['content'] = '-';
|
||||
$data['weight']['headers'] = "$header_cat $header_row weight";
|
||||
// has a weight assigned, might be extra credit
|
||||
if ($grade_object->aggregationcoef > 0 && $type <> 'courseitem') {
|
||||
$data['weight']['content'] = number_format($grade_object->aggregationcoef,2);
|
||||
|
||||
$hints = $grade_grade->get_aggregation_hint($grade_object);
|
||||
if ($hints) {
|
||||
// This obliterates the weight because it provides a more informative description.
|
||||
if (intval($hints)) {
|
||||
$hints = format_float(intval($hints) / 100.0, 2) . ' %';
|
||||
}
|
||||
$data['weight']['content'] = $hints;
|
||||
}
|
||||
}
|
||||
|
||||
|
1
lib/db/install.xml
Normal file → Executable file
1
lib/db/install.xml
Normal file → Executable file
@ -1764,6 +1764,7 @@
|
||||
<FIELD NAME="informationformat" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="format of information text"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="the time this grade was first created"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="the time this grade was last modified"/>
|
||||
<FIELD NAME="usedinaggregation" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="unknown" SEQUENCE="false" COMMENT="One of several values describing how this grade_grade was used when calculating the aggregation. Possible values are "unknown", "dropped", "novalue", "included""/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
@ -3719,6 +3719,21 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2014072400.01);
|
||||
}
|
||||
|
||||
if ($oldversion < 2014080700.00) {
|
||||
|
||||
// Define field usedinaggregation to be added to grade_grades.
|
||||
$table = new xmldb_table('grade_grades');
|
||||
$field = new xmldb_field('usedinaggregation', XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, 'unknown', 'timemodified');
|
||||
|
||||
// Conditionally launch add field usedinaggregation.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2014080700.00);
|
||||
}
|
||||
|
||||
if ($oldversion < 2014080801.00) {
|
||||
|
||||
// Define index behaviour (not unique) to be added to question_attempts.
|
||||
|
@ -526,6 +526,12 @@ class grade_category extends grade_object {
|
||||
*/
|
||||
private function aggregate_grades($userid, $items, $grade_values, $oldgrade, $excluded) {
|
||||
global $CFG;
|
||||
|
||||
// Remember these so we can set flags on them to describe how they were used in the aggregation.
|
||||
$novalue = array();
|
||||
$dropped = array();
|
||||
$usedweights = array();
|
||||
|
||||
if (empty($userid)) {
|
||||
//ignore first call
|
||||
return;
|
||||
@ -552,10 +558,10 @@ class grade_category extends grade_object {
|
||||
// can not use own final category grade in calculation
|
||||
unset($grade_values[$this->grade_item->id]);
|
||||
|
||||
|
||||
// sum is a special aggregation types - it adjusts the min max, does not use relative values
|
||||
if ($this->aggregation == GRADE_AGGREGATE_SUM) {
|
||||
$this->sum_grades($grade, $oldfinalgrade, $items, $grade_values, $excluded);
|
||||
$this->sum_grades($grade, $oldfinalgrade, $items, $grade_values, $excluded, $usedweights);
|
||||
$this->set_usedinaggregation($userid, $usedweights, $novalue, $dropped);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -566,6 +572,8 @@ class grade_category extends grade_object {
|
||||
if (!is_null($oldfinalgrade)) {
|
||||
$grade->update('aggregation');
|
||||
}
|
||||
$dropped = $grade_values;
|
||||
$this->set_usedinaggregation($userid, $usedweights, $novalue, $dropped);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -578,10 +586,12 @@ class grade_category extends grade_object {
|
||||
if (is_null($v)) {
|
||||
// null means no grade
|
||||
unset($grade_values[$itemid]);
|
||||
$novalue[$itemid] = 0;
|
||||
continue;
|
||||
|
||||
} else if (in_array($itemid, $excluded)) {
|
||||
unset($grade_values[$itemid]);
|
||||
$dropped[$itemid] = 0;
|
||||
continue;
|
||||
}
|
||||
// If grademin is hidden, set it to 0.
|
||||
@ -603,7 +613,13 @@ class grade_category extends grade_object {
|
||||
}
|
||||
|
||||
// limit and sort
|
||||
$allvalues = $grade_values;
|
||||
$this->apply_limit_rules($grade_values, $items);
|
||||
|
||||
$moredropped = array_diff($allvalues, $grade_values);
|
||||
foreach ($moredropped as $drop => $unused) {
|
||||
$dropped[$drop] = 0;
|
||||
}
|
||||
asort($grade_values, SORT_NUMERIC);
|
||||
|
||||
// let's see we have still enough grades to do any statistics
|
||||
@ -614,11 +630,12 @@ class grade_category extends grade_object {
|
||||
if (!is_null($oldfinalgrade)) {
|
||||
$grade->update('aggregation');
|
||||
}
|
||||
$this->set_usedinaggregation($userid, $usedweights, $novalue, $dropped);
|
||||
return;
|
||||
}
|
||||
|
||||
// do the maths
|
||||
$result = $this->aggregate_values_and_adjust_bounds($grade_values, $items);
|
||||
$result = $this->aggregate_values_and_adjust_bounds($grade_values, $items, $usedweights);
|
||||
$agg_grade = $result['grade'];
|
||||
|
||||
if (!$minvisible and $this->grade_item->gradetype != GRADE_TYPE_SCALE) {
|
||||
@ -635,9 +652,66 @@ class grade_category extends grade_object {
|
||||
$grade->update('aggregation');
|
||||
}
|
||||
|
||||
$this->set_usedinaggregation($userid, $usedweights, $novalue, $dropped);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flags on the grade_grade items to indicate how individual grades are used
|
||||
* in the aggregation.
|
||||
*
|
||||
* @param int $userid The user we have aggregated the grades for.
|
||||
* @param array $usedweights An array with keys for each of the grade_item columns included in the aggregation. The value are the relative weight.
|
||||
* @param array $novalue An array with keys for each of the grade_item columns skipped because
|
||||
* they had no value in the aggregation
|
||||
* @param array $dropped An array with keys for each of the grade_item columns dropped
|
||||
* because of any drop lowest/highest settings in the aggregation
|
||||
*/
|
||||
private function set_usedinaggregation($userid, $usedweights, $novalue, $dropped) {
|
||||
global $DB;
|
||||
|
||||
// Included.
|
||||
if (!empty($usedweights)) {
|
||||
// The usedweights items are updated individually to record the weights.
|
||||
foreach ($usedweights as $gradeitemid => $contribution) {
|
||||
// Convert contribution to a 4 digit integer so there are no localization problems.
|
||||
$contribution = intval($contribution * 10000);
|
||||
$DB->set_field_select('grade_grades',
|
||||
'usedinaggregation',
|
||||
$contribution,
|
||||
"itemid = :itemid AND userid = :userid",
|
||||
array('itemid'=>$gradeitemid, 'userid'=>$userid));
|
||||
}
|
||||
}
|
||||
|
||||
// No value.
|
||||
if (!empty($novalue)) {
|
||||
list($itemsql, $itemlist) = $DB->get_in_or_equal(array_keys($novalue), SQL_PARAMS_NAMED, 'g');
|
||||
|
||||
$itemlist['userid'] = $userid;
|
||||
|
||||
$DB->set_field_select('grade_grades',
|
||||
'usedinaggregation',
|
||||
'novalue',
|
||||
"itemid $itemsql AND userid = :userid",
|
||||
$itemlist);
|
||||
}
|
||||
|
||||
// Dropped.
|
||||
if (!empty($dropped)) {
|
||||
list($itemsql, $itemlist) = $DB->get_in_or_equal(array_keys($dropped), SQL_PARAMS_NAMED, 'g');
|
||||
|
||||
$itemlist['userid'] = $userid;
|
||||
|
||||
$DB->set_field_select('grade_grades',
|
||||
'usedinaggregation',
|
||||
'dropped',
|
||||
"itemid $itemsql AND userid = :userid",
|
||||
$itemlist);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function that calculates the aggregated grade and new min/max for this grade category
|
||||
*
|
||||
@ -646,12 +720,14 @@ class grade_category extends grade_object {
|
||||
* @param array $grade_values An array of values to be aggregated
|
||||
* @param array $items The array of grade_items
|
||||
* @since Moodle 2.6.5, 2.7.2
|
||||
* @param array & $weights If provided, will be filled with the normalized weights
|
||||
* for each grade_item as used in the aggregation.
|
||||
* @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_and_adjust_bounds($grade_values, $items) {
|
||||
public function aggregate_values_and_adjust_bounds($grade_values, $items, & $weights = null) {
|
||||
$category_item = $this->get_grade_item();
|
||||
$grademin = $category_item->grademin;
|
||||
$grademax = $category_item->grademax;
|
||||
@ -668,17 +744,42 @@ class grade_category extends grade_object {
|
||||
} else {
|
||||
$agg_grade = $grades[intval(($num/2)-0.5)];
|
||||
}
|
||||
|
||||
// Record the weights evenly.
|
||||
if ($weights !== null && $num > 0) {
|
||||
foreach ($grade_values as $itemid=>$grade_value) {
|
||||
$weights[$itemid] = 1.0 / $num;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADE_AGGREGATE_MIN:
|
||||
$agg_grade = reset($grade_values);
|
||||
// Record the weights as used.
|
||||
if ($weights !== null) {
|
||||
foreach ($grade_values as $itemid=>$grade_value) {
|
||||
$weights[$itemid] = 0;
|
||||
}
|
||||
}
|
||||
// Set the first item to 1.
|
||||
$itemids = array_keys($grade_values);
|
||||
$weights[reset($itemids)] = 1;
|
||||
break;
|
||||
|
||||
case GRADE_AGGREGATE_MAX:
|
||||
$agg_grade = array_pop($grade_values);
|
||||
// Record the weights as used.
|
||||
if ($weights !== null) {
|
||||
foreach ($grade_values as $itemid=>$grade_value) {
|
||||
$weights[$itemid] = 0;
|
||||
}
|
||||
}
|
||||
// Set the last item to 1.
|
||||
$itemids = array_keys($grade_values);
|
||||
$weights[end($itemids)] = 1;
|
||||
$agg_grade = end($grade_values);
|
||||
break;
|
||||
|
||||
case GRADE_AGGREGATE_MODE: // the most common value, average used if multimode
|
||||
case GRADE_AGGREGATE_MODE: // the most common value
|
||||
// array_count_values only counts INT and STRING, so if grades are floats we must convert them to string
|
||||
$converted_grade_values = array();
|
||||
|
||||
@ -690,6 +791,9 @@ class grade_category extends grade_object {
|
||||
} else {
|
||||
$converted_grade_values[$k] = $gv;
|
||||
}
|
||||
if ($weights !== null) {
|
||||
$weights[$k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$freq = array_count_values($converted_grade_values);
|
||||
@ -698,6 +802,14 @@ class grade_category extends grade_object {
|
||||
$modes = array_keys($freq, $top); // search for all modes (have the same highest count)
|
||||
rsort($modes, SORT_NUMERIC); // get highest mode
|
||||
$agg_grade = reset($modes);
|
||||
// Record the weights as used.
|
||||
if ($weights !== null && $top > 0) {
|
||||
foreach ($grade_values as $k => $gv) {
|
||||
if ($gv == $agg_grade) {
|
||||
$weights[$k] = 1.0 / $top;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADE_AGGREGATE_WEIGHTED_MEAN: // Weighted average of all existing final grades, weight specified in coef
|
||||
@ -711,13 +823,22 @@ class grade_category extends grade_object {
|
||||
}
|
||||
$weightsum += $items[$itemid]->aggregationcoef;
|
||||
$sum += $items[$itemid]->aggregationcoef * $grade_value;
|
||||
if ($weights !== null) {
|
||||
$weights[$itemid] = $items[$itemid]->aggregationcoef;
|
||||
}
|
||||
}
|
||||
|
||||
if ($weightsum == 0) {
|
||||
$agg_grade = null;
|
||||
|
||||
} else {
|
||||
$agg_grade = $sum / $weightsum;
|
||||
if ($weights !== null) {
|
||||
// Normalise the weights.
|
||||
foreach ($weights as $itemid => $weight) {
|
||||
$weights[$itemid] = $weight / $weightsum;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
@ -739,13 +860,23 @@ class grade_category extends grade_object {
|
||||
}
|
||||
$sum += $weight * $grade_value;
|
||||
}
|
||||
|
||||
if ($weightsum == 0) {
|
||||
$agg_grade = $sum; // only extra credits
|
||||
|
||||
} else {
|
||||
$agg_grade = $sum / $weightsum;
|
||||
}
|
||||
// Record the weights as used.
|
||||
if ($weights !== null) {
|
||||
foreach ($grade_values as $itemid=>$grade_value) {
|
||||
if ($items[$itemid]->aggregationcoef == 0 && $weightsum > 0) {
|
||||
$weight = $items[$itemid]->grademax - $items[$itemid]->grademin;
|
||||
$weights[$itemid] = ($items[$itemid]->grademax - $items[$itemid]->grademin) / $weightsum;
|
||||
} else {
|
||||
$weights[$itemid] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADE_AGGREGATE_EXTRACREDIT_MEAN: // special average
|
||||
@ -757,9 +888,22 @@ class grade_category extends grade_object {
|
||||
if ($items[$itemid]->aggregationcoef == 0) {
|
||||
$num += 1;
|
||||
$sum += $grade_value;
|
||||
if ($weights !== null) {
|
||||
$weights[$itemid] = 1;
|
||||
}
|
||||
|
||||
} else if ($items[$itemid]->aggregationcoef > 0) {
|
||||
$sum += $items[$itemid]->aggregationcoef * $grade_value;
|
||||
if ($weights !== null) {
|
||||
$weights[$itemid] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($weights !== null && $num > 0) {
|
||||
foreach ($grade_values as $itemid=>$grade_value) {
|
||||
if ($weights[$itemid]) {
|
||||
$weights[$itemid] = 1.0 / $num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -781,9 +925,11 @@ class grade_category extends grade_object {
|
||||
$sum += $grade_value * ($items[$itemid]->grademax - $items[$itemid]->grademin);
|
||||
$grademin += $items[$itemid]->grademin;
|
||||
$grademax += $items[$itemid]->grademax;
|
||||
if ($weights !== null && $num > 0) {
|
||||
$weights[$itemid] = 1.0 / $num;
|
||||
}
|
||||
}
|
||||
|
||||
$agg_grade = $sum / ($grademax - $grademin);
|
||||
break;
|
||||
|
||||
case GRADE_AGGREGATE_MEAN: // Arithmetic average of all grade items (if ungraded aggregated, NULL counted as minimum)
|
||||
@ -791,6 +937,12 @@ class grade_category extends grade_object {
|
||||
$num = count($grade_values);
|
||||
$sum = array_sum($grade_values);
|
||||
$agg_grade = $sum / $num;
|
||||
// Record the weights evenly.
|
||||
if ($weights !== null && $num > 0) {
|
||||
foreach ($grade_values as $itemid=>$grade_value) {
|
||||
$weights[$itemid] = 1.0 / $num;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -874,12 +1026,19 @@ class grade_category extends grade_object {
|
||||
* @param array $items Grade items
|
||||
* @param array $grade_values Grade values
|
||||
* @param array $excluded Excluded
|
||||
* @param array & $weights For filling with the weights used in the aggregation.
|
||||
*/
|
||||
private function sum_grades(&$grade, $oldfinalgrade, $items, $grade_values, $excluded) {
|
||||
private function sum_grades(&$grade, $oldfinalgrade, $items, $grade_values, $excluded, & $weights = null) {
|
||||
if (empty($items)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($weights) {
|
||||
foreach ($grade_values as $itemid => $value) {
|
||||
$weights[$itemid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ungraded and excluded items are not used in aggregation
|
||||
foreach ($grade_values as $itemid=>$v) {
|
||||
|
||||
@ -906,6 +1065,11 @@ class grade_category extends grade_object {
|
||||
|
||||
$sum = array_sum($grade_values);
|
||||
$grade->finalgrade = $this->grade_item->bounded_grade($sum);
|
||||
if ($weights !== null && $sum > 0) {
|
||||
foreach ($grade_values as $itemid => $value) {
|
||||
$weights[$itemid] = $value / $sum;
|
||||
}
|
||||
}
|
||||
|
||||
// update in db if changed
|
||||
if (grade_floats_different($grade->finalgrade, $oldfinalgrade)) {
|
||||
|
@ -49,7 +49,8 @@ class grade_grade extends grade_object {
|
||||
*/
|
||||
public $required_fields = array('id', 'itemid', 'userid', 'rawgrade', 'rawgrademax', 'rawgrademin',
|
||||
'rawscaleid', 'usermodified', 'finalgrade', 'hidden', 'locked',
|
||||
'locktime', 'exported', 'overridden', 'excluded', 'timecreated', 'timemodified');
|
||||
'locktime', 'exported', 'overridden', 'excluded', 'timecreated',
|
||||
'timemodified', 'usedinaggregation');
|
||||
|
||||
/**
|
||||
* Array of optional fields with default values (these should match db defaults)
|
||||
@ -159,6 +160,12 @@ class grade_grade extends grade_object {
|
||||
*/
|
||||
public $timemodified = null;
|
||||
|
||||
/**
|
||||
* Used in aggregation flag. Can be one of 'unknown', 'dropped', 'novalue' or a specific weighting.
|
||||
* @var string $usedinaggregation
|
||||
*/
|
||||
public $usedinaggregation = 'unknown';
|
||||
|
||||
|
||||
/**
|
||||
* Returns array of grades for given grade_item+users
|
||||
@ -285,6 +292,26 @@ class grade_grade extends grade_object {
|
||||
return $this->timecreated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the info on how this value was used in the aggregated grade
|
||||
*
|
||||
* @return string One of 'dropped', 'excluded', 'novalue' or a specific weighting
|
||||
*/
|
||||
public function get_usedinaggregation() {
|
||||
return $this->usedinaggregation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set usedinaggregation flag
|
||||
*
|
||||
* @param string $usedinaggregation
|
||||
* @return void
|
||||
*/
|
||||
public function set_usedinaggregation($usedinaggregation) {
|
||||
$this->usedinaggregation = $usedinaggregation;
|
||||
$this->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns timestamp when last graded, null if no grade present
|
||||
*
|
||||
@ -923,5 +950,54 @@ class grade_grade extends grade_object {
|
||||
|
||||
// Pass information on to completion system
|
||||
$completion->inform_grade_changed($cm, $this->grade_item, $this, $deleted);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get some useful information about how this grade_grade is reflected in the aggregation
|
||||
* for the grade_category. For example this could be an extra credit item, and it could be
|
||||
* dropped because it's in the X lowest or highest.
|
||||
*
|
||||
* @param grade_item $gradeitem An optional grade_item, saves having to load the grade_grade's grade_item
|
||||
* @return string - A list of keywords that hint at how this grade_grade is reflected in the aggregation.
|
||||
*/
|
||||
function get_aggregation_hint($gradeitem = null) {
|
||||
$hint = '';
|
||||
|
||||
if ($this->is_excluded()) {
|
||||
$hint = get_string('excluded', 'grades');
|
||||
} else {
|
||||
if (empty($grade_item)) {
|
||||
if (!isset($this->grade_item)) {
|
||||
$this->load_grade_item();
|
||||
}
|
||||
} else {
|
||||
$this->grade_item = $grade_item;
|
||||
$this->itemid = $grade_item->id;
|
||||
}
|
||||
$item = $this->grade_item;
|
||||
|
||||
if (!$item->is_course_item()) {
|
||||
$parent_category = $item->get_parent_category();
|
||||
$parent_category->apply_forced_settings();
|
||||
if ($parent_category->is_extracredit_used() && ($item->aggregationcoef > 0)) {
|
||||
$hint = get_string('aggregationcoefextra', 'grades');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Is it dropped?
|
||||
if ($hint == '') {
|
||||
$aggr = $this->get_usedinaggregation();
|
||||
if ($aggr == 'dropped') {
|
||||
$hint = get_string('dropped', 'grades');
|
||||
} else if ($aggr == 'novalue') {
|
||||
$hint = '-';
|
||||
} else if ($aggr != 'unknown') {
|
||||
$hint = $aggr;
|
||||
}
|
||||
}
|
||||
|
||||
return $hint;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user