]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-9137 added new aggregation needed for upgrade - weighted + extra credit
authorskodak <skodak>
Wed, 18 Jul 2007 19:29:32 +0000 (19:29 +0000)
committerskodak <skodak>
Wed, 18 Jul 2007 19:29:32 +0000 (19:29 +0000)
minor item edit form cleanup
fixed minor bug in grader/lib.php

grade/edit/category_form.php
grade/edit/item.php
grade/edit/item_form.php
grade/report/grader/lib.php
lib/grade/grade_category.php
lib/grade/grade_grades.php
lib/grade/grade_item.php
lib/gradelib.php

index f82aa0e303e4f5aa45bbe22c86c9b4cc8039a1a5..01597f132116ced4cd397af2a408c46c38db8688 100644 (file)
@@ -12,11 +12,16 @@ class edit_category_form extends moodleform {
         $mform->addElement('text', 'fullname', get_string('categoryname', 'grades'));
 
         $options = array(GRADE_AGGREGATE_MEAN_ALL   =>get_string('aggregatemeanall', 'grades'),
-                         GRADE_AGGREGATE_MEDIAN     =>get_string('aggregatemedian', '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_MODE       =>get_string('aggregatemode', 'grades'),
+                         GRADE_AGGREGATE_WEIGHTED_MEAN_ALL      =>get_string('aggregateweightedmeanall', 'grades'),
+                         GRADE_AGGREGATE_WEIGHTED_MEAN_GRADED   =>get_string('aggregateweightedgraded', 'grades'),
+                         GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL   =>get_string('aggregateextracreditmeanall', 'grades'),
+                         GRADE_AGGREGATE_EXTRACREDIT_MEAN_GRADED=>get_string('aggregateextracreditmeangraded', 'grades'));
+
         $mform->addElement('select', 'aggregation', get_string('aggregation', 'grades'), $options);
         $mform->setDefault('gradetype', GRADE_AGGREGATE_MEAN_ALL);
 
index b7ca41d1ac1278353fdcad5569d868e1e2b2f7fe..15796c884768cfac65415afc85b9d853d56ce8b6 100644 (file)
@@ -34,10 +34,6 @@ if ($item = get_record('grade_items', 'id', $id, 'courseid', $course->id)) {
 
     $item->calculation = grade_item::denormalize_formula($item->calculation, $course->id);
     $mform->set_data($item);
-
-} else {
-    // defaults for new items
-    $mform->set_data(array('courseid'=>$course->id, 'itemtype'=>'manual'));
 }
 
 if ($data = $mform->get_data()) {
@@ -69,7 +65,7 @@ if ($data = $mform->get_data()) {
         }
     }
 
-    redirect($returnurl, 'temporary debug delay', 50);
+    redirect($returnurl, 'temporary debug delay', 5);
 }
 
 $strgrades       = get_string('grades');
index 80e8635313732a8f45237324b86931b3a02161e7..9a588353d984b7402d28ff25c3da0ef4dfbc6aa4 100644 (file)
@@ -46,26 +46,29 @@ class edit_item_form extends moodleform {
 
         $mform->addElement('text', 'grademax', get_string('grademax', 'grades'));
         $mform->disabledIf('grademax', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
-        $mform->setDefault('grademax', 100);
+        $mform->setDefault('grademax', 100.0);
 
         $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
         $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
-        $mform->setDefault('grademin', 0);
+        $mform->setDefault('grademin', 0.0);
 
         $mform->addElement('text', 'gradepass', get_string('gradepass', 'grades'));
         $mform->disabledIf('gradepass', 'gradetype', 'eq', GRADE_TYPE_NONE);
         $mform->disabledIf('gradepass', 'gradetype', 'eq', GRADE_TYPE_TEXT);
-        $mform->setDefault('gradepass', 0);
+        $mform->setDefault('gradepass', 0.0);
 
         $mform->addElement('text', 'multfactor', get_string('multfactor', 'grades'));
         $mform->disabledIf('multfactor', 'gradetype', 'eq', GRADE_TYPE_NONE);
         $mform->disabledIf('multfactor', 'gradetype', 'eq', GRADE_TYPE_TEXT);
-        $mform->setDefault('multfactor', 1);
+        $mform->setDefault('multfactor', 1.0);
 
         $mform->addElement('text', 'plusfactor', get_string('plusfactor', 'grades'));
         $mform->disabledIf('plusfactor', 'gradetype', 'eq', GRADE_TYPE_NONE);
         $mform->disabledIf('plusfactor', 'gradetype', 'eq', GRADE_TYPE_TEXT);
-        $mform->setDefault('plusfactor', 0);
+        $mform->setDefault('plusfactor', 0.0);
+
+        $mform->addElement('text', 'aggregationcoef', get_string('aggregationcoef', 'grades'));
+        $mform->setDefault('aggregationcoef', 0.0);
 
         $mform->addElement('advcheckbox', 'locked', get_string('locked', 'grades'));
 
@@ -97,10 +100,10 @@ class edit_item_form extends moodleform {
         $mform->addElement('hidden', 'id', 0);
         $mform->setType('id', PARAM_INT);
 
-        $mform->addElement('hidden', 'courseid', 0);
+        $mform->addElement('hidden', 'courseid', $COURSE->id);
         $mform->setType('courseid', PARAM_INT);
 
-        $mform->addElement('hidden', 'itemtype', 0);
+        $mform->addElement('hidden', 'itemtype', 'manual'); // all new items are manual only
         $mform->setType('itemtype', PARAM_ALPHA);
 
 /// add return tracking info
@@ -115,19 +118,51 @@ class edit_item_form extends moodleform {
 
 /// tweak the form - depending on existing data
     function definition_after_data() {
-        global $CFG;
+        global $CFG, $COURSE;
 
         $mform =& $this->_form;
 
         if ($id = $mform->getElementValue('id')) {
             $grade_item = grade_item::fetch(array('id'=>$id));
+
             if ($grade_item->is_normal_item()) {
                 // following items are set up from modules and should not be overrided by user
-                $mform->hardFreeze('itemname,idnumber,calculation,gradetype,grademax,grademin,scaleid');
-            }
-            if ($grade_item->is_manual_item()) {
+                $mform->hardFreeze('itemname,idnumber,gradetype,grademax,grademin,scaleid');
+                $mform->removeElement('calculation');
+
+            } else if ($grade_item->is_manual_item()) {
                 // manual grade item does not use these - uses only final grades
-                $mform->hardFreeze('plusfactor,multfactor');
+                $mform->removeElement('plusfactor');
+                $mform->removeElement('multfactor');
+
+            }
+
+            //remove the aggregation coef element if not needed
+            if ($grade_item->is_course_item()) {
+                $mform->removeElement('aggregationcoef');
+
+            } else if ($grade_item->is_category_item()) {
+                $category = $grade_item->get_item_category();
+                $parent_category = $category->get_parent_category();
+                if (!$parent_category->is_aggregationcoef_used()) {
+                    $mform->removeElement('aggregationcoef');
+                }
+
+            } else {
+                $parent_category = $grade_item->get_parent_category();
+                if (!$parent_category->is_aggregationcoef_used()) {
+                    $mform->removeElement('aggregationcoef');
+                }
+            }
+
+        } else {
+            // all new items are manual, children of course category
+            $mform->removeElement('plusfactor');
+            $mform->removeElement('multfactor');
+
+            $course_category = grade_category::fetch_course_category($COURSE->id);
+            if (!$course_category->is_aggregationcoef_used()) {
+                $mform->removeElement('aggregationcoef');
             }
         }
     }
index c92e70bda8d436b8235449827347b2e3807ebfb6..63eebe7482e49b21eb4415740581b5c011c0456c 100644 (file)
@@ -708,8 +708,8 @@ class grade_report_grader extends grade_report {
                     $gradedisplaytype = $this->get_pref('gradedisplaytype', $item->id);
 
                     $percentsign = '';
-                    $grademin = $this->finalgrades[$userid][$item->id]->grademin;
-                    $grademax = $this->finalgrades[$userid][$item->id]->grademax;
+                    $grademin = $item->grademin;
+                    $grademax = $item->grademax;
 
                     if ($gradedisplaytype == GRADE_REPORT_GRADE_DISPLAY_TYPE_PERCENTAGE) {
                         if (!is_null($gradeval)) {
index 30a0fde2c97fce72a3bca8adbd36e094cc264db2..b01fc8b909e5c95334c0dcfcba93f59fde5554fa 100644 (file)
@@ -352,25 +352,25 @@ class grade_category extends grade_object {
                  WHERE gi.id = g.itemid AND gi.id IN ($gis) $usersql
               ORDER BY g.userid";
 
-        // group the results by userid and aggregate the grades in this group
+        // group the results by userid and aggregate the grades for this user
         if ($rs = get_recordset_sql($sql)) {
             if ($rs->RecordCount() > 0) {
                 $prevuser = 0;
-                $grade_records = array();
-                $oldgrade      = null;
+                $grade_values = array();
+                $oldgrade     = null;
                 while ($used = rs_fetch_next_record($rs)) {
                     if ($used->userid != $prevuser) {
-                        $this->aggregate_grades($prevuser, $items, $grade_records, $oldgrade);
+                        $this->aggregate_grades($prevuser, $items, $grade_values, $oldgrade);
                         $prevuser = $used->userid;
-                        $grade_records = array();
-                        $oldgrade      = null;
+                        $grade_values = array();
+                        $oldgrade     = null;
                     }
-                    $grade_records[$used->itemid] = $used->finalgrade;
+                    $grade_values[$used->itemid] = $used->finalgrade;
                     if ($this->grade_item->id == $used->itemid) {
                         $oldgrade = $used;
                     }
                 }
-                $this->aggregate_grades($prevuser, $items, $grade_records, $oldgrade);//the last one
+                $this->aggregate_grades($prevuser, $items, $grade_values, $oldgrade);//the last one
             }
         }
 
@@ -380,7 +380,7 @@ class grade_category extends grade_object {
     /**
      * internal function for category grades aggregation
      */
-    function aggregate_grades($userid, $items, $grade_records, $oldgrade) {
+    function aggregate_grades($userid, $items, $grade_values, $oldgrade) {
         if (empty($userid)) {
             //ignore first call
             return;
@@ -410,10 +410,10 @@ class grade_category extends grade_object {
         }
 
         // can not use own final category grade in calculation
-        unset($grade_records[$this->grade_item->id]);
+        unset($grade_values[$this->grade_item->id]);
 
         // if no grades calculation possible or grading not allowed clear both final and raw
-        if (empty($grade_records) or empty($items) or ($this->grade_item->gradetype != GRADE_TYPE_VALUE and $this->grade_item->gradetype != GRADE_TYPE_SCALE)) {
+        if (empty($grade_values) or empty($items) or ($this->grade_item->gradetype != GRADE_TYPE_VALUE and $this->grade_item->gradetype != GRADE_TYPE_SCALE)) {
             $grade->finalgrade = null;
             $grade->rawgrade   = null;
             if ($grade->finalgrade !== $oldgrade->finalgrade or $grade->rawgrade !== $oldgrade->rawgrade) {
@@ -424,21 +424,21 @@ class grade_category extends grade_object {
 
     /// normalize the grades first - all will have value 0...1
         // ungraded items are not used in aggreagation
-        foreach ($grade_records as $k=>$v) {
+        foreach ($grade_values as $k=>$v) {
             if (is_null($v)) {
                 // null means no grade
-                unset($grade_records[$k]);
+                unset($grade_values[$k]);
                 continue;
             }
-            $grade_records[$k] = grade_grades::standardise_score($v, $items[$k]->grademin, $items[$k]->grademax, 0, 1);
+            $grade_values[$k] = grade_grades::standardise_score($v, $items[$k]->grademin, $items[$k]->grademax, 0, 1);
         }
 
         //limit and sort
-        $this->apply_limit_rules($grade_records);
-        sort($grade_records, SORT_NUMERIC);
+        $this->apply_limit_rules($grade_values);
+        asort($grade_values, SORT_NUMERIC);
 
         // let's see we have still enough grades to do any statisctics
-        if (count($grade_records) == 0) {
+        if (count($grade_values) == 0) {
             // not enough attempts yet
             $grade->finalgrade = null;
             $grade->rawgrade   = null;
@@ -451,32 +451,26 @@ class grade_category extends grade_object {
     /// start the aggregation
         switch ($this->aggregation) {
             case GRADE_AGGREGATE_MEDIAN: // Middle point value in the set: ignores frequencies
-                $num = count($grade_records);
+                $num = count($grade_values);
                 $halfpoint = intval($num / 2);
 
                 if($num % 2 == 0) {
-                    $rawgrade = ($grade_records[ceil($halfpoint)] + $grade_records[floor($halfpoint)]) / 2;
+                    $rawgrade = ($grade_values[ceil($halfpoint)] + $grade_values[floor($halfpoint)]) / 2;
                 } else {
-                    $rawgrade = $grade_records[$halfpoint];
+                    $rawgrade = $grade_values[$halfpoint];
                 }
                 break;
 
             case GRADE_AGGREGATE_MIN:
-                $rawgrade = reset($grade_records);
+                $rawgrade = reset($grade_values);
                 break;
 
             case GRADE_AGGREGATE_MAX:
-                $rawgrade = array_pop($grade_records);
-                break;
-
-            case GRADE_AGGREGATE_MEAN_ALL:    // Arithmetic average of all grade items including even NULLs; NULL grade caunted 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_records);
-                $rawgrade = $sum / $num;
+                $rawgrade = array_pop($grade_values);
                 break;
 
             case GRADE_AGGREGATE_MODE:       // the most common value, the highest one if multimode
-                $freq = array_count_values($grade_records);
+                $freq = array_count_values($grade_values);
                 arsort($freq);                      // sort by frequency keeping keys
                 $top = reset($freq);               // highest frequency count
                 $modes = array_keys($freq, $top);  // search for all modes (have the same highest count)
@@ -484,10 +478,88 @@ 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
+                $weightsum = 0;
+                $sum       = 0;
+                foreach($grade_values as $key=>$grade_value) {
+                    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_EXTRACREDIT_MEAN_ALL: // special average 
+                $num = 0;
+                $sum = 0;
+                foreach($items as $key=>$value) {
+                    $grade_value = isset($grade_values[$key]) ? $grade_values[$key] : 0; 
+                    if ($items[$key]->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;
+                    }
+                }
+                if ($num == 0) {
+                    $rawgrade = $sum; // only extra credits or wrong coefs
+                } else {
+                    $rawgrade = $sum / $num;
+                }
+                break;
+
+            case GRADE_AGGREGATE_MEAN_ALL:    // Arithmetic average of all grade items including even NULLs; NULL grade caunted 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_records);
-                $sum = array_sum($grade_records);
+                $num = count($grade_values);
+                $sum = array_sum($grade_values);
                 $rawgrade = $sum / $num;
                 break;
         }
@@ -519,22 +591,35 @@ class grade_category extends grade_object {
     /**
      * Given an array of grade values (numerical indices), applies droplow or keephigh
      * rules to limit the final array.
-     * @param array $grades
+     * @param array $grade_values
      * @return array Limited grades.
      */
-    function apply_limit_rules(&$grades) {
-        rsort($grades, SORT_NUMERIC);
+    function apply_limit_rules(&$grade_values) {
+        arsort($grade_values, SORT_NUMERIC);
         if (!empty($this->droplow)) {
             for ($i = 0; $i < $this->droplow; $i++) {
-                array_pop($grades);
+                array_pop($grade_values);
             }
         } elseif (!empty($this->keephigh)) {
-            while (count($grades) > $this->keephigh) {
-                array_pop($grades);
+            while (count($grade_values) > $this->keephigh) {
+                array_pop($grade_values);
             }
         }
     }
 
+
+    /**
+     * Returns true if category uses special aggregation coeficient
+     * @return boolean true if coeficient used
+     */
+    function is_aggregationcoef_used() {
+        return ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_ALL
+             or $this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_GRADED
+             or $this->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL
+             or $this->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_GRADED);
+             
+    }
+
     /**
      * Returns true if this category has any child grade_category or grade_item.
      * @return int number of direct children, or false if none found.
@@ -905,7 +990,7 @@ class grade_category extends grade_object {
      * Sets the grade_item's locked variable and updates the grade_item.
      * Method named after grade_item::set_locked().
      * @param int $locked 0, 1 or a timestamp int(10) after which date the item will be locked.
-     * @return boolean success if categroy locked (not all children mayb be locked though)
+     * @return boolean success if category locked (not all children mayb be locked though)
      */
     function set_locked($lockedstate) {
         $this->load_grade_item();
index 53e85dcd09b725f6d51f43972e334814e308c7af..d110d540481581c94717380e0073c6fac9efd38e 100644 (file)
@@ -422,6 +422,10 @@ class grade_grades extends grade_object {
      * @return float Converted value
      */
     function standardise_score($rawgrade, $source_min, $source_max, $target_min, $target_max) {
+        if (is_null($rawgrade)) {
+          return null;  
+        }
+
         $factor = ($rawgrade - $source_min) / ($source_max - $source_min);
         $diff = $target_max - $target_min;
         $standardised_value = $factor * $diff + $target_min;
index 8f66544e8d558c6809daf549d19148e98469b5a8..745cc399433a16c54c4fef99ce6318683c19ec4f 100644 (file)
@@ -261,13 +261,14 @@ class grade_item extends grade_object {
         $outcomeiddiff   = $db_item->outcomeid   != $this->outcomeid;
         $multfactordiff  = $db_item->multfactor  != $this->multfactor;
         $plusfactordiff  = $db_item->plusfactor  != $this->plusfactor;
+        $acoefdiff       = $db_item->aggregationcoef != $this->aggregationcoef;
 
         $needsupdatediff = !$db_item->needsupdate &&  $this->needsupdate;    // force regrading only if setting the flag first time
         $lockeddiff      = !empty($db_item->locked) && empty($this->locked); // force regrading only when unlocking
 
         return ($calculationdiff || $categorydiff || $gradetypediff || $grademaxdiff || $grademindiff || $scaleiddiff
              || $outcomeiddiff || $multfactordiff || $plusfactordiff || $needsupdatediff
-             || $lockeddiff);
+             || $lockeddiff || $acoefdiff);
     }
 
     /**
index a3702b0bcebadaf648daf406ed1e9bc8b5f32c6e..0c6d42079752509cef8f56c4e2c22d9cfb92e867 100644 (file)
  */
 
 define('GRADE_AGGREGATE_MEAN_ALL', 0);
-define('GRADE_AGGREGATE_MEDIAN', 1);
-define('GRADE_AGGREGATE_MEAN_GRADED', 2);
+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);