MDL-9506 Finished grade_item::adjust_grade, which now also adjusts scale grades correctly. Added grade_scale object to wrap around the current non-normalized scale DB table. When/if we upgrade to grade_scales and grade_scale_items DB tables, changing the grade_scale class will be easy.

This commit is contained in:
nicolasconnault
2007-05-01 05:45:54 +00:00
parent 339e3c5375
commit d5bdb228a5
4 changed files with 162 additions and 22 deletions
+17 -2
View File
@@ -36,7 +36,7 @@ class grade_grades_raw extends grade_object {
* Array of class variables that are not part of the DB table fields
* @var array $nonfields
*/
var $nonfields = array('table', 'nonfields');
var $nonfields = array('table', 'nonfields', 'scale');
/**
* The id of the grade_item this raw grade belongs to.
@@ -79,7 +79,13 @@ class grade_grades_raw extends grade_object {
* @var int $scaleid
*/
var $scaleid;
/**
* A grade_scale object (referenced by $this->scaleid).
* @var object $scale
*/
var $scale;
/**
* The userid of the person who last modified this grade.
* @var int $usermodified
@@ -93,6 +99,10 @@ class grade_grades_raw extends grade_object {
*/
function grade_grades_raw($params=NULL, $fetch=true) {
$this->grade_object($params, $fetch);
if (!empty($this->scaleid)) {
$this->scale = new grade_scale(array('id' => $this->scaleid));
$this->scale->load_items();
}
}
@@ -138,6 +148,11 @@ class grade_grades_raw extends grade_object {
global $USER;
$oldgrade = $this->gradevalue;
$this->gradevalue = $newgrade;
// Update this scaleid if it has changed (use the largest integer (most recent))
if ($this->scale->id != $this->scaleid) {
$this->scaleid = max($this->scale->id, $this->scaleid);
}
$result = parent::update();
+50 -16
View File
@@ -40,7 +40,7 @@ class grade_item extends grade_object {
* Array of class variables that are not part of the DB table fields
* @var array $nonfields
*/
var $nonfields = array('table', 'nonfields', 'calculation', 'grade_grades_raw');
var $nonfields = array('table', 'nonfields', 'calculation', 'grade_grades_raw', 'scale');
/**
* The course this grade_item belongs to.
@@ -109,11 +109,17 @@ class grade_item extends grade_object {
var $grademin;
/**
* The scale this grade is based on, if applicable.
* id of the scale, if this grade is based on a scale.
* @var int $scaleid
*/
var $scaleid;
/**
* A grade_scale object (referenced by $this->scaleid).
* @var object $scale
*/
var $scale;
/**
* The Outcome this grade is associated with, if applicable.
* @var object $outcome
@@ -180,6 +186,19 @@ class grade_item extends grade_object {
*/
var $grade_grades_final = array();
/**
* Constructor. Extends the basic functionality defined in grade_object.
* @param array $params Can also be a standard object.
* @param boolean $fetch Wether or not to fetch the corresponding row from the DB.
*/
function grade_item($params=NULL, $fetch=true) {
$this->grade_object($params, $fetch);
if (!empty($this->scaleid)) {
$this->scale = new grade_scale(array('id' => $this->scaleid));
$this->scale->load_items();
}
}
/**
* Finds and returns a grade_item object based on 1-3 field values.
*
@@ -433,33 +452,48 @@ class grade_item extends grade_object {
* @return mixed
*/
function adjust_grade($grade_raw, $gradevalue=NULL) {
$raw_offset = 0;
$item_offset = 0;
if (!empty($grade_raw->gradevalue)) { // Dealing with numerical grade
if (empty($gradevalue)) {
$gradevalue = $grade_raw->gradevalue;
}
// Adjust both scales to 0-? and store offsets
$raw_offset = -(0 - $grade_raw->grademin);
$item_offset = -(0 - $this->grademin);
$raw_adjusted_max = $grade_raw->grademax - $raw_offset;
$item_adjusted_max = $this->grademax - $item_offset;
} elseif(!empty($grade_raw->gradescale)) { // Dealing with a scale value
if (empty($gradevalue)) {
$gradevalue = $grade_raw->gradescale;
}
$raw_adjusted_max = count($grade_raw->scale->scale_items) - 1;
$item_adjusted_max = count($this->scale->scale_items) - 1;
} else { // Something's wrong, the raw grade has no value!?
return false;
}
// Adjust both scales to 0-? and store offsets
$raw_offset = -(0 - $grade_raw->grademin);
$item_offset = -(0 - $this->grademin);
$raw_adjusted_max = $grade_raw->grademax - $raw_offset;
$item_adjusted_max = $this->grademax - $item_offset;
// Compute factor from adjusted scales
// Compute factor from grademax of adjusted scales
$factor = ($item_adjusted_max) / ($raw_adjusted_max);
// Multiply adjusted grade value (using source offset) by factor
$gradevalue = ($gradevalue - $raw_offset) * $factor;
$gradevalue += $item_offset;
// Apply factors
$gradevalue *= $this->multfactor;
$gradevalue += $this->plusfactor;
// Add target offset to resulting grade value
$gradevalue += $item_offset;
// Apply rounding or factors, depending on whether it's a scale or value
if (!empty($grade_raw->gradevalue)) {
// Apply other grade_item factors
$gradevalue *= $this->multfactor;
$gradevalue += $this->plusfactor;
} elseif (!empty($grade_raw->gradescale)) {
$gradevalue = (int) round($gradevalue);
}
return $gradevalue;
}
+1
View File
@@ -42,6 +42,7 @@ require_once($CFG->libdir . '/grade/grade_item.php');
require_once($CFG->libdir . '/grade/grade_calculation.php');
require_once($CFG->libdir . '/grade/grade_grades_raw.php');
require_once($CFG->libdir . '/grade/grade_grades_final.php');
require_once($CFG->libdir . '/grade/grade_scale.php');
/**
* Extracts from the gradebook all the grade items attached to the calling object.
+94 -4
View File
@@ -41,11 +41,14 @@ require_once($CFG->libdir . '/dmllib.php');
/**
* A cleanup of the tables is a good idea before we start, in case the last unit test
* crashed before running its tearDown method.
* crashed before running its tearDown method. Be careful because ANY record matching
* this search (%unittest%) will be deleted! Maybe a good idea to switch this off in
* production environment.
*/
delete_records_select('grade_categories', 'fullname LIKE "%unittest%"');
delete_records_select('grade_items', 'itemname LIKE "%unittest%"');
delete_records_select('grade_calculation', 'calculation LIKE "%unittest%"');
delete_records_select('scale', 'name LIKE "%unittest%"');
class gradelib_test extends UnitTestCase {
@@ -62,7 +65,8 @@ class gradelib_test extends UnitTestCase {
'grade_grades_final',
'grade_grades_text',
'grade_outcomes',
'grade_history');
'grade_history',
'scale');
var $grade_items = array();
var $grade_categories = array();
@@ -72,6 +76,7 @@ class gradelib_test extends UnitTestCase {
var $grade_grades_text = array();
var $grade_outcomes = array();
var $grade_history = array();
var $scale = array();
var $courseid = 1;
var $userid = 1;
@@ -472,6 +477,36 @@ class gradelib_test extends UnitTestCase {
}
/**
* Load scale data into the database, and adds the corresponding objects to this class' variable.
*/
function load_scale() {
$scale = new stdClass();
$scale->name = 'unittestscale1';
$scale->courseid = $this->courseid;
$scale->userid = $this->userid;
$scale->scale = 'Way off topic, Not very helpful, Fairly neutral, Fairly helpful, Supportive, Some good information, Perfect answer!';
$scale->description = 'This scale defines some of qualities that make posts helpful within the Moodle help forums.\n Your feedback will help others see how their posts are being received.';
$scale->timemodified = mktime();
if ($scale->id = insert_record('scale', $scale)) {
$this->scale[] = $scale;
}
$scale = new stdClass();
$scale->name = 'unittestscale2';
$scale->courseid = $this->courseid;
$scale->userid = $this->userid;
$scale->scale = 'Distinction, Very Good, Good, Pass, Fail';
$scale->description = 'This scale is used to mark standard assignments.';
$scale->timemodified = mktime();
if ($scale->id = insert_record('scale', $scale)) {
$this->scale[] = $scale;
}
}
/**
* TESTS BEGIN HERE
*/
@@ -537,7 +572,7 @@ class gradelib_test extends UnitTestCase {
$params->iteminstance = 4;
$params->iteminfo = 'Grade item used for unit testing';
$grade_item = new grade_item($params);
$grade_item = new grade_item($params, false);
$this->assertEqual($params->courseid, $grade_item->courseid);
$this->assertEqual($params->categoryid, $grade_item->categoryid);
@@ -752,7 +787,6 @@ class gradelib_test extends UnitTestCase {
// Try a larger maximum grade
$grade_item->grademax = 150;
$grade_item->grademin = 0;
$this->assertEqual(60, $grade_item->adjust_grade($grade_raw));
// Try larger minimum grade
@@ -791,6 +825,22 @@ class gradelib_test extends UnitTestCase {
$this->assertEqual(round(1.6), round($grade_item->adjust_grade($grade_raw)));
}
function test_grade_item_adjust_scale_grade() {
// Load raw grade and its scale
$grade_raw = new grade_grades_raw(array('scaleid' => $this->scale[0]->id));
$grade_raw->gradescale = 4;
$this->assertEqual('Fairly neutral', $grade_raw->scale->scale_items[2]);
// Load grade item and its scale
$grade_item = new grade_item(array('scaleid' => $this->scale[1]->id));
$this->assertEqual('Very Good', $grade_item->scale->scale_items[1]);
// Test grade_item::adjust_scale
$this->assertEqual(3, $grade_item->adjust_grade($grade_raw));
$grade_raw->gradescale = 6;
$this->assertEqual(4, $grade_item->adjust_grade($grade_raw));
}
// GRADE_CATEGORY OBJECT
function test_grade_category_construct() {
@@ -815,6 +865,46 @@ class gradelib_test extends UnitTestCase {
// GRADE_CALCULATION OBJECT
// SCALE OBJECT
function test_scale_constructor() {
$params = new stdClass();
$params->name = 'unittestscale3';
$params->courseid = $this->courseid;
$params->userid = $this->userid;
$params->scale = 'Distinction, Very Good, Good, Pass, Fail';
$params->description = 'This scale is used to mark standard assignments.';
$params->timemodified = mktime();
$scale = new grade_scale($params, false);
$this->assertEqual($params->name, $scale->name);
$this->assertEqual($params->scale, $scale->scale);
$this->assertEqual($params->description, $scale->description);
}
function test_scale_load_items() {
$scale = new grade_scale($this->scale[0]);
$this->assertTrue(method_exists($scale, 'load_items'));
$scale->load_items();
$this->assertEqual(7, count($scale->scale_items));
$this->assertEqual('Fairly neutral', $scale->scale_items[2]);
}
function test_scale_compact_items() {
$scale = new grade_scale($this->scale[0]);
$this->assertTrue(method_exists($scale, 'compact_items'));
$scale->load_items();
$scale->scale = null;
$scale->compact_items();
// The original string and the new string may have differences in whitespace around the delimiter, and that's OK
$this->assertEqual(preg_replace('/\s*,\s*/', ',', $this->scale[0]->scale), $scale->scale);
}
// SCENARIOS: define use cases here by defining tests and implementing code until the tests pass.
}