mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 22:08:20 +01:00
MDL-10901 new SUM aggregation type
MDL-12154 used proper cast to float before !== comparison
This commit is contained in:
parent
bc1bbaf477
commit
0758a08e2a
@ -68,6 +68,12 @@ if ($mform->is_cancelled()) {
|
||||
redirect($returnurl);
|
||||
|
||||
} else if ($data = $mform->get_data(false)) {
|
||||
if (!isset($data->aggregateonlygraded)) {
|
||||
$data->aggregateonlygraded = 0;
|
||||
}
|
||||
if (!isset($data->aggregateoutcomes)) {
|
||||
$data->aggregateoutcomes = 0;
|
||||
}
|
||||
grade_category::set_properties($grade_category, $data);
|
||||
|
||||
if (empty($grade_category->id)) {
|
||||
|
@ -37,7 +37,8 @@ class edit_category_form extends moodleform {
|
||||
GRADE_AGGREGATE_MAX =>get_string('aggregatemax', 'grades'),
|
||||
GRADE_AGGREGATE_MODE =>get_string('aggregatemode', 'grades'),
|
||||
GRADE_AGGREGATE_WEIGHTED_MEAN =>get_string('aggregateweightedmean', 'grades'),
|
||||
GRADE_AGGREGATE_EXTRACREDIT_MEAN=>get_string('aggregateextracreditmean', 'grades'));
|
||||
GRADE_AGGREGATE_EXTRACREDIT_MEAN=>get_string('aggregateextracreditmean', 'grades'),
|
||||
GRADE_AGGREGATE_SUM =>get_string('aggregatesum', 'grades'));
|
||||
|
||||
// visible elements
|
||||
$mform->addElement('header', 'gradecat', get_string('gradecategory', 'grades'));
|
||||
@ -47,14 +48,19 @@ class edit_category_form extends moodleform {
|
||||
$mform->addElement('select', 'aggregation', get_string('aggregation', 'grades'), $options);
|
||||
$mform->setHelpButton('aggregation', array('aggregation', get_string('aggregation', 'grades'), 'grade'));
|
||||
|
||||
$mform->addElement('advcheckbox', 'aggregateonlygraded', get_string('aggregateonlygraded', 'grades'));
|
||||
$mform->addElement('checkbox', 'aggregateonlygraded', get_string('aggregateonlygraded', 'grades'));
|
||||
$mform->setHelpButton('aggregateonlygraded', array(false, get_string('aggregateonlygraded', 'grades'),
|
||||
false, true, false, get_string('aggregateonlygradedhelp', 'grades')));
|
||||
$mform->disabledIf('aggregateonlygraded', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
|
||||
|
||||
if (!empty($CFG->enableoutcomes)) {
|
||||
$mform->addElement('advcheckbox', 'aggregateoutcomes', get_string('aggregateoutcomes', 'grades'));
|
||||
if (empty($CFG->enableoutcomes)) {
|
||||
$mform->addElement('hidden', 'aggregateoutcomes');
|
||||
$mform->setType('aggregateoutcomes', PARAM_INT);
|
||||
} else {
|
||||
$mform->addElement('checkbox', 'aggregateoutcomes', get_string('aggregateoutcomes', 'grades'));
|
||||
$mform->setHelpButton('aggregateoutcomes', array(false, get_string('aggregateoutcomes', 'grades'),
|
||||
false, true, false, get_string('aggregateoutcomeshelp', 'grades')));
|
||||
$mform->disabledIf('aggregateoutcomes', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
|
||||
}
|
||||
|
||||
$mform->addElement('advcheckbox', 'aggregatesubcats', get_string('aggregatesubcats', 'grades'));
|
||||
|
@ -197,6 +197,7 @@ class edit_item_form extends moodleform {
|
||||
//$mform->removeElement('calculation');
|
||||
}
|
||||
}
|
||||
|
||||
//remove the aggregation coef element if not needed
|
||||
if ($grade_item->is_course_item()) {
|
||||
$mform->removeElement('aggregationcoef');
|
||||
@ -227,6 +228,23 @@ class edit_item_form extends moodleform {
|
||||
}
|
||||
}
|
||||
|
||||
if ($category = $grade_item->get_item_category()) {
|
||||
if ($category->aggregation == GRADE_AGGREGATE_SUM) {
|
||||
if ($mform->elementExists('gradetype')) {
|
||||
$mform->hardFreeze('gradetype');
|
||||
}
|
||||
if ($mform->elementExists('grademin')) {
|
||||
$mform->hardFreeze('grademin');
|
||||
}
|
||||
if ($mform->elementExists('grademax')) {
|
||||
$mform->hardFreeze('grademax');
|
||||
}
|
||||
if ($mform->elementExists('scaleid')) {
|
||||
$mform->removeElement('scaleid');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// all new items are manual, children of course category
|
||||
$mform->removeElement('plusfactor');
|
||||
|
@ -740,8 +740,8 @@ class grade_structure {
|
||||
case GRADE_AGGREGATE_WEIGHTED_MEAN:
|
||||
case GRADE_AGGREGATE_EXTRACREDIT_MEAN:
|
||||
return '<img src="'.$CFG->pixpath.'/i/agg_mean.gif" class="icon itemicon" alt="'.get_string('aggregation', 'grades').'"/>';
|
||||
//case GRADE_AGGREGATE_SUM:
|
||||
//return '<img src="'.$CFG->pixpath.'/i/agg_sum.gif" class="icon itemicon" alt="'.get_string('aggregation', 'grades').'"/>';
|
||||
case GRADE_AGGREGATE_SUM:
|
||||
return '<img src="'.$CFG->pixpath.'/i/agg_sum.gif" class="icon itemicon" alt="'.get_string('aggregation', 'grades').'"/>';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ $string['aggregateoutcomes'] = 'Include outcomes in aggregation';
|
||||
$string['aggregateoutcomeshelp'] = 'Including outcomes in aggregation may not lead to the desired overall grade, so you have the option to include or leave them out.';
|
||||
$string['aggregatesubcats'] = 'Aggregate including subcategories';
|
||||
$string['aggregatesubcatshelp'] = 'The aggregation is usually done only with immediate children, it is also possible to aggregate grades in all subcategories excluding other aggregated grades.';
|
||||
$string['aggregatesum'] = 'Sum of grades';
|
||||
$string['aggregatesonly'] = 'Aggregates only';
|
||||
$string['aggregateweightedmean'] = 'Weighted mean of grades';
|
||||
$string['aggregation'] = 'Aggregation';
|
||||
|
@ -40,6 +40,7 @@ define('GRADE_AGGREGATE_MAX', 6);
|
||||
define('GRADE_AGGREGATE_MODE', 8);
|
||||
define('GRADE_AGGREGATE_WEIGHTED_MEAN', 10);
|
||||
define('GRADE_AGGREGATE_EXTRACREDIT_MEAN', 12);
|
||||
define('GRADE_AGGREGATE_SUM', 13);
|
||||
|
||||
// grade types
|
||||
define('GRADE_TYPE_NONE', 0);
|
||||
|
@ -375,9 +375,9 @@ class grade_category extends grade_object {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and saves raw_grades in associated category grade item.
|
||||
* Generates and saves final grades in associated category grade item.
|
||||
* These immediate children must already have their own final grades.
|
||||
* The category's aggregation method is used to generate raw grades.
|
||||
* The category's aggregation method is used to generate final grades.
|
||||
*
|
||||
* Please note that category grade is either calculated or aggregated - not both at the same time.
|
||||
*
|
||||
@ -387,7 +387,7 @@ class grade_category extends grade_object {
|
||||
* Steps to follow:
|
||||
* 1. Get final grades from immediate children
|
||||
* 3. Aggregate these grades
|
||||
* 4. Save them in raw grades of associated category grade item
|
||||
* 4. Save them in final grades of associated category grade item
|
||||
*/
|
||||
function generate_grades($userid=null) {
|
||||
global $CFG;
|
||||
@ -474,6 +474,10 @@ class grade_category extends grade_object {
|
||||
}
|
||||
|
||||
if ($oldgrade) {
|
||||
if (!is_null($oldgrade->finalgrade)) {
|
||||
// we need proper floats here for !== comparison later
|
||||
$oldgrade->finalgrade = (float)$oldgrade->finalgrade;
|
||||
}
|
||||
$grade = $this->get_instance('grade_grade', $oldgrade, false);
|
||||
$grade->grade_item =& $this->grade_item;
|
||||
|
||||
@ -485,10 +489,6 @@ class grade_category extends grade_object {
|
||||
|
||||
$oldgrade = new object();
|
||||
$oldgrade->finalgrade = $grade->finalgrade;
|
||||
$oldgrade->rawgrade = $grade->rawgrade;
|
||||
$oldgrade->rawgrademin = $grade->rawgrademin;
|
||||
$oldgrade->rawgrademax = $grade->rawgrademax;
|
||||
$oldgrade->rawscaleid = $grade->rawscaleid;
|
||||
}
|
||||
|
||||
$grade->itemid = $this->grade_item->id; // For testability, avoids the need for load_grade_item()
|
||||
@ -501,15 +501,20 @@ class grade_category extends grade_object {
|
||||
// can not use own final category grade in calculation
|
||||
unset($grade_values[$this->grade_item->id]);
|
||||
|
||||
// if no grades calculation possible or grading not allowed clear both final and raw
|
||||
// if no grades calculation possible or grading not allowed clear final grade
|
||||
if (empty($grade_values) or empty($items) or ($this->grade_item->gradetype != GRADE_TYPE_VALUE and $this->grade_item->gradetype != GRADE_TYPE_SCALE)) {
|
||||
$grade->finalgrade = null;
|
||||
$grade->rawgrade = null;
|
||||
if ($grade->finalgrade !== $oldgrade->finalgrade or $grade->rawgrade !== $oldgrade->rawgrade) {
|
||||
$grade->update('system');
|
||||
if ($grade->finalgrade !== $oldgrade->finalgrade) {
|
||||
$grade->update('aggregation');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/// 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, $oldgrade, $items, $grade_values, $excluded);
|
||||
return;
|
||||
}
|
||||
/// normalize the grades first - all will have value 0...1
|
||||
// ungraded items are not used in aggregation
|
||||
foreach ($grade_values as $itemid=>$v) {
|
||||
@ -541,9 +546,8 @@ class grade_category extends grade_object {
|
||||
if (count($grade_values) == 0) {
|
||||
// not enough attempts yet
|
||||
$grade->finalgrade = null;
|
||||
$grade->rawgrade = null;
|
||||
if ($grade->finalgrade !== $oldgrade->finalgrade or $grade->rawgrade !== $oldgrade->rawgrade) {
|
||||
$grade->update('system');
|
||||
if ($grade->finalgrade !== $oldgrade->finalgrade) {
|
||||
$grade->update('aggregation');
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -551,13 +555,7 @@ class grade_category extends grade_object {
|
||||
// do the maths
|
||||
$agg_grade = $this->aggregate_values($grade_values, $items);
|
||||
|
||||
/// prepare update of new raw grade
|
||||
$grade->rawgrademin = $this->grade_item->grademin;
|
||||
$grade->rawgrademax = $this->grade_item->grademax;
|
||||
$grade->rawscaleid = $this->grade_item->scaleid;
|
||||
$grade->rawgrade = null; // categories do not use raw grades
|
||||
|
||||
// recalculate the rawgrade back to requested range
|
||||
// recalculate the grade back to requested range
|
||||
$finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $this->grade_item->grademin, $this->grade_item->grademax);
|
||||
|
||||
if (!is_null($finalgrade)) {
|
||||
@ -567,13 +565,8 @@ class grade_category extends grade_object {
|
||||
}
|
||||
|
||||
// update in db if changed
|
||||
if ( $grade->finalgrade !== $oldgrade->finalgrade
|
||||
or $grade->rawgrade !== $oldgrade->rawgrade
|
||||
or $grade->rawgrademin !== $oldgrade->rawgrademin
|
||||
or $grade->rawgrademax !== $oldgrade->rawgrademax
|
||||
or $grade->rawscaleid !== $oldgrade->rawscaleid) {
|
||||
|
||||
$grade->update('system');
|
||||
if ($grade->finalgrade !== $oldgrade->finalgrade) {
|
||||
$grade->update('aggregation');
|
||||
}
|
||||
|
||||
return;
|
||||
@ -656,6 +649,58 @@ class grade_category extends grade_object {
|
||||
|
||||
return $agg_grade;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* internal function for category grades summing
|
||||
*
|
||||
* @param int $userid
|
||||
* @param array $items
|
||||
* @param array $grade_values
|
||||
* @param float $oldgrade
|
||||
* @param bool $excluded
|
||||
* @return boolean (just plain return;)
|
||||
*/
|
||||
function sum_grades(&$grade, &$oldgrade, $items, $grade_values, $excluded) {
|
||||
// ungraded and exluded items are not used in aggregation
|
||||
foreach ($grade_values as $itemid=>$v) {
|
||||
if (is_null($v)) {
|
||||
unset($grade_values[$itemid]);
|
||||
} else if (in_array($itemid, $excluded)) {
|
||||
unset($grade_values[$itemid]);
|
||||
}
|
||||
}
|
||||
|
||||
$max = 0;
|
||||
|
||||
//find max grade
|
||||
foreach ($items as $item) {
|
||||
if ($item->gradetype != GRADE_TYPE_VALUE) {
|
||||
continue; // sum only items with value grades, no scales and outcomes!
|
||||
}
|
||||
$max += $item->grademax;
|
||||
}
|
||||
|
||||
if ($this->grade_item->grademax != $max or $this->grade_item->grademin != 0 or $this->grade_item->gradetype != GRADE_TYPE_VALUE){
|
||||
$this->grade_item->grademax = $max;
|
||||
$this->grade_item->grademin = 0;
|
||||
$this->grade_item->gradetype = GRADE_TYPE_VALUE;
|
||||
$this->grade_item->update('aggregation');
|
||||
}
|
||||
|
||||
$this->apply_limit_rules($grade_values);
|
||||
|
||||
$sum = array_sum($grade_values);
|
||||
$grade->finalgrade = bounded_number($this->grade_item->grademin, $sum, $this->grade_item->grademax);
|
||||
|
||||
// update in db if changed
|
||||
if ($grade->finalgrade !== $oldgrade->finalgrade) {
|
||||
$grade->update('aggregation');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of grade values (numerical indices), applies droplow or keephigh
|
||||
* rules to limit the final array.
|
||||
|
Loading…
x
Reference in New Issue
Block a user