MDL-33563 Grading methods allow decimal grades
authorMarina Glancy <marina@moodle.com>
Fri, 19 Jul 2013 05:07:03 +0000 (15:07 +1000)
committerMarina Glancy <marina@moodle.com>
Fri, 19 Jul 2013 05:12:40 +0000 (15:12 +1000)
grade/grading/form/guide/lib.php
grade/grading/form/lib.php
grade/grading/form/rubric/lib.php
grade/grading/form/upgrade.txt [new file with mode: 0644]
mod/assign/locallib.php

index c5292ba..942b19b 100644 (file)
@@ -820,10 +820,9 @@ class gradingform_guide_instance extends gradingform_instance {
     /**
      * Calculates the grade to be pushed to the gradebook
      *
-     * @return int the valid grade from $this->get_controller()->get_grade_range()
+     * @return float|int the valid grade from $this->get_controller()->get_grade_range()
      */
     public function get_grade() {
-        global $DB, $USER;
         $grade = $this->get_guide_filling();
 
         if (!($scores = $this->get_controller()->get_min_max_score()) || $scores['maxscore'] <= $scores['minscore']) {
@@ -842,8 +841,12 @@ class gradingform_guide_instance extends gradingform_instance {
         foreach ($grade['criteria'] as $record) {
             $curscore += $record['score'];
         }
-        return round(($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*
-            ($maxgrade-$mingrade), 0) + $mingrade;
+        $gradeoffset = ($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*
+            ($maxgrade-$mingrade);
+        if ($this->get_controller()->get_allow_grade_decimals()) {
+            return $gradeoffset + $mingrade;
+        }
+        return round($gradeoffset, 0) + $mingrade;
     }
 
     /**
index f28c516..666d0d9 100644 (file)
@@ -73,6 +73,9 @@ abstract class gradingform_controller {
     /** @var array graderange array of valid grades for this area. Use set_grade_range and get_grade_range to access this */
     private $graderange = null;
 
+    /** @var bool if decimal values are allowed as grades. */
+    private $allowgradedecimals = false;
+
     /** @var boolean|null cached result of function has_active_instances() */
     protected $hasactiveinstances = null;
 
@@ -622,13 +625,23 @@ abstract class gradingform_controller {
 
     /**
      * Sets the range of grades used in this area. This is usually either range like 0-100
-     * or the scale where keys start from 1. Typical use:
-     * $controller->set_grade_range(make_grades_menu($gradingtype));
+     * or the scale where keys start from 1.
+     *
+     * Typically modules will call it:
+     * $controller->set_grade_range(make_grades_menu($gradingtype), $gradingtype > 0);
+     * Negative $gradingtype means that scale is used and the grade must be rounded
+     * to the nearest int. Positive $gradingtype means that range 0..$gradingtype
+     * is used for the grades and in this case grade does not have to be rounded.
+     *
+     * Sometimes modules always expect grade to be rounded (like mod_assignment does).
      *
-     * @param array $graderange
+     * @param array $graderange array where first _key_ is the minimum grade and the
+     *     last key is the maximum grade.
+     * @param bool $allowgradedecimals if decimal values are allowed as grades.
      */
-    public final function set_grade_range(array $graderange) {
+    public final function set_grade_range(array $graderange, $allowgradedecimals = false) {
         $this->graderange = $graderange;
+        $this->allowgradedecimals = $allowgradedecimals;
     }
 
     /**
@@ -643,6 +656,15 @@ abstract class gradingform_controller {
         return $this->graderange;
     }
 
+    /**
+     * Returns if decimal values are allowed as grades
+     *
+     * @return bool
+     */
+    public final function get_allow_grade_decimals() {
+        return $this->allowgradedecimals;
+    }
+
     /**
      * Overridden by sub classes that wish to make definition details available to web services.
      * When not overridden, only definition data common to all grading methods is made available.
@@ -866,7 +888,11 @@ abstract class gradingform_instance {
     /**
      * Calculates the grade to be pushed to the gradebook
      *
-     * @return int the valid grade from $this->get_controller()->get_grade_range()
+     * Returned grade must be in range $this->get_controller()->get_grade_range()
+     * Plugins must returned grade converted to int unless
+     * $this->get_controller()->get_allow_grade_decimals() is true.
+     *
+     * @return float|int
      */
     abstract public function get_grade();
 
index ae4f5d5..39e6adc 100644 (file)
@@ -814,10 +814,9 @@ class gradingform_rubric_instance extends gradingform_instance {
     /**
      * Calculates the grade to be pushed to the gradebook
      *
-     * @return int the valid grade from $this->get_controller()->get_grade_range()
+     * @return float|int the valid grade from $this->get_controller()->get_grade_range()
      */
     public function get_grade() {
-        global $DB, $USER;
         $grade = $this->get_rubric_filling();
 
         if (!($scores = $this->get_controller()->get_min_max_score()) || $scores['maxscore'] <= $scores['minscore']) {
@@ -836,7 +835,11 @@ class gradingform_rubric_instance extends gradingform_instance {
         foreach ($grade['criteria'] as $id => $record) {
             $curscore += $this->get_controller()->get_definition()->rubric_criteria[$id]['levels'][$record['levelid']]['score'];
         }
-        return round(($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*($maxgrade-$mingrade), 0) + $mingrade;
+        $gradeoffset = ($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*($maxgrade-$mingrade);
+        if ($this->get_controller()->get_allow_grade_decimals()) {
+            return $gradeoffset + $mingrade;
+        }
+        return round($gradeoffset, 0) + $mingrade;
     }
 
     /**
diff --git a/grade/grading/form/upgrade.txt b/grade/grading/form/upgrade.txt
new file mode 100644 (file)
index 0000000..21cc631
--- /dev/null
@@ -0,0 +1,9 @@
+This files describes API changes in /grade/grading/form/* - Advanced grading methods
+information provided here is intended especially for developers.
+
+=== 2.5.2 ===
+
+* Grading methods now can return grade with decimals. See API functions
+  gradingform_controller::set_grade_range() and
+  gradingform_controller::get_allow_grade_decimals(), and also examples
+  in gradingform_rubric_instance::get_grade().
index f29ed2a..fed15b2 100644 (file)
@@ -3624,7 +3624,7 @@ class assign {
                 // Only show the grade if it is not hidden in gradebook.
                 if (!empty($gradebookgrade->grade) && ($cangrade || !$gradebookgrade->hidden)) {
                     if ($controller = $gradingmanager->get_active_controller()) {
-                        $controller->set_grade_range(make_grades_menu($this->get_instance()->grade));
+                        $controller->set_grade_range(make_grades_menu($this->get_instance()->grade), $this->get_instance()->grade > 0);
                         $gradefordisplay = $controller->render_grade($PAGE,
                                                                      $grade->id,
                                                                      $gradingitem,
@@ -3721,7 +3721,7 @@ class assign {
 
             // Now get the gradefordisplay.
             if ($controller) {
-                $controller->set_grade_range(make_grades_menu($this->get_instance()->grade));
+                $controller->set_grade_range(make_grades_menu($this->get_instance()->grade), $this->get_instance()->grade > 0);
                 $grade->gradefordisplay = $controller->render_grade($PAGE,
                                                                      $grade->id,
                                                                      $gradingitem,
@@ -5182,6 +5182,7 @@ class assign {
         global $CFG, $USER;
 
         $grademenu = make_grades_menu($this->get_instance()->grade);
+        $allowgradedecimals = $this->get_instance()->grade > 0;
 
         $advancedgradingwarning = false;
         $gradingmanager = get_grading_manager($this->context, 'mod_assign', 'submissions');
@@ -5206,7 +5207,7 @@ class assign {
             }
         }
         if ($gradinginstance) {
-            $gradinginstance->get_controller()->set_grade_range($grademenu);
+            $gradinginstance->get_controller()->set_grade_range($grademenu, $allowgradedecimals);
         }
         return $gradinginstance;
     }