/**
* Applies the formula represented by this object to the value given, and returns the result.
* @param float $oldvalue
+ * @param string $valuetype Either 'gradevalue' or 'gradescale'
* @return float result
*/
- function compute($oldvalue) {
+ function compute($oldvalue, $valuetype = 'gradevalue') {
return $oldvalue; // TODO implement computation using parser
}
return $result;
}
-
+
+ /**
+ * Generates and saves raw_grades, based on this category's immediate children, then uses the
+ * associated grade_item to generate matching final grades. These immediate children must first have their own
+ * raw and final grades, which means that ultimately we must get grade_items as children. The category's aggregation
+ * method is used to generate these raw grades, which can then be used by the category's associated grade_item
+ * to apply calculations to and generate final grades.
+ */
+ function generate_grades() {
+ // Check that the children have final grades. If not, call their generate_raw_grades method (recursion)
+ if (empty($this->children)) {
+ $this->children = $this->get_children(1, 'flat');
+ }
+
+ $category_raw_grades = array();
+ $aggregated_grades = array();
+
+ foreach ($this->children as $child) {
+ if (get_class($child) == 'grade_item') {
+ $category_raw_grades[$child->id] = $child->load_final();
+ } elseif ($get_class($child) == 'grade_category') {
+ $category_raw_grades[$child->id] = $child->load_final();
+ if (empty($category_raw_grades)) {
+ $category_raw_grades[$child->id] = $child->generate_grades();
+ }
+ }
+ }
+
+ if (empty($category_raw_grades)) {
+ return null;
+ } else {
+ $aggregated_grades = $this->aggregate_grades($category_raw_grades);
+ foreach ($aggregated_grades as $raw_grade) {
+ $raw_grade->insert();
+ }
+ $this->grade_item->generate_final();
+ }
+ }
+
+ /**
+ * Given an array of arrays of grade objects (raw or final), uses this category's aggregation method to
+ * compute and return a single array of grade_raw objects with the aggregated gradevalue.
+ * @param array $raw_grade_sets
+ * @return array Raw grade objects
+ */
+ function aggregate_grades($raw_grade_sets) {
+
+ }
+
/**
* Looks at a path string (e.g. /2/45/56) and returns the depth level represented by this path (in this example, 3).
* If no string is given, it looks at the obect's path and assigns the resulting depth to its $depth variable.
/**
* The scale value of this raw grade, if such was provided by the module.
- * @var int $scalevalue
+ * @var int $gradescale
*/
- var $scalevalue;
+ var $gradescale;
/**
* The maximum allowable grade when this grade was created.
*/
function load_final() {
$grade_final_array = get_records('grade_grades_final', 'itemid', $this->id);
+
+ if (empty($grade_final_array)) {
+ $this->generate_final();
+ $grade_final_array = get_records('grade_grades_final', 'itemid', $this->id);
+ }
+
+ if (empty($grade_final_array)) {
+ return false;
+ }
+
foreach ($grade_final_array as $f) {
$this->grade_grades_final[$f->userid] = new grade_grades_final($f);
}
return $this->grade_grades_final;
}
+ /**
+ * Once the raw_grades are imported or entered, this method uses the grade_item's calculation and rules to
+ * generate final grade entries in the DB.
+ * @return array final grade objects (grade_grades_final).
+ */
+ function generate_final() {
+ if (empty($this->grade_grades_raw)) {
+ $this->load_raw();
+ }
+
+ $success = true;
+
+ foreach ($this->grade_grades_raw as $raw_grade) {
+ $final_grade = new grade_grades_final();
+ $final_grade->gradevalue = $this->adjust_grade($raw_grade, null, 'gradevalue');
+ $final_grade->gradescale = $this->adjust_grade($raw_grade, null, 'gradescale');
+ $final_grade->itemid = $this->id;
+ $final_grade->userid = $raw_grade->userid;
+ $success = $success & $final_grade->insert();
+ $this->grade_grades_final[$final_grade->userid] = $final_grade;
+ }
+
+ return $success;
+ }
+
/**
* Returns this object's calculation.
* @param boolean $fetch Whether to fetch the value from the DB or not (false == just use the object's value)
$grade_raw_array = $this->grade_grades_raw;
}
+ // The following code assumes that there is a grade_final object in DB for every
+ // grade_raw object. This assumption depends on the correct creation of grade_final entries.
+ // This also assumes that the two arrays $this->grade_grades_raw and its final counterpart are
+ // indexed by userid, not sequentially or by grade_id
+ if (count($this->grade_grades_final) != count($this->grade_grades_raw)) {
+ $this->generate_final();
+ }
+
foreach ($grade_raw_array as $userid => $raw) {
- $newgradevalue = $raw->gradevalue;
+ // the value could be gradevalue or gradescale
+ $valuetype = null;
+
+ if (!empty($raw->gradevalue)) {
+ $valuetype = 'gradevalue';
+ } elseif (!empty($raw->gradescale)) {
+ $valuetype = 'gradescale';
+ }
+
+ $newgradevalue = $raw->$valuetype;
if (!empty($this->calculation)) {
$this->upgrade_calculation_to_object();
- $newgradevalue = $this->calculation->compute($raw->gradevalue);
+ $newgradevalue = $this->calculation->compute($raw->$valuetype, $valuetype);
}
$final = $this->grade_grades_final[$userid];
- $final->gradevalue = $this->adjust_grade($raw, $newgradevalue);
+ $final->$valuetype = $this->adjust_grade($raw, $newgradevalue, $valuetype);
- if ($final->update($newgradevalue)) {
+ if ($final->update()) {
$count++;
} else {
return false;
* Given a float grade value or integer grade scale, applies a number of adjustment based on
* grade_item variables and returns the result.
* @param object $grade_raw The raw object to compare with this grade_item's rules
- * @param mixed $gradevalue The new gradevalue (after calculations are performed)
+ * @param mixed $gradevalue The new gradevalue (after calculations are performed).
+ * If null, the raw_grade's gradevalue or gradescale will be used.
+ * @param string $valuetype Either 'gradevalue' or 'gradescale'
* @return mixed
*/
- function adjust_grade($grade_raw, $gradevalue=NULL) {
+ function adjust_grade($grade_raw, $gradevalue=NULL, $valuetype='gradevalue') {
$raw_offset = 0;
$item_offset = 0;
-
- if (!empty($grade_raw->gradevalue)) { // Dealing with numerical grade
+
+ if ($valuetype == 'gradevalue') { // Dealing with numerical grade
if (empty($gradevalue)) {
$gradevalue = $grade_raw->gradevalue;
}
- } elseif(!empty($grade_raw->gradescale)) { // Dealing with a scale value
+ } elseif($valuetype == 'gradescale') { // Dealing with a scale value
if (empty($gradevalue)) {
$gradevalue = $grade_raw->gradescale;
}
$gradevalue = $factor * $diff + $this->grademin;
// Apply rounding or factors, depending on whether it's a scale or value
- if (!empty($grade_raw->gradevalue)) {
+ if ($valuetype == 'gradevalue') {
// Apply other grade_item factors
$gradevalue *= $this->multfactor;
$gradevalue += $this->plusfactor;
- } elseif (!empty($grade_raw->gradescale)) {
+ } elseif ($valuetype == 'gradescale') {
$gradevalue = (int) round($gradevalue);
}
$this->assertEqual($grade_calculation->id, $last_grade_calculation->id + 1);
$this->assertFalse(empty($grade_calculation->timecreated));
$this->assertFalse(empty($grade_calculation->timemodified));
- $this->grade_calculations[] = $grade_calculation;
}
$grade_category = new grade_category($params, false);
$grade_category->insert();
- $this->grade_categories[] = $grade_category;
- $this->grade_items[] = $grade_category->grade_item;
$this->assertEqual($params->courseid, $grade_category->courseid);
$this->assertEqual($params->fullname, $grade_category->fullname);
$this->assertEqual(1, $grade_category->depth);
$params->fullname = 'unittestcategory5';
$grade_category = new grade_category($params, false);
$grade_category->insert();
- $this->grade_categories[] = $grade_category;
- $this->grade_items[] = $grade_category->grade_item;
$this->assertEqual(2, $grade_category->depth);
$this->assertEqual("$parentpath/$grade_category->id", $grade_category->path);
$parentpath = $grade_category->path;
$params->fullname = 'unittestcategory6';
$grade_category = new grade_category($params, false);
$grade_category->insert();
- $this->grade_categories[] = $grade_category;
- $this->grade_items[] = $grade_category->grade_item;
$this->assertEqual(3, $grade_category->depth);
$this->assertEqual("$parentpath/$grade_category->id", $grade_category->path);
}
$grade_category->insert();
$last_grade_category = end($this->grade_categories);
+
+ $this->assertFalse(empty($grade_category->grade_item));
+ $this->assertEqual($grade_category->id, $grade_category->grade_item->iteminstance);
+ $this->assertEqual('category', $grade_category->grade_item->itemtype);
$this->assertEqual($grade_category->id, $last_grade_category->id + 1);
- $this->assertTrue(!empty($grade_category->timecreated));
- $this->assertTrue(!empty($grade_category->timemodified));
- $this->grade_categories[] = $grade_category;
- $this->grade_items[] = $grade_category->grade_item;
+ $this->assertFalse(empty($grade_category->timecreated));
+ $this->assertFalse(empty($grade_category->timemodified));
}
function test_grade_category_update() {
$this->assertEqual($grade_grades_final->id, $last_grade_grades_final->id + 1);
$this->assertFalse(empty($grade_grades_final->timecreated));
$this->assertFalse(empty($grade_grades_final->timemodified));
- $this->grade_grades_final[] = $grade_grades_final;
-
}
function test_grade_grades_final_update() {
$this->assertEqual($grade_history->id, $last_grade_history->id + 1);
$this->assertFalse(empty($grade_history->timecreated));
$this->assertFalse(empty($grade_history->timemodified));
- $this->grade_history[] = $grade_history;
-
}
function test_grade_history_update() {
$params = new stdClass();
$params->courseid = $this->courseid;
- $params->categoryid = $this->grade_categories[0]->id;
+ $params->categoryid = $this->grade_categories[1]->id;
$params->itemname = 'unittestgradeitem4';
$params->itemtype = 'mod';
$params->itemmodule = 'database';
- $params->iteminstance = 4;
$params->iteminfo = 'Grade item used for unit testing';
$grade_item = new grade_item($params, false);
$this->assertTrue(method_exists($grade_item, 'insert'));
$grade_item->courseid = $this->courseid;
- $grade_item->categoryid = $this->grade_categories[0]->id;
+ $grade_item->categoryid = $this->grade_categories[1]->id;
$grade_item->itemname = 'unittestgradeitem4';
$grade_item->itemtype = 'mod';
$grade_item->itemmodule = 'quiz';
- $grade_item->iteminstance = 1;
$grade_item->iteminfo = 'Grade item used for unit testing';
$grade_item->insert();
$last_grade_item = end($this->grade_items);
$this->assertEqual($grade_item->id, $last_grade_item->id + 1);
- $this->grade_items[] = $grade_item;
}
function test_grade_item_delete() {
$calculation = 'SUM([unittestgradeitem1], [unittestgradeitem3])';
$grade_item->set_calculation($calculation);
$new_calculation = $grade_item->get_calculation();
- $this->grade_calculations[] = $new_calculation;
$this->assertEqual($calculation, $new_calculation->calculation);
}
}
function test_grade_item_adjust_scale_grade() {
+ // Load grade item and its scale
+ $grade_item = new grade_item(array('scaleid' => $this->scale[1]->id), false);
+ $grade_item->insert();
+ $grade_item->load_scale();
+ $this->assertEqual('Very Good', $grade_item->scale->scale_items[1]);
+
// Load raw grade and its scale
- $grade_raw = new grade_grades_raw(array('scaleid' => $this->scale[0]->id));
+ $grade_raw = new grade_grades_raw(array('scaleid' => $this->scale[0]->id), false);
$grade_raw->gradescale = 4;
+ $grade_raw->itemid = $grade_item->id;
+ $grade_raw->userid = 1;
+ $grade_raw->insert();
$grade_raw->load_scale();
$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));
- $grade_item->load_scale();
- $this->assertEqual('Very Good', $grade_item->scale->scale_items[1]);
// Test grade_item::adjust_scale
- $this->assertEqual(3, $grade_item->adjust_grade($grade_raw));
+ $this->assertEqual(3, $grade_item->adjust_grade($grade_raw, null, 'gradescale'));
$grade_raw->gradescale = 6;
- $this->assertEqual(4, $grade_item->adjust_grade($grade_raw));
+ $this->assertEqual(4, $grade_item->adjust_grade($grade_raw, null, 'gradescale'));
+
+ // Check that the final grades have the correct values now
+ $grade_item->load_raw();
+ $grade_item->update_final_grade();
+ $this->assertFalse(empty($grade_item->grade_grades_final));
+ $this->assertEqual($grade_item->id, $grade_item->grade_grades_final[1]->itemid);
+ $this->assertEqual(3, $grade_item->grade_grades_final[1]->gradescale);
+ $this->assertEqual(1, $grade_item->grade_grades_final[1]->userid);
}
function test_grade_item_toggle_locking() {
$this->assertTrue($grade_item->grade_grades_final[2]->hidden);
$this->assertTrue($grade_item->grade_grades_final[3]->hidden);
}
+
+ function test_grade_item_generate_final() {
+ $grade_item = new grade_item();
+ $grade_item->courseid = $this->courseid;
+ $grade_item->categoryid = $this->grade_categories[1]->id;
+ $grade_item->itemname = 'unittestgradeitem4';
+ $grade_item->itemtype = 'mod';
+ $grade_item->itemmodule = 'quiz';
+ $grade_item->iteminfo = 'Grade item used for unit testing';
+
+ $grade_item->insert();
+
+ $grade_grades_raw = new grade_grades_raw();
+ $grade_grades_raw->itemid = $grade_item->id;
+ $grade_grades_raw->userid = 1;
+ $grade_grades_raw->gradevalue = 88;
+ $grade_grades_raw->grademax = 110;
+ $grade_grades_raw->grademin = 18;
+ $grade_grades_raw->insert();
+
+ $grade_grades_raw = new grade_grades_raw();
+ $grade_grades_raw->itemid = $grade_item->id;
+ $grade_grades_raw->userid = 2;
+ $grade_grades_raw->gradevalue = 68;
+ $grade_grades_raw->grademax = 110;
+ $grade_grades_raw->grademin = 18;
+ $grade_grades_raw->insert();
+
+ $grade_grades_raw = new grade_grades_raw();
+ $grade_grades_raw->itemid = $grade_item->id;
+ $grade_grades_raw->userid = 3;
+ $grade_grades_raw->gradevalue = 81;
+ $grade_grades_raw->grademax = 110;
+ $grade_grades_raw->grademin = 18;
+ $grade_grades_raw->insert();
+
+ $grade_item->load_raw();
+ $this->assertEqual(3, count($grade_item->grade_grades_raw));
+
+ $grade_item->generate_final();
+ $this->assertEqual(3, count($grade_item->grade_grades_final));
+
+ }
}
?>
$this->assertEqual($grade_outcome->id, $last_grade_outcome->id + 1);
$this->assertFalse(empty($grade_outcome->timecreated));
$this->assertFalse(empty($grade_outcome->timemodified));
- $this->grade_outcomes[] = $grade_outcome;
}
function test_grade_outcome_update() {
$this->assertEqual($grade_grades_raw->id, $last_grade_grades_raw->id + 1);
$this->assertFalse(empty($grade_grades_raw->timecreated));
$this->assertFalse(empty($grade_grades_raw->timemodified));
- $this->grade_grades_raw[] = $grade_grades_raw;
-
}
function test_grade_grades_raw_update() {
$this->assertEqual($grade_scale->id, $last_grade_scale->id + 1);
$this->assertTrue(!empty($grade_scale->timecreated));
$this->assertTrue(!empty($grade_scale->timemodified));
- $this->scale[] = $grade_scale;
-
}
function test_grade_scale_update() {
$this->assertFalse(empty($grade_grades_text->timecreated));
$this->assertFalse(empty($grade_grades_text->timemodified));
$this->assertEqual($USER->id, $grade_grades_text->usermodified);
- $this->grade_grades_text[] = $grade_grades_text;
-
}
function test_grade_grades_text_update() {