MDL-35339 Better cache reset for get_fast_modinfo(), allow exec get_fast_modinfo...
authorMarina Glancy <marina@moodle.com>
Wed, 10 Oct 2012 04:41:04 +0000 (12:41 +0800)
committerMarina Glancy <marina@moodle.com>
Mon, 15 Oct 2012 06:08:15 +0000 (14:08 +0800)
course/lib.php
course/tests/courselib_test.php
lib/completionlib.php
lib/deprecatedlib.php
lib/modinfolib.php
lib/phpunit/classes/data_generator.php
lib/phpunit/classes/util.php
lib/tests/conditionlib_test.php

index 33786e1..1919f79 100644 (file)
@@ -2695,21 +2695,24 @@ function add_course_module($mod) {
 /**
  * Creates missing course section(s) and rebuilds course cache
  *
- * @param stdClass $course course object
+ * @param int|stdClass $courseorid course id or course object
  * @param int|array $sections list of relative section numbers to create
  * @return bool if there were any sections created
  */
-function course_create_sections_if_missing(&$course, $sections) {
+function course_create_sections_if_missing($courseorid, $sections) {
     global $DB;
     if (!is_array($sections)) {
         $sections = array($sections);
     }
-    $existing = array_keys(get_fast_modinfo($course)->get_section_info_all());
+    $existing = array_keys(get_fast_modinfo($courseorid)->get_section_info_all());
+    if (is_object($courseorid)) {
+        $courseorid = $courseorid->id;
+    }
     $coursechanged = false;
     foreach ($sections as $sectionnum) {
         if (!in_array($sectionnum, $existing)) {
             $cw = new stdClass();
-            $cw->course   = $course->id;
+            $cw->course   = $courseorid;
             $cw->section  = $sectionnum;
             $cw->summary  = '';
             $cw->summaryformat = FORMAT_HTML;
@@ -2719,9 +2722,7 @@ function course_create_sections_if_missing(&$course, $sections) {
         }
     }
     if ($coursechanged) {
-        rebuild_course_cache($course->id, true);
-        $course->modinfo = null;
-        $course->sectioncache = null;
+        rebuild_course_cache($courseorid, true);
     }
     return $coursechanged;
 }
@@ -2745,17 +2746,8 @@ function course_add_cm_to_section($courseorid, $modid, $sectionnum, $beforemod =
     if (is_object($beforemod)) {
         $beforemod = $beforemod->id;
     }
-    if (is_object($courseorid)) {
-        $course = &$courseorid;
-    } else {
-        if (isset($COURSE->id) && $COURSE->id == $courseorid) {
-            $course = &$COURSE;
-        } else {
-            $course = $DB->get_record('course', array('id' => $courseorid), '*', MUST_EXIST);
-        }
-    }
-    course_create_sections_if_missing($course, $sectionnum);
-    $section = get_fast_modinfo($course)->get_section_info($sectionnum);
+    course_create_sections_if_missing($courseorid, $sectionnum);
+    $section = get_fast_modinfo($courseorid)->get_section_info($sectionnum);
     $modarray = explode(",", trim($section->sequence));
     if (empty($modarray)) {
         $newsequence = "$modid";
@@ -2768,9 +2760,11 @@ function course_add_cm_to_section($courseorid, $modid, $sectionnum, $beforemod =
     }
     $DB->set_field("course_sections", "sequence", $newsequence, array("id" => $section->id));
     $DB->set_field('course_modules', 'section', $section->id, array('id' => $modid));
-    rebuild_course_cache($course->id, true);
-    $course->modinfo = null;
-    $course->sectioncache = null;
+    if (is_object($courseorid)) {
+        rebuild_course_cache($courseorid->id, true);
+    } else {
+        rebuild_course_cache($courseorid, true);
+    }
     return $section->id;     // Return course_sections ID that was used.
 }
 
index 5957966..c964414 100644 (file)
@@ -302,10 +302,6 @@ class courselib_testcase extends advanced_testcase {
         $course = $this->getDataGenerator()->create_course(array('numsections'=>5));
         $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course->id));
 
-        // reset cache inside $course because $course is not passed to create_module
-        $course->modinfo = null;
-        $course->sectioncache = null;
-
         $cms = get_fast_modinfo($course)->get_cms();
         $cm = reset($cms);
 
@@ -314,10 +310,6 @@ class courselib_testcase extends advanced_testcase {
 
         moveto_module($cm, $section3);
 
-        // reset cache inside $course because $course is not passed to moveto_module
-        $course->modinfo = null;
-        $course->sectioncache = null;
-
         $modinfo = get_fast_modinfo($course);
         $this->assertTrue(empty($modinfo->sections[0]));
         $this->assertFalse(empty($modinfo->sections[3]));
index 4d6ea82..41b7921 100644 (file)
@@ -971,8 +971,8 @@ class completion_info {
 
         if ($data->userid == $USER->id) {
             $SESSION->completioncache[$cm->course][$cm->id] = $data;
-            $reset = 'reset';
-            get_fast_modinfo($reset);
+            // reset modinfo for user (no need to call rebuild_course_cache())
+            get_fast_modinfo($cm->course, 0, true);
         }
     }
 
index 8293a2e..2e98925 100644 (file)
@@ -2937,13 +2937,13 @@ function get_generic_section_name($format, stdClass $section) {
  * from 2.4 $section may also be just the field course_sections.section
  *
  * If you need the list of all sections it is more efficient to get this data by calling
- * $modinfo = get_fast_modinfo($course);
+ * $modinfo = get_fast_modinfo($courseorid);
  * $sections = $modinfo->get_section_info_all()
  * {@link get_fast_modinfo()}
  * {@link course_modinfo::get_section_info_all()}
  *
  * Information about one section (instance of section_info):
- * get_fast_modinfo($course)->get_sections_info($section)
+ * get_fast_modinfo($courseorid)->get_sections_info($section)
  * {@link course_modinfo::get_section_info()}
  *
  * @deprecated since 2.4
@@ -2954,8 +2954,7 @@ function get_generic_section_name($format, stdClass $section) {
 function get_all_sections($courseid) {
     global $DB;
     debugging('get_all_sections() is deprecated. See phpdocs for this function', DEBUG_DEVELOPER);
-    $course = $DB->get_record('course', array('id' => $courseid));
-    return get_fast_modinfo($course)->get_section_info_all();
+    return get_fast_modinfo($courseid)->get_section_info_all();
 }
 
 /**
@@ -2974,8 +2973,7 @@ function get_all_sections($courseid) {
 function add_mod_to_section($mod, $beforemod=NULL) {
     debugging('Function add_mod_to_section() is deprecated, please use course_add_cm_to_section()', DEBUG_DEVELOPER);
     global $DB;
-    $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
-    return course_add_cm_to_section($course, $mod->coursemodule, $mod->section, $beforemod);
+    return course_add_cm_to_section($mod->course, $mod->coursemodule, $mod->section, $beforemod);
 }
 
 /**
@@ -2984,14 +2982,14 @@ function add_mod_to_section($mod, $beforemod=NULL) {
  * Function get_all_mods() is deprecated in 2.4
  * Instead of:
  * <code>
- * get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
+ * get_all_mods($courseid, $mods, $modnames, $modnamesplural, $modnamesused);
  * </code>
  * please use:
  * <code>
- * $mods = get_fast_modinfo($course)->get_cms();
+ * $mods = get_fast_modinfo($courseorid)->get_cms();
  * $modnames = get_module_types_names();
  * $modnamesplural = get_module_types_names(true);
- * $modnamesused = get_fast_modinfo($course)->get_used_module_names();
+ * $modnamesused = get_fast_modinfo($courseorid)->get_used_module_names();
  * </code>
  *
  * @deprecated since 2.4
@@ -3008,8 +3006,7 @@ function get_all_mods($courseid, &$mods, &$modnames, &$modnamesplural, &$modname
     global $COURSE;
     $modnames      = get_module_types_names();
     $modnamesplural= get_module_types_names(true);
-    $course = ($courseid==$COURSE->id) ? $COURSE : $DB->get_record('course',array('id'=>$courseid));
-    $modinfo = get_fast_modinfo($course);
+    $modinfo = get_fast_modinfo($courseid);
     $mods = $modinfo->get_cms();
     $modnamesused = $modinfo->get_used_module_names();
 }
@@ -3018,9 +3015,9 @@ function get_all_mods($courseid, &$mods, &$modnames, &$modnamesplural, &$modname
  * Returns course section - creates new if does not exist yet
  *
  * This function is deprecated. To create a course section call:
- * course_create_sections_if_missing($course, $sections);
+ * course_create_sections_if_missing($courseorid, $sections);
  * to get the section call:
- * get_fast_modinfo($course)->get_section_info($sectionnum);
+ * get_fast_modinfo($courseorid)->get_section_info($sectionnum);
  *
  * @see course_create_sections_if_missing()
  * @see get_fast_modinfo()
index d24ec6d..405fd7b 100644 (file)
@@ -1216,16 +1216,14 @@ class cm_info extends stdClass {
  * Returns reference to full info about modules in course (including visibility).
  * Cached and as fast as possible (0 or 1 db query).
  *
- * @global object
- * @global object
- * @global moodle_database
  * @uses MAX_MODINFO_CACHE_SIZE
- * @param mixed $course object or 'reset' string to reset caches, modinfo may be updated in db
- * @param int $userid Defaults to current user id
- * @return course_modinfo Module information for course, or null if resetting
+ * @param int|stdClass $courseorid object or 'reset' string to reset caches, modinfo may be updated in db
+ * @param int $userid Set 0 (default) for current user
+ * @param bool $resetonly whether we want to get modinfo or just reset the cache
+ * @return course_modinfo|null Module information for course, or null if resetting
  */
-function get_fast_modinfo(&$course, $userid=0) {
-    global $CFG, $USER, $DB;
+function get_fast_modinfo($courseorid, $userid = 0, $resetonly = false) {
+    global $CFG, $USER;
     require_once($CFG->dirroot.'/course/lib.php');
 
     if (!empty($CFG->enableavailability)) {
@@ -1234,17 +1232,45 @@ function get_fast_modinfo(&$course, $userid=0) {
 
     static $cache = array();
 
-    if ($course === 'reset') {
-        $cache = array();
+    // compartibility with syntax prior to 2.4:
+    if ($courseorid === 'reset') {
+        debugging("Using the string 'reset' as the first argument of get_fast_modinfo() is deprecated. Use get_fast_modinfo(0,0,true) instead.", DEBUG_DEVELOPER);
+        $courseorid = 0;
+        $resetonly = true;
+    }
+
+    if (is_object($courseorid)) {
+        $course = $courseorid;
+    } else {
+        $course = (object)array('id' => $courseorid, 'modinfo' => null, 'sectioncache' => null);
+    }
+
+    // Function is called with $reset = true
+    if ($resetonly) {
+        if (isset($course->id) && $course->id > 0) {
+            $cache[$course->id] = false;
+        } else {
+            foreach (array_keys($cache) as $key) {
+                $cache[$key] = false;
+            }
+        }
         return null;
     }
 
+    // Function is called with $reset = false, retrieve modinfo
     if (empty($userid)) {
         $userid = $USER->id;
     }
 
-    if (array_key_exists($course->id, $cache) and $cache[$course->id]->userid == $userid) {
-        return $cache[$course->id];
+    if (array_key_exists($course->id, $cache)) {
+        if ($cache[$course->id] === false) {
+            // this course has been recently reset, do not rely on modinfo and sectioncache in $course
+            $course->modinfo = null;
+            $course->sectioncache = null;
+        } else if ($cache[$course->id]->userid == $userid) {
+            // this course's modinfo for the same user was recently retrieved, return cached
+            return $cache[$course->id];
+        }
     }
 
     if (!property_exists($course, 'modinfo')) {
@@ -1302,8 +1328,7 @@ function rebuild_course_cache($courseid=0, $clearonly=false) {
             $COURSE->sectioncache = null;
         }
         // reset the fast modinfo cache
-        $reset = 'reset';
-        get_fast_modinfo($reset);
+        get_fast_modinfo($courseid, 0, true);
         return;
     }
 
@@ -1331,8 +1356,7 @@ function rebuild_course_cache($courseid=0, $clearonly=false) {
     }
     $rs->close();
     // reset the fast modinfo cache
-    $reset = 'reset';
-    get_fast_modinfo($reset);
+    get_fast_modinfo($courseid, 0, true);
 }
 
 
index 98fecbe..32ab788 100644 (file)
@@ -400,9 +400,8 @@ EOD;
             throw new coding_exception('section must be present in phpunit_util::create_course_section() $record');
         }
 
-        $course = $DB->get_record('course', array('id' => $record['course']), '*', MUST_EXIST);
-        course_create_sections_if_missing($course, $record['section']);
-        return get_fast_modinfo($course)->get_section_info($record['section']);
+        course_create_sections_if_missing($record['course'], $record['section']);
+        return get_fast_modinfo($record['course'])->get_section_info($record['section']);
     }
 
     /**
index 0f95b2f..83b3865 100644 (file)
@@ -640,8 +640,7 @@ class phpunit_util {
             // If file containing class is not loaded, there is no cache there anyway.
             format_base::reset_course_cache(0);
         }
-        $reset = 'reset';
-        get_fast_modinfo($reset);
+        get_fast_modinfo(0, 0, true);
 
         // purge dataroot directory
         self::reset_dataroot();
index b4e7cee..6079b6a 100644 (file)
@@ -43,10 +43,6 @@ class conditionlib_testcase extends advanced_testcase {
         $CFG->enablecompletion = 1;
         $user = $this->getDataGenerator()->create_user();;
         $this->setUser($user);
-
-        // Reset modinfo cache before each request
-        $reset = 'reset';
-        get_fast_modinfo($reset);
     }
 
     function test_constructor() {
@@ -276,8 +272,7 @@ class conditionlib_testcase extends advanced_testcase {
         ));
 
         // Okay sweet, now get modinfo
-        $course = $DB->get_record('course',array('id'=>$courseid));
-        $modinfo=get_fast_modinfo($course);
+        $modinfo=get_fast_modinfo($courseid);
 
         // Test basic data
         $this->assertEquals(1,$modinfo->cms[$cmid1]->showavailability);
@@ -327,8 +322,7 @@ class conditionlib_testcase extends advanced_testcase {
 
         rebuild_course_cache($courseid, true);
         // Okay sweet, now get modinfo
-        $course = $DB->get_record('course', array('id' => $courseid));
-        $modinfo = get_fast_modinfo($course);
+        $modinfo = get_fast_modinfo($courseid);
 
         // Test basic data
         $section1 = $modinfo->get_section_info(1);