]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-9506 Lots more unit tests, and work on grade_item::update method and associated...
authornicolasconnault <nicolasconnault>
Mon, 30 Apr 2007 09:09:32 +0000 (09:09 +0000)
committernicolasconnault <nicolasconnault>
Mon, 30 Apr 2007 09:09:32 +0000 (09:09 +0000)
lib/grade/grade_calculation.php
lib/grade/grade_item.php
lib/simpletest/testgradelib.php

index f05cf0482767f8049106deffc26b9c942d8ec6e2..beb786962fb782e416977b3bd8f387173b4801bf 100644 (file)
@@ -59,7 +59,22 @@ class grade_calculation extends grade_object {
      * @var int $usermodified
      */
     var $usermodified;
+    
+    /**
+     * A formula parser object.
+     * @var object $parser
+     * @TODO implement parsing of formula and calculation MDL-9643
+     */
+    var $parser;
 
+    /**
+     * Applies the formula represented by this object to the value given, and returns the result.
+     * @param float $oldvalue
+     * @return float result
+     */
+    function compute($oldvalue) {
+        return $oldvalue; // TODO implement computation using parser
+    }
 
     /**
      * Finds and returns a grade_calculation object based on 1-3 field values.
index b46c11cc2c5fce1e9f648241e152b515387af95a..4fbc9cc94d9df5f272d0393b191b147aa4135854 100644 (file)
@@ -174,6 +174,12 @@ class grade_item extends grade_object {
      */
     var $grade_grades_raw = array();
 
+    /**
+     * Array of grade_grades_final objects linked to this grade_item. They are indexed by userid.
+     * @var array $grade_grades_final
+     */
+    var $grade_grades_final = array();
+
     /**
      * Finds and returns a grade_item object based on 1-3 field values.
      *
@@ -364,22 +370,95 @@ class grade_item extends grade_object {
      * requested. Also resets the needs_update flag once successfully performed.
      *
      * @param int $userid
-     * @param string $howmodified What caused the modification? manual/module/import/cron...
-     * @param string $note A note attached to this modification.
-     * @return boolean Success or failure
+     * @return int Number of grades updated, or false if error
      */
-    function update_final_grade($userid=NULL, $howmodified='manual', $note=NULL) {
+    function update_final_grade($userid=NULL) {
         if (empty($this->grade_grades_final)) {
             $this->load_final();
         }
+        if (empty($this->grade_grades_raw)) {
+            $this->load_raw();
+        }
         
-        // TODO implement parsing of formula and calculation MDL-9643
-        foreach ($this->grade_grades_final as $f) {
-            $newgradevalue = 0; // TODO replace '0' with calculated value
-            $f->update($newgradevalue, $howmodified, $note);
+        $count = 0;
+        
+        $grade_final_array = array();
+
+        if (!empty($userid)) {
+            $grade_final_array[$userid] = $this->grade_grades_final[$userid];
+        } else {
+            $grade_final_array = $this->grade_grades_final;
         }
 
-        return true;
+        foreach ($grade_raw_array as $userid => $raw) {
+            $newgradevalue = $raw->gradevalue;
+            
+            if (!empty($this->calculation)) {
+                $this->upgrade_calculation_to_object();
+                $newgradevalue = $this->calculation->compute($raw->gradevalue);
+            }
+            
+            $final = $this->grade_grades_final[$userid];
+
+            $final->gradevalue = $this->adjust_grade($raw, $newgradevalue);
+            if ($final->update($newgradevalue)) {
+                $count++;
+            } else {
+                return false;
+            }
+        }
+
+        return $count;
+    }
+
+    /**
+     * Use this when the calculation object is a stdClass (rare) and you need it to have full
+     * object status (with methods and all).
+     */
+    function upgrade_calculation_to_object() {
+        if (!is_a($this->calculation, 'grade_calculation')) {
+            $this->calculation = new grade_calculation($this->calculation, 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)
+     * @return mixed 
+     */
+    function adjust_grade($grade_raw, $gradevalue=NULL) {
+        if (!empty($grade_raw->gradevalue)) { // Dealing with numerical grade
+            if (empty($gradevalue)) {
+                $gradevalue = $grade_raw->gradevalue;
+            }
+        } elseif(!empty($grade_raw->gradescale)) { // Dealing with a scale value
+            if (empty($gradevalue)) {
+                $gradevalue = $grade_raw->gradescale;
+            }
+
+        } else { // Something's wrong, the raw grade has no value!?
+
+        }
+        
+        $raw_diff = $grade_raw->grademax - $grade_raw->grademin;
+        $item_diff = $this->grademax - $this->grademin;
+        $min_diff = $grade_raw->grademin - $this->grademin;
+
+        $diff_factor = max($raw_diff, $item_diff) / min($raw_diff, $item_diff);
+        
+        if ($raw_diff > $item_diff) {
+            $gradevalue = $gradevalue / $diff_factor;
+        } else {
+            $gradevalue = $gradevalue * $diff_factor;
+        }
+
+        // Apply factors
+        $gradevalue *= $this->multfactor;
+        $gradevalue += $this->plusfactor;
+
+        return $gradevalue;
     }
 }
 ?>
index e554f8cef6c9db614226007cfb171d4a845a27e6..73d8401fc7a338b933650f81e489bf1a5f5cbd87 100644 (file)
@@ -695,6 +695,67 @@ class gradelib_test extends UnitTestCase {
         $this->assertEqual($this->grade_categories[0]->fullname, $category->fullname);
     }
 
+    /**
+     * Test update of all final grades
+     */
+    function test_grade_item_update_final_grades() {
+        $grade_item = new grade_item($this->grade_items[0]);
+        $this->assertTrue(method_exists($grade_item, 'update_final_grade'));
+        $this->assertEqual(3, $grade_item->update_final_grade()); 
+        $this->assertEqual(1, $grade_item->update_final_grade(1)); 
+    }
+
+    /**
+     * Test loading of raw and final items into grade_item.
+     */
+    function test_grade_item_load() {
+        $grade_item = new grade_item($this->grade_items[0]);
+        $this->assertTrue(method_exists($grade_item, 'load_final'));
+        $this->assertTrue(method_exists($grade_item, 'load_raw'));
+
+        // Check that final and raw items are not yet loaded
+        $this->assertTrue(empty($grade_item->grade_grades_final));
+        $this->assertTrue(empty($grade_item->grade_grades_raw));
+        
+        // Load raw and final grades
+        $grade_item->load_final();
+        $grade_item->load_raw();
+        
+        // Check that final and raw grades are now loaded
+        $this->assertFalse(empty($grade_item->grade_grades_final));
+        $this->assertFalse(empty($grade_item->grade_grades_raw));
+        $this->assertEqual($this->grade_grades_final[0]->gradevalue, $grade_item->grade_grades_final[1]->gradevalue);
+        $this->assertEqual($this->grade_grades_raw[0]->gradevalue, $grade_item->grade_grades_raw[1]->gradevalue);
+    }
+    
+    /**
+     * Test the adjust_grade method
+     */
+    function test_grade_item_adjust_grade() {
+        $grade_item = new grade_item($this->grade_items[0]);
+        $this->assertTrue(method_exists($grade_item, 'adjust_grade'));
+        $grade_raw = new stdClass();
+        $grade_raw->gradevalue = 40;
+        $grade_raw->grademax = 100;
+        $grade_raw->grademin = 0;
+        $grade_item->multfactor = 1;
+        $grade_item->plusfactor = 0;
+        $grade_item->grademax = 50;
+        $grade_item->grademin = 0;
+
+        $this->assertEqual(20, $grade_item->adjust_grade($grade_raw)); 
+
+        $grade_item->grademax = 150;
+        $grade_item->grademin = 0;
+
+        $this->assertEqual(60, $grade_item->adjust_grade($grade_raw)); 
+
+        $grade_item->grademax = 150;
+        $grade_item->grademin = 50;
+
+        $this->assertEqual(40, $grade_item->adjust_grade($grade_raw)); 
+    }
+
 // GRADE_CATEGORY OBJECT
 
     function test_grade_category_construct() {