From: skodak Date: Sat, 21 Jul 2007 10:09:57 +0000 (+0000) Subject: aggregation improvements; fixed aggregation of course category when changing type... X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=eacd3700f4665e25aec873bc130be9c5a65bbf9c;p=moodle.git aggregation improvements; fixed aggregation of course category when changing type; old gradebook upgrade wip (untested) --- diff --git a/grade/edit/category_form.php b/grade/edit/category_form.php index 2ceaac302f..0b0890ca0f 100644 --- a/grade/edit/category_form.php +++ b/grade/edit/category_form.php @@ -13,10 +13,14 @@ class edit_category_form extends moodleform { $options = array(GRADE_AGGREGATE_MEAN_ALL =>get_string('aggregatemeanall', 'grades'), GRADE_AGGREGATE_MEAN_GRADED =>get_string('aggregatemeangraded', '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_MEDIAN_ALL =>get_string('aggregatemedianall', 'grades'), + GRADE_AGGREGATE_MEDIAN_GRADED =>get_string('aggregatemediangraded', 'grades'), + GRADE_AGGREGATE_MIN_ALL =>get_string('aggregateminall', 'grades'), + GRADE_AGGREGATE_MIN_GRADED =>get_string('aggregatemingraded', 'grades'), + GRADE_AGGREGATE_MAX_ALL =>get_string('aggregatemaxall', 'grades'), + GRADE_AGGREGATE_MAX_GRADED =>get_string('aggregatemaxgraded', 'grades'), + GRADE_AGGREGATE_MODE_ALL =>get_string('aggregatemodeall', 'grades'), + GRADE_AGGREGATE_MODE_GRADED =>get_string('aggregatemodegraded', 'grades'), GRADE_AGGREGATE_WEIGHTED_MEAN_ALL =>get_string('aggregateweightedmeanall', 'grades'), GRADE_AGGREGATE_WEIGHTED_MEAN_GRADED =>get_string('aggregateweightedmeangraded', 'grades'), GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL =>get_string('aggregateextracreditmeanall', 'grades'), diff --git a/lang/en_utf8/grades.php b/lang/en_utf8/grades.php index b8b541fcd9..a3bba880ea 100644 --- a/lang/en_utf8/grades.php +++ b/lang/en_utf8/grades.php @@ -10,11 +10,15 @@ $string['additem'] = 'Add Grade Item'; $string['aggregateextracreditmeanall'] = 'Mean of all grades (extra credits)'; $string['aggregateextracreditmeangraded'] = 'Mean of non-empty grades (extra credits)'; $string['aggregatemeanall'] = 'Mean of all grades'; -$string['aggregatemedian'] = 'Median of non-empty grades'; $string['aggregatemeangraded'] = 'Mean of non-empty grades'; -$string['aggregatemin'] = 'Smallest grade'; -$string['aggregatemax'] = 'Highest grade'; -$string['aggregatemode'] = 'Mode of non-empty grades'; +$string['aggregatemedianall'] = 'Median of all grades'; +$string['aggregatemediangraded'] = 'Median of non-empty grades'; +$string['aggregateminall'] = 'Smallest grade of all grades'; +$string['aggregatemingraded'] = 'Smallest grade of non-empty grades'; +$string['aggregatemaxall'] = 'Highest grade of all grades'; +$string['aggregatemaxgraded'] = 'Highest grade of non-empty grades'; +$string['aggregatemodeall'] = 'Mode of non-empty grades of all grades'; +$string['aggregatemodegraded'] = 'Mode of non-empty grades'; $string['aggregateweightedmeanall'] = 'Weighted mean of all grades'; $string['aggregateweightedmeangraded'] = 'Weighted mean of non-empty grades'; $string['aggregation'] = 'Aggregation'; diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php index 436b44266b..80b096bf48 100644 --- a/lib/grade/grade_category.php +++ b/lib/grade/grade_category.php @@ -433,7 +433,24 @@ class grade_category extends grade_object { $grade_values[$k] = grade_grade::standardise_score($v, $items[$k]->grademin, $items[$k]->grademax, 0, 1); } - //limit and sort + // use min grade if grade missing for these types + switch ($this->aggregation) { + case GRADE_AGGREGATE_MEAN_ALL: + case GRADE_AGGREGATE_MEDIAN_ALL: + case GRADE_AGGREGATE_MIN_ALL: + case GRADE_AGGREGATE_MAX_ALL: + case GRADE_AGGREGATE_MODE_ALL: + case GRADE_AGGREGATE_WEIGHTED_MEAN_ALL: + case GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL: + foreach($items as $itemid=>$value) { + if (!isset($grade_values[$itemid])) { + $grade_values[$itemid] = 0; + } + } + break; + } + + // limit and sort $this->apply_limit_rules($grade_values); asort($grade_values, SORT_NUMERIC); @@ -450,7 +467,8 @@ class grade_category extends grade_object { /// start the aggregation switch ($this->aggregation) { - case GRADE_AGGREGATE_MEDIAN: // Middle point value in the set: ignores frequencies + case GRADE_AGGREGATE_MEDIAN_ALL: // Middle point value in the set: ignores frequencies + case GRADE_AGGREGATE_MEDIAN_GRADED: $num = count($grade_values); $grades = array_values($grade_values); if ($num % 2 == 0) { @@ -460,15 +478,18 @@ class grade_category extends grade_object { } break; - case GRADE_AGGREGATE_MIN: + case GRADE_AGGREGATE_MIN_ALL: + case GRADE_AGGREGATE_MIN_GRADED: $rawgrade = reset($grade_values); break; - case GRADE_AGGREGATE_MAX: + case GRADE_AGGREGATE_MAX_ALL: + case GRADE_AGGREGATE_MAX_GRADED: $rawgrade = array_pop($grade_values); break; - case GRADE_AGGREGATE_MODE: // the most common value, the highest one if multimode + case GRADE_AGGREGATE_MODE_ALL: // the most common value, average used if multimode + case GRADE_AGGREGATE_MODE_GRADED: $freq = array_count_values($grade_values); arsort($freq); // sort by frequency keeping keys $top = reset($freq); // highest frequency count @@ -477,33 +498,16 @@ class grade_category extends grade_object { $rawgrade = reset($modes); break; - case GRADE_AGGREGATE_WEIGHTED_MEAN_ALL: // Weighted average of all possible final grades - $weightsum = 0; - $sum = 0; - foreach($items as $key=>$value) { - $grade_value = isset($grade_values[$key]) ? $grade_values[$key] : 0; - if ($items[$key]->aggregationcoef <= 0) { - continue; - } - $weightsum += $items[$key]->aggregationcoef; - $sum += $items[$key]->aggregationcoef * $grade_value; - } - if ($weightsum == 0) { - $rawgrade = null; - } else { - $rawgrade = $sum / $weightsum; - } - break; - case GRADE_AGGREGATE_WEIGHTED_MEAN_GRADED: // Weighted average of all existing final grades + case GRADE_AGGREGATE_WEIGHTED_MEAN_ALL: $weightsum = 0; $sum = 0; - foreach($grade_values as $key=>$grade_value) { - if ($items[$key]->aggregationcoef <= 0) { + foreach($grade_values as $itemid=>$grade_value) { + if ($items[$itemid]->aggregationcoef <= 0) { continue; } - $weightsum += $items[$key]->aggregationcoef; - $sum += $items[$key]->aggregationcoef * $grade_value; + $weightsum += $items[$itemid]->aggregationcoef; + $sum += $items[$itemid]->aggregationcoef * $grade_value; } if ($weightsum == 0) { $rawgrade = null; @@ -513,33 +517,15 @@ class grade_category extends grade_object { break; case GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL: // special average + case GRADE_AGGREGATE_EXTRACREDIT_MEAN_GRADED: $num = 0; $sum = 0; - foreach($items as $key=>$value) { - $grade_value = isset($grade_values[$key]) ? $grade_values[$key] : 0; - if ($items[$key]->aggregationcoef == 0) { + foreach($grade_values as $itemid=>$grade_value) { + if ($items[$itemid]->aggregationcoef == 0) { $num += 1; $sum += $grade_value; - } else if ($items[$key]->aggregationcoef > 0) { - $sum += $items[$key]->aggregationcoef * $grade_value; - } - } - if ($num == 0) { - $rawgrade = $sum; // only extra credits or wrong coefs - } else { - $rawgrade = $sum / $num; - } - break; - - case GRADE_AGGREGATE_EXTRACREDIT_MEAN_GRADED: // special average - $num = 0; - $sum = 0; - foreach($grade_values as $key=>$grade_value) { - if ($items[$key]->aggregationcoef == 0) { - $num += 1; - $sum += $grade_value; - } else if ($items[$key]->aggregationcoef > 0) { - $sum += $items[$key]->aggregationcoef * $grade_value; + } else if ($items[$itemid]->aggregationcoef > 0) { + $sum += $items[$itemid]->aggregationcoef * $grade_value; } } if ($num == 0) { @@ -550,11 +536,6 @@ class grade_category extends grade_object { break; case GRADE_AGGREGATE_MEAN_ALL: // Arithmetic average of all grade items including even NULLs; NULL grade counted as minimum - $num = count($items); // you can calculate sum from this one if you multiply it with count($this->depends_on() ;-) - $sum = array_sum($grade_values); - $rawgrade = $sum / $num; - break; - case GRADE_AGGREGATE_MEAN_GRADED: // Arithmetic average of all final grades, unfinished are not calculated default: $num = count($grade_values); diff --git a/lib/gradelib.php b/lib/gradelib.php index e387db67ba..3e4b6dfbea 100644 --- a/lib/gradelib.php +++ b/lib/gradelib.php @@ -32,31 +32,29 @@ * @package moodlecore */ +// category aggregation types define('GRADE_AGGREGATE_MEAN_ALL', 0); define('GRADE_AGGREGATE_MEAN_GRADED', 1); -define('GRADE_AGGREGATE_MEDIAN', 2); -define('GRADE_AGGREGATE_MIN', 3); -define('GRADE_AGGREGATE_MAX', 4); -define('GRADE_AGGREGATE_MODE', 5); -define('GRADE_AGGREGATE_WEIGHTED_MEAN_ALL', 6); -define('GRADE_AGGREGATE_WEIGHTED_MEAN_GRADED', 7); -define('GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL', 8); -define('GRADE_AGGREGATE_EXTRACREDIT_MEAN_GRADED', 9); - -define('GRADE_CHILDTYPE_ITEM', 0); -define('GRADE_CHILDTYPE_CAT', 1); - -define('GRADE_ITEM', 0); // Used to compare class names with CHILDTYPE values -define('GRADE_CATEGORY', 1); // Used to compare class names with CHILDTYPE values - -define('GRADE_CATEGORY_CONTRACTED', 0); // The state of a category header in the grader report -define('GRADE_CATEGORY_EXPANDED', 1); // The state of a category header in the grader report - +define('GRADE_AGGREGATE_MEDIAN_ALL', 2); +define('GRADE_AGGREGATE_MEDIAN_GRADED', 3); +define('GRADE_AGGREGATE_MIN_ALL', 4); +define('GRADE_AGGREGATE_MIN_GRADED', 5); +define('GRADE_AGGREGATE_MAX_ALL', 6); +define('GRADE_AGGREGATE_MAX_GRADED', 7); +define('GRADE_AGGREGATE_MODE_ALL', 8); +define('GRADE_AGGREGATE_MODE_GRADED', 9); +define('GRADE_AGGREGATE_WEIGHTED_MEAN_ALL', 10); +define('GRADE_AGGREGATE_WEIGHTED_MEAN_GRADED', 11); +define('GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL', 12); +define('GRADE_AGGREGATE_EXTRACREDIT_MEAN_GRADED', 13); + +// grade types define('GRADE_TYPE_NONE', 0); define('GRADE_TYPE_VALUE', 1); define('GRADE_TYPE_SCALE', 2); define('GRADE_TYPE_TEXT', 3); +// grade_update() return status define('GRADE_UPDATE_OK', 0); define('GRADE_UPDATE_FAILED', 1); define('GRADE_UPDATE_MULTIPLE', 2); @@ -68,11 +66,10 @@ define('GRADE_HISTORY_INSERT', 1); define('GRADE_HISTORY_UPDATE', 2); define('GRADE_HISTORY_DELETE', 3); -// Common directories -define('GRADE_EDIT_DIR', $CFG->dirroot . '/grade/edit'); -define('GRADE_EDIT_URL', $CFG->wwwroot . '/grade/edit'); - // Grader reports +define('GRADE_CATEGORY_CONTRACTED', 0); // The state of a category header in the grader report +define('GRADE_CATEGORY_EXPANDED', 1); // The state of a category header in the grader report + define('GRADE_REPORT_AGGREGATION_POSITION_LEFT', 0); define('GRADE_REPORT_AGGREGATION_POSITION_RIGHT', 1); define('GRADE_REPORT_AGGREGATION_VIEW_FULL', 0); @@ -84,6 +81,10 @@ define('GRADE_REPORT_PREFERENCE_DEFAULT', 'default'); define('GRADE_REPORT_PREFERENCE_INHERIT', 'inherit'); define('GRADE_REPORT_PREFERENCE_UNUSED', -1); +// Common directories +define('GRADE_EDIT_DIR', $CFG->dirroot . '/grade/edit'); +define('GRADE_EDIT_URL', $CFG->wwwroot . '/grade/edit'); + require_once($CFG->libdir . '/grade/grade_category.php'); require_once($CFG->libdir . '/grade/grade_item.php'); require_once($CFG->libdir . '/grade/grade_grade.php'); @@ -351,7 +352,7 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null) if (!empty($updated_item) and $updated_item->id == $gid) { $grade_items[$gid]->needsupdate = 1; - } else if ($grade_items[$gid]->is_course_item() or $grade_items[$gid]->is_category_item() or $grade_items[$gid]->is_calculated()) { + } else if ($gitem->is_course_item() or $gitem->is_category_item() or $gitem->is_calculated()) { $grade_items[$gid]->needsupdate = 1; } @@ -362,6 +363,7 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null) $errors = array(); $finalids = array(); $gids = array_keys($grade_items); + $failed = 0; while (count($finalids) < count($gids)) { // work until all grades are final or error found $count = 0; @@ -399,6 +401,12 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null) } if ($count == 0) { + $failed++; + } else { + $failed = 0; + } + + if ($failed > 1) { foreach($gids as $gid) { if (in_array($gid, $finalids)) { continue; // this one is ok @@ -661,35 +669,54 @@ function grade_get_legacy_grade_item($modinstance, $grademax, $scaleid) { /** * This function is used to migrade old date and settings from old gradebook into new grading system. - * - * TODO: - * - category weight not used - we would have to create extra top course grade calculated category - * - exta_credit item flag not used - does not fit all our aggregation types, could be used in SUM only + * @param int $courseid */ -function grade_oldgradebook_upgrade($courseid) { +function grade_upgrade_oldgradebook($courseid) { global $CFG; + // regrade everything + grade_force_full_regrading($courseid); + + // course grade data + $course_category = grade_category::fetch_course_category($courseid); + $course_item = $course_category->get_grade_item(); + + // first create all categories if needed $categories = array(); - if ($oldcats = get_records('grade_category', 'courseid', $courseid)) { + $oldcats = get_records('grade_category', 'courseid', $courseid, 'id'); + + if (empty($oldcats) or count($oldcats) == 1) { + $course_category->aggregation = GRADE_AGGREGATE_MEAN_ALL; + $course_category->update('upgrade'); + if ($oldcats) { + $oldcat = reset($oldcats); + $categories[$oldcat->id] =& $course_category; + } + + } else { foreach ($oldcats as $oldcat) { $newcat = new grade_category(array('courseid'=>$courseid, 'fullname'=>$oldcat->name)); $newcat->droplow = $oldcat->drop_x_lowest; - $newcat->aggregation = GRADE_AGGREGATE_MEAN_GRADED; + $newcat->aggregation = GRADE_AGGREGATE_MEAN_ALL; if (empty($newcat->id)) { - $newcat->insert(); + $newcat->insert('upgrade'); } else { - $newcat->update(); + $newcat->update('upgrade'); } - $categories[$oldcat->id] = $newcat; + $categories[$oldcat->id] =& $newcat; $catitem = $newcat->get_grade_item(); - $catitem->gradetype = GRADE_TYPE_VALUE; - $catitem->plusfactor = $oldcat->bonus_points; - $catitem->hidden = $oldcat->hidden; - $catitem->update(); + $catitem->gradetype = GRADE_TYPE_VALUE; + $catitem->plusfactor = $oldcat->bonus_points; + $catitem->hidden = $oldcat->hidden; + $catitem->aggregationcoef = $oldcat->weight; + $catitem->update('upgrade'); } + + $course_category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN_ALL; + $course_category->update('upgrade'); } // get all grade items with mod details @@ -701,19 +728,27 @@ function grade_oldgradebook_upgrade($courseid) { if ($olditems = get_records_sql($sql)) { foreach ($olditems as $olditem) { $newitem = new grade_item(array('courseid'=>$olditem->courseid, 'itemtype'=>'mod', 'itemmodule'=>$olditem->modname, 'iteminstance'=>$olditem->cminstance, 'itemnumber'=>0)); - if (!empty($olditem->category)) { - // we do this low level stuff to get some speedup during upgrade - $newitem->set_parent($categories[$olditem->category]->id); + $newitem->multfactor = $olditem->scale_grade; + $newitem->aggregationcoef = $olditem->extra_credit; + if ($olditem->extra_credit and $categories[$olditem->category]->aggregation != GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL) { + $categories[$olditem->category]->aggregation = GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL; + $categories[$olditem->category]->update('upgrade'); } - $newitem->gradetype = GRADE_TYPE_NONE; - $newitem->multfactor = $olditem->scale_grade; + if (empty($newitem->id)) { - $newitem->insert(); + $newitem->gradetype = GRADE_TYPE_NONE; // type not known yet + $newitem->insert('upgrade'); } else { - $newitem->update(); + $newitem->update('upgrade'); + } + + if (!empty($olditem->category)) { + $newitem->set_parent($categories[$olditem->category]->id); } } } + + // setup up exception handling } /**