]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-9506 Upgraded grade_item::adjust_grade with Darlene's more elegant formula. Compl...
authornicolasconnault <nicolasconnault>
Thu, 3 May 2007 07:10:22 +0000 (07:10 +0000)
committernicolasconnault <nicolasconnault>
Thu, 3 May 2007 07:10:22 +0000 (07:10 +0000)
lib/grade/grade_category.php
lib/grade/grade_item.php
lib/gradelib.php
lib/simpletest/testgradelib.php

index 9b34efd20476e45fb457348df4ad90bebe8855c0..341bc3f7183b602e3d894ff68bfb05e072c8aca7 100644 (file)
@@ -49,7 +49,7 @@ class grade_category extends grade_object {
      * @var int $parent 
      */
     var $parent;
-   
+
     /**
      * The number of parents this category has.
      * @var int $depth
@@ -148,8 +148,7 @@ class grade_category extends grade_object {
      * @param string $fields
      * @return object grade_category object or false if none found.
      */
-    function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*")
-    { 
+    function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") { 
         if ($grade_category = get_record('grade_categories', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
             if (isset($this) && get_class($this) == 'grade_category') {
                 foreach ($grade_category as $param => $value) {
@@ -169,7 +168,7 @@ class grade_category extends grade_object {
      * In addition to the normal insert() defined in grade_object, this method sets the depth
      * and path for this object, and update the record accordingly. The reason why this must
      * be done here instead of in the constructor, is that they both need to know the record's
-     * id number, which only gets created at insertion time.
+     * id number, which only gets created at insertion time.      
      */
     function insert() {
         $result = parent::insert();
@@ -212,33 +211,125 @@ class grade_category extends grade_object {
      * @return array Array of child objects (grade_category and grade_item).
      */
     function get_children($depth=1, $arraytype='nested') {
-        $children = array();
+        $children_array = array();
+        
+        // Set up $depth for recursion
+        $newdepth = $depth;
+        if ($depth > 1) {
+            $newdepth--;
+        }
+        
+        $childrentype = $this->get_childrentype();
 
-        if ($depth == 1) {
-            if (!empty($this->children)) {
-                return $this->children;
+        if ($childrentype == 'grade_item') {
+            $children = get_records('grade_items', 'categoryid', $this->id, 'id');
+            // No need to proceed with recursion
+            $children_array = $this->children_to_array($children, $arraytype, 'grade_item');
+            $this->children = $this->children_to_array($children, 'flat', 'grade_item');
+        } elseif ($childrentype == 'grade_category') {
+            $children = get_records('grade_categories', 'parent', $this->id, 'id');
+            if ($depth == 1) {
+                $children_array = $this->children_to_array($children, $arraytype, 'grade_category');
+                $this->children = $this->children_to_array($children, 'flat', 'grade_category');
             } else {
-                $cat = new grade_category();
-                $cat->parent = $this->id;
-                $children = $cat->fetch_all_using_this();
-                $item = new grade_item();
-                $item->categoryid = $this->id;
-                $item_children = $item->fetch_all_using_this();
-
-                if (!empty($children)) {                    
-                    $children = array_merge($children, $item_children);
-                } else {
-                    $children = $item_children;
+                foreach ($children as $id => $child) {
+                    $cat = new grade_category($child, false);
+
+                    if ($cat->has_children()) {
+                        if ($arraytype == 'nested') {
+                            $children_array[] = array('object' => $cat, 'children' => $cat->get_children($newdepth, $arraytype));
+                        } else {
+                            $children_array[] = $cat;
+                            $cat_children = $cat->get_children($newdepth, $arraytype);
+                            foreach ($cat_children as $id => $cat_child) {
+                                $children_array[] = new grade_category($cat_child, false);
+                            }
+                        }
+                    } else {
+                        if ($arraytype == 'nested') {
+                            $children_array[] = array('object' => $cat);
+                        } else {
+                            $children_array[] = $cat;
+                        }
+                    }
                 }
+            }
+        } else {
+            return null;
+        }
+
+        return $children_array;
+    }
+   
+    /**
+     * Given an array of stdClass children of a certain $object_type, returns a flat or nested
+     * array of these children, ready for appending to a tree built by get_children.
+     * @static
+     * @param array $children
+     * @param string $arraytype
+     * @param string $object_type
+     * @return array
+     */
+    function children_to_array($children, $arraytype='nested', $object_type='grade_item') {
+        $children_array = array();
+
+        foreach ($children as $id => $child) {
+            if ($arraytype == 'nested') {
+                $children_array[] = array('object' => new $object_type($child, false));
+            } else {
+                $children_array[] = new $object_type($child);
+            }
+        }        
 
-                $this->children = $children;
+        return $children_array;
+    }
+
+    /**
+     * Returns true if this category has any child grade_category or grade_item.
+     * @return int number of direct children, or false if none found.
+     */
+    function has_children() {
+        return count_records('grade_categories', 'parent', $this->id) + count_records('grade_items', 'categoryid', $this->id);
+    }
+
+    /**
+     * This method checks whether an existing child exists for this
+     * category. If the new child is of a different type, the method will return false (not allowed).
+     * Otherwise it will return true.
+     * @param object $child This must be a complete object, not a stdClass
+     * @return boolean Success or failure
+     */
+    function can_add_child($child) {
+        if ($this->has_children()) {
+            if (get_class($child) != $this->get_childrentype()) {
+                return false;
+            } else {
+                return true;
+            }
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Check the type of the first child of this category, to see whether it is a 
+     * grade_category or a grade_item, and returns that type as a string (get_class).
+     * @return string
+     */
+    function get_childrentype() {
+        $children = $this->children;
+        if (empty($this->children)) {
+            $count_item_children = count_records('grade_items', 'categoryid', $this->id);
+            $count_cat_children = count_records('grade_categories', 'parent', $this->id);
+            if ($count_item_children > 0) {
+                return 'grade_item';
+            } elseif ($count_cat_children > 0) {
+                return 'grade_category';
+            } else {
+                return null;
             }
-        } elseif ($depth > 1) {
-            // TODO implement
-        } elseif ($depth == 0) {
-            // TODO implement
         }
-        return $children;
+        return get_class($children[0]);
     }
 }
 
index 91561490e61561888e64c65241f94f4f3196b4a3..9e08e4d85e1415ed54a88263a75cddf0da7f7d65 100644 (file)
@@ -227,7 +227,6 @@ class grade_item extends grade_object {
         }
     }
     
-    
     /**
      * Returns the raw values for this grade item (as imported by module or other source).
      * @param int $userid Optional: to retrieve a single raw grade
@@ -458,33 +457,28 @@ class grade_item extends grade_object {
             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;
+            $grade_raw->grademax = count($grade_raw->scale->scale_items) - 1;
+            $this->grademax = count($this->scale->scale_items) - 1;
+            $grade_raw->grademin = 0;
+            $this->grademin = 0;
 
         } else { // Something's wrong, the raw grade has no value!?
             return false;
         }
-        // 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;
+        /**
+         * Darlene's formula
+         */
+        $factor = ($gradevalue - $grade_raw->grademin) / ($grade_raw->grademax - $grade_raw->grademin);
+        $diff = $this->grademax - $this->grademin;
+        $gradevalue = $factor * $diff + $this->grademin;
 
-        // 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
index ff1e3028a6639701ea5c0a534b23a2f3dd73d5f0..bea775fe559f5ede157612a84c42828dedc9445e 100644 (file)
@@ -36,6 +36,10 @@ define('GRADE_AGGREGATE_MEAN', 0);
 define('GRADE_AGGREGATE_MEDIAN', 1);
 define('GRADE_AGGREGATE_SUM', 2);
 define('GRADE_AGGREGATE_MODE', 3);
+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
 
 require_once($CFG->libdir . '/grade/grade_category.php');
 require_once($CFG->libdir . '/grade/grade_item.php');
index 58ba8281534891e728a3a660df78f83ca3d5ab49..650a5ed95ef0a5bac34439ff88f3e13149f6510b 100644 (file)
@@ -45,16 +45,14 @@ require_once($CFG->libdir . '/dmllib.php');
  * 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%"');
-*/
 
 /**
  * Here is a brief explanation of the test data set up in these unit tests.
- * category1 => array(grade_item1, grade_item3, category2 => array(grade_item2))
+ * category1 => array(category2 => array(grade_item1, grade_item2), category3 => array(grade_item3))
  * 3 users for 3 grade_items
  */
 class gradelib_test extends UnitTestCase {
@@ -151,6 +149,22 @@ class gradelib_test extends UnitTestCase {
         if ($grade_category->id = insert_record('grade_categories', $grade_category)) {
             $this->grade_categories[] = $grade_category;
         } 
+        
+        $grade_category = new stdClass();
+        
+        $grade_category->fullname    = 'unittestcategory3';
+        $grade_category->courseid    = $this->courseid;
+        $grade_category->aggregation = GRADE_AGGREGATE_MODE;
+        $grade_category->keephigh    = 100;
+        $grade_category->droplow     = 10;
+        $grade_category->hidden      = 0;
+        $grade_category->parent      = $this->grade_categories[0]->id;
+        $grade_category->timecreated = mktime();
+        $grade_category->timemodified = mktime();
+        
+        if ($grade_category->id = insert_record('grade_categories', $grade_category)) {
+            $this->grade_categories[] = $grade_category;
+        } 
     }
 
     /**
@@ -160,7 +174,7 @@ class gradelib_test extends UnitTestCase {
         $grade_item = new stdClass();
 
         $grade_item->courseid = $this->courseid;
-        $grade_item->categoryid = $this->grade_categories[0]->id;
+        $grade_item->categoryid = $this->grade_categories[1]->id;
         $grade_item->itemname = 'unittestgradeitem1';
         $grade_item->itemtype = 'mod';
         $grade_item->itemmodule = 'quiz';
@@ -196,7 +210,7 @@ class gradelib_test extends UnitTestCase {
         $grade_item = new stdClass();
 
         $grade_item->courseid = $this->courseid;
-        $grade_item->categoryid = $this->grade_categories[0]->id;
+        $grade_item->categoryid = $this->grade_categories[2]->id;
         $grade_item->itemname = 'unittestgradeitem3';
         $grade_item->itemtype = 'mod';
         $grade_item->itemmodule = 'forum';
@@ -569,7 +583,7 @@ class gradelib_test extends UnitTestCase {
         $grade_category->timecreated = mktime();
         $grade_category->timemodified = mktime();
         
-        $grade_category->id = grade_create_category($this->courseid, 'unittestcategory2', $this->grade_items, GRADE_AGGREGATE_MEAN);
+        $grade_category->id = grade_create_category($this->courseid, 'unittestcategory4', $this->grade_items, GRADE_AGGREGATE_MEAN);
         $last_grade_category = end($this->grade_categories);
 
         $this->assertEqual($grade_category->id, $last_grade_category->id + 1);
@@ -750,7 +764,7 @@ class gradelib_test extends UnitTestCase {
         $this->assertTrue(method_exists($grade_item, 'get_category'));
         
         $category = $grade_item->get_category();
-        $this->assertEqual($this->grade_categories[0]->fullname, $category->fullname);
+        $this->assertEqual($this->grade_categories[1]->fullname, $category->fullname);
     }
 
     /**
@@ -955,13 +969,31 @@ class gradelib_test extends UnitTestCase {
 
     function test_grade_category_get_children() {
         $category = new grade_category($this->grade_categories[0]);
-        $this->assertTrue(method_exists($category, 'get_children'));
-        
-        $this->assertEqual(3, count($category->get_children()));
-        $this->assertEqual(5, count($category->get_children(0))); 
+        $children_array = $category->get_children(0);
+        $this->assertTrue(is_array($children_array));
+        $this->assertTrue(!empty($children_array[0]));
+        $this->assertTrue(!empty($children_array[0]['object']));
+        $this->assertTrue(!empty($children_array[0]['children']));
+        $this->assertEqual($this->grade_categories[1]->id, $children_array[0]['object']->id);
+        $this->assertEqual($this->grade_categories[2]->id, $children_array[1]['object']->id);
+        $this->assertEqual($this->grade_items[0]->id, $children_array[0]['children'][0]['object']->id);
+        $this->assertEqual($this->grade_items[1]->id, $children_array[0]['children'][1]['object']->id);
+        $this->assertEqual($this->grade_items[2]->id, $children_array[1]['children'][0]['object']->id);
+
+        $children_array = $category->get_children(0, 'flat');
+        $this->assertEqual(5, count($children_array));
         
-        $category = new grade_category($this->grade_categories[1]);
-        $this->assertEqual(1, count($category->get_children())); 
+        $children_array = $category->get_children(1, 'flat');
+        $this->assertEqual(2, count($children_array));
+    }
+
+    function test_grade_category_children_to_array() {
+        $children = get_records('grade_items', 'categoryid', $this->grade_categories[1]->id);
+        $children_array = grade_category::children_to_array($children, 'nested', 'grade_item');
+        $this->assertTrue(is_array($children_array));
+        $this->assertTrue(isset($children_array[0]));
+        $this->assertTrue(isset($children_array[0]['object']));
+        $this->assertEqual($this->grade_items[0]->id, $children_array[0]['object']->id); 
     }
 
 // GRADE_CALCULATION OBJECT