]> git.mjollnir.org Git - moodle.git/commitdiff
Grading grades aggregations
authorDavid Mudrak <david.mudrak@gmail.com>
Mon, 4 Jan 2010 18:17:37 +0000 (18:17 +0000)
committerDavid Mudrak <david.mudrak@gmail.com>
Mon, 4 Jan 2010 18:17:37 +0000 (18:17 +0000)
mod/workshop/locallib.php
mod/workshop/simpletest/testlocallib.php

index f076c4651a36b158339d48919911141fdf6cb89d..9c24cb699a8ee153a9ed63f699ab58c75a0f7a20 100644 (file)
@@ -1189,7 +1189,8 @@ class workshop {
     /**
      * Calculates grades for assessment for the given participant(s)
      *
-     * Grade for submission is calculated as a weighted mean of all given grades
+     * Grade for assessment is calculated as a simple mean of all grading grades calculated by the grading evaluator.
+     * The assessment weight is not taken into account here.
      *
      * @param null|int|array $restrict If null, update all reviewers, otherwise update just grades for the given reviewer(s)
      * @return void
@@ -1197,7 +1198,50 @@ class workshop {
     public function aggregate_grading_grades($restrict=null) {
         global $DB;
 
-        // todo
+        // fetch a recordset with all assessments to process
+        $sql = 'SELECT a.reviewerid, a.gradinggrade, a.gradinggradeover,
+                       ag.id AS aggregationid, ag.gradinggrade AS aggregatedgrade
+                  FROM {workshop_assessments} a
+            INNER JOIN {workshop_submissions} s ON (a.submissionid = s.id)
+             LEFT JOIN {workshop_aggregations} ag ON (ag.userid = a.reviewerid AND ag.workshopid = s.workshopid)
+                 WHERE s.example=0 AND s.workshopid=:workshopid'; // to be cont.
+        $params = array('workshopid' => $this->id);
+
+        if (is_null($restrict)) {
+            // update all users - no more conditions
+        } elseif (!empty($restrict)) {
+            list($usql, $uparams) = $DB->get_in_or_equal($restrict, SQL_PARAMS_NAMED);
+            $sql .= " AND a.reviewerid $usql";
+            $params = array_merge($params, $uparams);
+        } else {
+            throw new coding_exception('Empty value is not a valid parameter here');
+        }
+
+        $sql .= ' ORDER BY a.reviewerid'; // this is important for bulk processing
+
+        $rs         = $DB->get_recordset_sql($sql, $params);
+        $batch      = array();    // will contain a set of all assessments of a single submission
+        $previous   = null;       // a previous record in the recordset
+
+        foreach ($rs as $current) {
+            if (is_null($previous)) {
+                // we are processing the very first record in the recordset
+                $previous   = $current;
+            }
+            if ($current->reviewerid == $previous->reviewerid) {
+                // we are still processing the current reviewer
+                $batch[] = $current;
+            } else {
+                // process all the assessments of a sigle submission
+                $this->aggregate_grading_grades_process($batch);
+                // and then start to process another reviewer
+                $batch      = array($current);
+                $previous   = $current;
+            }
+        }
+        // do not forget to process the last batch!
+        $this->aggregate_grading_grades_process($batch);
+        $rs->close();
     }
 
     /**
@@ -1295,6 +1339,68 @@ class workshop {
         }
     }
 
+    /**
+     * Given an array of all assessments done by a single reviewer, calculates the final grading grade
+     *
+     * This calculates the simple mean of the passed grading grades. If, however, the grading grade
+     * was overridden by a teacher, the gradinggradeover value is returned and the rest of grades are ignored.
+     *
+     * @param array $assessments of stdClass(->reviewerid ->gradinggrade ->gradinggradeover ->aggregationid ->aggregatedgrade)
+     * @return null|float the aggregated grade rounded to numeric(10,5)
+     */
+    protected function aggregate_grading_grades_process(array $assessments) {
+        global $DB;
+
+        $reviewerid = null; // the id of the reviewer being processed
+        $current    = null; // the gradinggrade currently saved in database
+        $finalgrade = null; // the new grade to be calculated
+        $agid       = null; // aggregation id
+        $sumgrades  = 0;
+        $count      = 0;
+
+        foreach ($assessments as $assessment) {
+            if (is_null($reviewerid)) {
+                // the id is the same in all records, fetch it during the first loop cycle
+                $reviewerid = $assessment->reviewerid;
+            }
+            if (is_null($agid)) {
+                // the id is the same in all records, fetch it during the first loop cycle
+                $agid = $assessment->aggregationid;
+            }
+            if (is_null($current)) {
+                // the currently saved grade is the same in all records, fetch it during the first loop cycle
+                $current = $assessment->aggregatedgrade;
+            }
+            if (!is_null($assessment->gradinggradeover)) {
+                // the grading grade for this assessment is overriden by a teacher
+                $sumgrades += $assessment->gradinggradeover;
+                $count++;
+            } else {
+                if (!is_null($assessment->gradinggrade)) {
+                    $sumgrades += $assessment->gradinggrade;
+                    $count++;
+                }
+            }
+        }
+        if ($count > 0) {
+            $finalgrade = grade_floatval($sumgrades / $count);
+        }
+        // check if the new final grade differs from the one stored in the database
+        if (grade_floats_different($finalgrade, $current)) {
+            // we need to save new calculation into the database
+            if (is_null($agid)) {
+                // no aggregation record yet
+                $record = new stdClass();
+                $record->workshopid = $this->id;
+                $record->userid = $reviewerid;
+                $record->gradinggrade = $finalgrade;
+                $DB->insert_record('workshop_aggregations', $record);
+            } else {
+                $DB->set_field('workshop_aggregations', 'gradinggrade', $finalgrade, array('id' => $agid));
+            }
+        }
+    }
+
     /**
      * Given a list of user ids, returns the filtered one containing just ids of users with own submission
      *
index c6f2b8e20f24dfc856cd885eda1f2858a3ff6d75..4e9839450a4043cdf08fcc5980d23b5b8af26e3c 100644 (file)
@@ -36,6 +36,7 @@ Mock::generate(get_class($DB), 'mockDB');
 class testable_workshop extends workshop {
 
     public function __construct() {
+        $this->id       = 16;
         $this->cm       = new stdClass();
         $this->course   = new stdClass();
         $this->context  = new stdClass();
@@ -44,6 +45,10 @@ class testable_workshop extends workshop {
     public function aggregate_submission_grades_process(array $assessments) {
         parent::aggregate_submission_grades_process($assessments);
     }
+
+    public function aggregate_grading_grades_process(array $assessments) {
+        parent::aggregate_grading_grades_process($assessments);
+    }
 }
 
 /**
@@ -243,6 +248,135 @@ class workshop_internal_api_test extends UnitTestCase {
         $this->workshop->aggregate_submission_grades_process($batch);
     }
 
+    public function test_aggregate_grading_grades_process_nograding() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>2, 'gradinggrade'=>null, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
+        // expectation
+        $DB->expectNever('set_field');
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_single_grade_new() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>3, 'gradinggrade'=>82.87670, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
+        // expectation
+        $expected = new stdClass();
+        $expected->workshopid = $this->workshop->id;
+        $expected->userid = 3;
+        $expected->gradinggrade = 82.87670;
+        $DB->expectOnce('insert_record', array('workshop_aggregations', $expected));
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_single_grade_update() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>3, 'gradinggrade'=>90.00000, 'gradinggradeover'=>null, 'aggregationid'=>1, 'aggregatedgrade'=>82.87670);
+        // expectation
+        $DB->expectOnce('set_field', array('workshop_aggregations', 'gradinggrade', 90.00000, array('id' => 1)));
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_single_grade_uptodate() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>3, 'gradinggrade'=>90.00000, 'gradinggradeover'=>null, 'aggregationid'=>1, 'aggregatedgrade'=>90.00000);
+        // expectation
+        $DB->expectNever('set_field');
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_single_grade_overridden() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>4, 'gradinggrade'=>91.56700, 'gradinggradeover'=>82.32105, 'aggregationid'=>2, 'aggregatedgrade'=>91.56700);
+        // expectation
+        $DB->expectOnce('set_field', array('workshop_aggregations', 'gradinggrade', 82.32105, array('id' => 2)));
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_multiple_grades_new() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>99.45670, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>87.34311, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>51.12000, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
+        // expectation
+        $expected = new stdClass();
+        $expected->workshopid = $this->workshop->id;
+        $expected->userid = 5;
+        $expected->gradinggrade = 79.3066;
+        $DB->expectOnce('insert_record', array('workshop_aggregations', $expected));
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_multiple_grades_update() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>56.23400, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>79.30660);
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>87.34311, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>79.30660);
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>51.12000, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>79.30660);
+        // expectation
+        $DB->expectOnce('set_field', array('workshop_aggregations', 'gradinggrade', 64.89904, array('id' => 2)));
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_multiple_grades_overriden() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>56.23400, 'gradinggradeover'=>99.45670, 'aggregationid'=>2, 'aggregatedgrade'=>64.89904);
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>87.34311, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>64.89904);
+        $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>51.12000, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>64.89904);
+        // expectation
+        $DB->expectOnce('set_field', array('workshop_aggregations', 'gradinggrade', 79.30660, array('id' => 2)));
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_multiple_grades_one_missing() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>50.00000, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
+        $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>null, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
+        $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>52.20000, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
+        // expectation
+        $DB->expectOnce('set_field', array('workshop_aggregations', 'gradinggrade', 51.10000, array('id' => 3)));
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+    public function test_aggregate_grading_grades_process_multiple_grades_missing_overridden() {
+        global $DB;
+        // fixture set-up
+        $batch = array();
+        $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>50.00000, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
+        $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>null, 'gradinggradeover'=>69.00000, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
+        $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>52.20000, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
+        // expectation
+        $DB->expectOnce('set_field', array('workshop_aggregations', 'gradinggrade', 57.06667, array('id' => 3)));
+        // excersise SUT
+        $this->workshop->aggregate_grading_grades_process($batch);
+    }
+
+
     public function test_percent_to_value() {
         // fixture setup
         $total = 185;