MDL-28463 conditionlib: use MUC for caching grades, reset when grades are changed
authorMarina Glancy <marina@moodle.com>
Tue, 29 Oct 2013 01:22:59 +0000 (12:22 +1100)
committerMarina Glancy <marina@moodle.com>
Fri, 1 Nov 2013 05:48:50 +0000 (16:48 +1100)
lang/en/cache.php
lib/conditionlib.php
lib/db/caches.php
lib/tests/conditionlib_test.php
version.php

index a97ebb5..461edde 100644 (file)
@@ -46,6 +46,7 @@ $string['cachedef_coursemodinfo'] = 'Accumulated information about modules and s
 $string['cachedef_databasemeta'] = 'Database meta information';
 $string['cachedef_eventinvalidation'] = 'Event invalidation';
 $string['cachedef_externalbadges'] = 'External badges for particular user';
+$string['cachedef_gradecondition'] = 'User grades cached for evaluating conditional availability';
 $string['cachedef_groupdata'] = 'Course group information';
 $string['cachedef_htmlpurifier'] = 'HTML Purifier - cleaned content';
 $string['cachedef_langmenu'] = 'List of available languages';
index 3fc62e7..564a4b2 100644 (file)
@@ -1151,7 +1151,6 @@ abstract class condition_info_base {
      *
      * @global stdClass $USER
      * @global moodle_database $DB
-     * @global stdClass $SESSION
      * @param int $gradeitemid Grade item ID we're interested in
      * @param bool $grabthelot If true, grabs all scores for current user on
      *   this course, so that later ones come from cache
@@ -1161,71 +1160,59 @@ abstract class condition_info_base {
      *   or 37.21), or false if user does not have a grade yet
      */
     private function get_cached_grade_score($gradeitemid, $grabthelot=false, $userid=0) {
-        global $USER, $DB, $SESSION;
-        if ($userid==0 || $userid==$USER->id) {
-            // For current user, go via cache in session
-            if (empty($SESSION->gradescorecache) || $SESSION->gradescorecacheuserid!=$USER->id) {
-                $SESSION->gradescorecache = array();
-                $SESSION->gradescorecacheuserid = $USER->id;
-            }
-            if (!array_key_exists($gradeitemid, $SESSION->gradescorecache)) {
-                if ($grabthelot) {
-                    // Get all grades for the current course
-                    $rs = $DB->get_recordset_sql('
-                            SELECT
-                                gi.id,gg.finalgrade,gg.rawgrademin,gg.rawgrademax
-                            FROM
-                                {grade_items} gi
-                                LEFT JOIN {grade_grades} gg ON gi.id=gg.itemid AND gg.userid=?
-                            WHERE
-                                gi.courseid = ?', array($USER->id, $this->item->course));
-                    foreach ($rs as $record) {
-                        $SESSION->gradescorecache[$record->id] =
-                            is_null($record->finalgrade)
-                                // No grade = false
-                                ? false
-                                // Otherwise convert grade to percentage
-                                : (($record->finalgrade - $record->rawgrademin) * 100) /
-                                    ($record->rawgrademax - $record->rawgrademin);
+        global $USER, $DB;
+        if (!$userid) {
+            $userid = $USER->id;
+        }
+        $cache = cache::make('core', 'gradecondition');
+        if (($cachedgrades = $cache->get($userid)) === false) {
+            $cachedgrades = array();
+        }
+        if (!array_key_exists($gradeitemid, $cachedgrades)) {
+            if ($grabthelot) {
+                // Get all grades for the current course
+                $rs = $DB->get_recordset_sql('
+                        SELECT
+                            gi.id,gg.finalgrade,gg.rawgrademin,gg.rawgrademax
+                        FROM
+                            {grade_items} gi
+                            LEFT JOIN {grade_grades} gg ON gi.id=gg.itemid AND gg.userid=?
+                        WHERE
+                            gi.courseid = ?', array($userid, $this->item->course));
+                foreach ($rs as $record) {
+                    $cachedgrades[$record->id] =
+                        is_null($record->finalgrade)
+                            // No grade = false
+                            ? false
+                            // Otherwise convert grade to percentage
+                            : (($record->finalgrade - $record->rawgrademin) * 100) /
+                                ($record->rawgrademax - $record->rawgrademin);
 
-                    }
-                    $rs->close();
-                    // And if it's still not set, well it doesn't exist (eg
-                    // maybe the user set it as a condition, then deleted the
-                    // grade item) so we call it false
-                    if (!array_key_exists($gradeitemid, $SESSION->gradescorecache)) {
-                        $SESSION->gradescorecache[$gradeitemid] = false;
-                    }
-                } else {
-                    // Just get current grade
-                    $record = $DB->get_record('grade_grades', array(
-                        'userid'=>$USER->id, 'itemid'=>$gradeitemid));
-                    if ($record && !is_null($record->finalgrade)) {
-                        $score = (($record->finalgrade - $record->rawgrademin) * 100) /
-                            ($record->rawgrademax - $record->rawgrademin);
-                    } else {
-                        // Treat the case where row exists but is null, same as
-                        // case where row doesn't exist
-                        $score = false;
-                    }
-                    $SESSION->gradescorecache[$gradeitemid]=$score;
                 }
-            }
-            return $SESSION->gradescorecache[$gradeitemid];
-        } else {
-            // Not the current user, so request the score individually
-            $record = $DB->get_record('grade_grades', array(
-                'userid'=>$userid, 'itemid'=>$gradeitemid));
-            if ($record && !is_null($record->finalgrade)) {
-                $score = (($record->finalgrade - $record->rawgrademin) * 100) /
-                    ($record->rawgrademax - $record->rawgrademin);
+                $rs->close();
+                // And if it's still not set, well it doesn't exist (eg
+                // maybe the user set it as a condition, then deleted the
+                // grade item) so we call it false
+                if (!array_key_exists($gradeitemid, $cachedgrades)) {
+                    $cachedgrades[$gradeitemid] = false;
+                }
             } else {
-                // Treat the case where row exists but is null, same as
-                // case where row doesn't exist
-                $score = false;
+                // Just get current grade
+                $record = $DB->get_record('grade_grades', array(
+                    'userid'=>$userid, 'itemid'=>$gradeitemid));
+                if ($record && !is_null($record->finalgrade)) {
+                    $score = (($record->finalgrade - $record->rawgrademin) * 100) /
+                        ($record->rawgrademax - $record->rawgrademin);
+                } else {
+                    // Treat the case where row exists but is null, same as
+                    // case where row doesn't exist
+                    $score = false;
+                }
+                $cachedgrades[$gradeitemid]=$score;
             }
-            return $score;
+            $cache->set($userid, $cachedgrades);
         }
+        return $cachedgrades[$gradeitemid];
     }
 
     /**
@@ -1239,11 +1226,7 @@ abstract class condition_info_base {
      * @param bool $deleted
      */
     public static function inform_grade_changed($grade, $deleted) {
-        global $USER, $SESSION;
-        // In case of self-grading we can purge cache immediately.
-        if ($USER->id == $grade->userid) {
-            unset($SESSION->gradescorecache[$grade->itemid]);
-        }
+        cache::make('core', 'gradecondition')->delete($grade->userid);
     }
 
     /**
@@ -1407,16 +1390,12 @@ abstract class condition_info_base {
     }
 
     /**
-     * For testing only. Wipes information cached in user session.
-     *
-     * @global stdClass $SESSION
+     * For testing only. Wipes information cached in cache.
+     * Replaced with {@link core_conditionlib_testcase::wipe_condition_cache()}
+     * @deprecated since 2.6
      */
     static function wipe_session_cache() {
-        global $SESSION;
-        unset($SESSION->gradescorecache);
-        unset($SESSION->gradescorecacheuserid);
-        unset($SESSION->userfieldcache);
-        unset($SESSION->userfieldcacheuserid);
+        cache::make('core', 'gradecondition')->purge();
     }
 
     /**
index a728d55..c882073 100644 (file)
@@ -205,4 +205,11 @@ $definitions = array(
         'simplekeys' => true,
         'simpledata' => true
     ),
+    // Used to cache user grades for conditional availability purposes.
+    'gradecondition' => array(
+        'mode' => cache_store::MODE_APPLICATION,
+        'staticacceleration' => true,
+        'staticaccelerationsize' => 2, // Should not be required for more than one user at a time.
+        'ttl' => 3600,
+    ),
 );
index 3c9c761..e1a0b1a 100644 (file)
@@ -44,6 +44,10 @@ class core_conditionlib_testcase extends advanced_testcase {
         $this->setUser($user);
     }
 
+    protected function wipe_condition_cache() {
+        cache::make('core', 'gradecondition')->purge();
+    }
+
     public function test_constructor() {
         global $DB;
         $cm = new stdClass;
@@ -480,7 +484,7 @@ class core_conditionlib_testcase extends advanced_testcase {
 
         $ci = new condition_info((object)array('id'=>$cmid), CONDITION_MISSING_EVERYTHING);
         $ci->add_completion_condition($oldid, COMPLETION_COMPLETE);
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
 
         $this->assertFalse($ci->is_available($text, false));
         $this->assertEquals(get_string('requires_completion_1', 'condition', 'xxx'), $text);
@@ -488,23 +492,23 @@ class core_conditionlib_testcase extends advanced_testcase {
         $completion = new completion_info($DB->get_record('course', array('id'=>$courseid)));
         $completion->update_state($oldcm, COMPLETION_COMPLETE);
         completion_info::wipe_session_cache();
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
 
         $this->assertTrue($ci->is_available($text));
         $this->assertFalse($ci->is_available($text, false, $USER->id+1));
         completion_info::wipe_session_cache();
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $completion = new completion_info($DB->get_record('course', array('id'=>$courseid)));
         $completion->update_state($oldcm, COMPLETION_INCOMPLETE);
         $this->assertFalse($ci->is_available($text));
 
         $ci->wipe_conditions();
         $ci->add_completion_condition($oldid, COMPLETION_INCOMPLETE);
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
         $this->assertTrue($ci->is_available($text, false, $USER->id+1));
 
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text, true));
 
         // Grade.
@@ -520,48 +524,48 @@ class core_conditionlib_testcase extends advanced_testcase {
         // Fake it existing.
         $DB->insert_record('grade_grades', (object)array(
             'itemid'=>$gradeitemid, 'userid'=>$USER->id, 'finalgrade'=>3.78));
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
 
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text, true));
 
         // Now require that user gets more than 3.78001.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, 3.78001, null, true);
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertFalse($ci->is_available($text));
         $this->assertEquals(get_string('requires_grade_min', 'condition', 'frog'), $text);
 
         // ...just on 3.78...
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, 3.78, null, true);
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
 
         // ...less than 3.78.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, null, 3.78, true);
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertFalse($ci->is_available($text));
         $this->assertEquals(get_string('requires_grade_max', 'condition', 'frog'), $text);
 
         // ...less than 3.78001.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, null, 3.78001, true);
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
 
         // ...in a range that includes it.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, 3, 4, true);
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
 
         // ...in a range that doesn't include it.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, 4, 5, true);
-        condition_info::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertFalse($ci->is_available($text));
         $this->assertEquals(get_string('requires_grade_range', 'condition', 'frog'), $text);
     }
@@ -630,7 +634,7 @@ class core_conditionlib_testcase extends advanced_testcase {
         $ci = new condition_info_section((object)array('id' => $sectionid),
                 CONDITION_MISSING_EVERYTHING);
         $ci->add_completion_condition($cmid, COMPLETION_COMPLETE);
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
 
         // Completion: Check.
         $this->assertFalse($ci->is_available($text, false));
@@ -639,13 +643,13 @@ class core_conditionlib_testcase extends advanced_testcase {
         $completion = new completion_info($DB->get_record('course', array('id' => $courseid)));
         $completion->update_state($cm, COMPLETION_COMPLETE);
         completion_info::wipe_session_cache();
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
         $this->assertFalse($ci->is_available($text, false, $USER->id + 1));
 
         // Completion: Uncheck.
         completion_info::wipe_session_cache();
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $completion = new completion_info($DB->get_record('course', array('id' => $courseid)));
         $completion->update_state($cm, COMPLETION_INCOMPLETE);
         $this->assertFalse($ci->is_available($text));
@@ -653,10 +657,10 @@ class core_conditionlib_testcase extends advanced_testcase {
         // Completion: Incomplete condition.
         $ci->wipe_conditions();
         $ci->add_completion_condition($cmid, COMPLETION_INCOMPLETE);
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
         $this->assertTrue($ci->is_available($text, false, $USER->id + 1));
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text, true));
 
         // Grade: Add a fake grade item.
@@ -672,47 +676,47 @@ class core_conditionlib_testcase extends advanced_testcase {
         // Grade: Fake it existing.
         $DB->insert_record('grade_grades', (object)array(
             'itemid' => $gradeitemid, 'userid' => $USER->id, 'finalgrade' => 3.78));
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text, true));
 
         // Grade: Now require that user gets more than 3.78001.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, 3.78001, null, true);
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertFalse($ci->is_available($text));
         $this->assertEquals(get_string('requires_grade_min', 'condition', 'frog'), $text);
 
         // Grade: ...just on 3.78...
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, 3.78, null, true);
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
 
         // Grade: ...less than 3.78.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, null, 3.78, true);
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertFalse($ci->is_available($text));
         $this->assertEquals(get_string('requires_grade_max', 'condition', 'frog'), $text);
 
         // Grade: ...less than 3.78001.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, null, 3.78001, true);
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
 
         // Grade: ...in a range that includes it.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, 3, 4, true);
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertTrue($ci->is_available($text));
 
         // Grade: ...in a range that doesn't include it.
         $ci->wipe_conditions();
         $ci->add_grade_condition($gradeitemid, 4, 5, true);
-        condition_info_section::wipe_session_cache();
+        $this->wipe_condition_cache();
         $this->assertFalse($ci->is_available($text));
         $this->assertEquals(get_string('requires_grade_range', 'condition', 'frog'), $text);
 
index da79433..5fa9b8d 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2013102500.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2013102500.01;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.