diff --git a/admin/settings/subsystems.php b/admin/settings/subsystems.php index c7735e6ec7f..49ca205c6e9 100644 --- a/admin/settings/subsystems.php +++ b/admin/settings/subsystems.php @@ -37,9 +37,10 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page $optionalsubsystems->add(new admin_setting_configcheckbox('enablecompletion', get_string('enablecompletion','completion'), get_string('configenablecompletion','completion'), 0)); - $optionalsubsystems->add(new admin_setting_configcheckbox('enableavailability', + $optionalsubsystems->add($checkbox = new admin_setting_configcheckbox('enableavailability', get_string('enableavailability','condition'), get_string('configenableavailability','condition'), 0)); + $checkbox->set_affects_modinfo(true); $optionalsubsystems->add(new admin_setting_configcheckbox('enableplagiarism', get_string('enableplagiarism','plagiarism'), get_string('configenableplagiarism','plagiarism'), 0)); } diff --git a/course/lib.php b/course/lib.php index 3fd14389258..889dd4536c8 100644 --- a/course/lib.php +++ b/course/lib.php @@ -1082,20 +1082,32 @@ function get_array_of_activities($courseid) { $mod[$seq]->id = $rawmods[$seq]->instance; $mod[$seq]->cm = $rawmods[$seq]->id; $mod[$seq]->mod = $rawmods[$seq]->modname; + + // Oh dear. Inconsistent names left here for backward compatibility. $mod[$seq]->section = $section->section; + $mod[$seq]->sectionid = $rawmods[$seq]->section; + + $mod[$seq]->module = $rawmods[$seq]->module; + $mod[$seq]->added = $rawmods[$seq]->added; + $mod[$seq]->score = $rawmods[$seq]->score; $mod[$seq]->idnumber = $rawmods[$seq]->idnumber; $mod[$seq]->visible = $rawmods[$seq]->visible; + $mod[$seq]->visibleold = $rawmods[$seq]->visibleold; $mod[$seq]->groupmode = $rawmods[$seq]->groupmode; $mod[$seq]->groupingid = $rawmods[$seq]->groupingid; $mod[$seq]->groupmembersonly = $rawmods[$seq]->groupmembersonly; $mod[$seq]->indent = $rawmods[$seq]->indent; $mod[$seq]->completion = $rawmods[$seq]->completion; $mod[$seq]->extra = ""; - if(!empty($CFG->enableavailability)) { + $mod[$seq]->completiongradeitemnumber = + $rawmods[$seq]->completiongradeitemnumber; + $mod[$seq]->completionview = $rawmods[$seq]->completionview; + $mod[$seq]->completionexpected = $rawmods[$seq]->completionexpected; + $mod[$seq]->availablefrom = $rawmods[$seq]->availablefrom; + $mod[$seq]->availableuntil = $rawmods[$seq]->availableuntil; + $mod[$seq]->showavailability = $rawmods[$seq]->showavailability; + if (!empty($CFG->enableavailability)) { condition_info::fill_availability_conditions($rawmods[$seq]); - $mod[$seq]->availablefrom = $rawmods[$seq]->availablefrom; - $mod[$seq]->availableuntil = $rawmods[$seq]->availableuntil; - $mod[$seq]->showavailability = $rawmods[$seq]->showavailability; $mod[$seq]->conditionscompletion = $rawmods[$seq]->conditionscompletion; $mod[$seq]->conditionsgrade = $rawmods[$seq]->conditionsgrade; } @@ -1152,13 +1164,19 @@ function get_array_of_activities($courseid) { // 'empty'. This list corresponds to code in the cm_info constructor. foreach(array('idnumber', 'groupmode', 'groupingid', 'groupmembersonly', 'indent', 'completion', 'extra', 'extraclasses', 'onclick', 'content', - 'icon', 'iconcomponent', 'customdata', 'availablefrom', 'availableuntil', - 'conditionscompletion', 'conditionsgrade') as $property) { + 'icon', 'iconcomponent', 'customdata', 'showavailability', 'availablefrom', + 'availableuntil', 'conditionscompletion', 'conditionsgrade', + 'completionview', 'completionexpected', 'score') as $property) { if (property_exists($mod[$seq], $property) && empty($mod[$seq]->{$property})) { unset($mod[$seq]->{$property}); } } + // Special case: this value is usually set to null, but may be 0 + if (property_exists($mod[$seq], 'completiongradeitemnumber') && + is_null($mod[$seq]->completiongradeitemnumber)) { + unset($mod[$seq]->completiongradeitemnumber); + } } } } diff --git a/lib/adminlib.php b/lib/adminlib.php index f249aa35ff4..273867e9276 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -1373,6 +1373,8 @@ abstract class admin_setting { public $plugin; // null means main config table /** @var bool true indicates this setting does not actually save anything, just information */ public $nosave = false; + /** @var bool if set, indicates that a change to this setting requires rebuild course cache */ + public $affectsmodinfo = false; /** * Constructor @@ -1434,6 +1436,14 @@ abstract class admin_setting { return 'id_s_'.$this->plugin.'_'.$this->name; } + /** + * @param bool $affectsmodinfo If true, changes to this setting will + * cause the course cache to be rebuilt + */ + public function set_affects_modinfo($affectsmodinfo) { + $this->affectsmodinfo = $affectsmodinfo; + } + /** * Returns the config if possible * @@ -1480,6 +1490,12 @@ abstract class admin_setting { // store change set_config($name, $value, $this->plugin); + // Some admin settings affect course modinfo + if ($this->affectsmodinfo) { + // Clear course cache for all courses + rebuild_course_cache(0, true); + } + // log change $log = new stdClass(); $log->userid = during_initial_install() ? 0 :$USER->id; // 0 as user id during install diff --git a/lib/modinfolib.php b/lib/modinfolib.php index 50888fb4827..722eec1e112 100644 --- a/lib/modinfolib.php +++ b/lib/modinfolib.php @@ -340,12 +340,34 @@ class cm_info extends stdClass { public $idnumber; /** - * Visible setting (0 or 1; if this is 0, students cannot see/access the activity) - from + * Time that this course-module was added (unix time) - from course_modules table + * @var int + */ + public $added; + + /** + * This variable is not used and is included here only so it can be documented. + * Once the database entry is removed from course_modules, it should be deleted + * here too. + * @var int + * @deprecated Do not use this variable + */ + public $score; + + /** + * Visible setting (0 or 1; if this is 0, students cannot see/access the activity) - from * course_modules table * @var int */ public $visible; + /** + * Old visible setting (if the entire section is hidden, the previous value for + * visible is stored in this field) - from course_modules table + * @var int + */ + public $visibleold; + /** * Group mode (one of the constants NONE, SEPARATEGROUPS, or VISIBLEGROUPS) - from * course_modules table @@ -380,6 +402,27 @@ class cm_info extends stdClass { */ public $completion; + /** + * Set to the item number (usually 0) if completion depends on a particular + * grade of this activity, or null if completion does not depend on a grade - from + * course_modules table + * @var mixed + */ + public $completiongradeitemnumber; + + /** + * 1 if 'on view' completion is enabled, 0 otherwise - from course_modules table + * @var int + */ + public $completionview; + + /** + * Set to a unix time if completion of this activity is expected at a + * particular time, 0 if no time set - from course_modules table + * @var int + */ + public $completionexpected; + /** * Available date for this activity (0 if not set, or set to seconds since epoch; before this * date, activity does not display to students) - from course_modules table @@ -429,6 +472,12 @@ class cm_info extends stdClass { */ public $modname; + /** + * ID of module - from course_modules table + * @var int + */ + public $module; + /** * Name of module instance for display on page e.g. 'General discussion forum' - from cached * data in modinfo field @@ -443,6 +492,12 @@ class cm_info extends stdClass { */ public $sectionnum; + /** + * Section id - from course_modules table + * @var int + */ + public $section; + /** * Availability conditions for this course-module based on the completion of other * course-modules (array from other course-module id to required completion state for that @@ -786,12 +841,11 @@ class cm_info extends stdClass { $this->idnumber = isset($mod->idnumber) ? $mod->idnumber : ''; $this->name = $mod->name; $this->visible = $mod->visible; - $this->sectionnum = $mod->section; + $this->sectionnum = $mod->section; // Note weirdness with name here $this->groupmode = isset($mod->groupmode) ? $mod->groupmode : 0; $this->groupingid = isset($mod->groupingid) ? $mod->groupingid : 0; $this->groupmembersonly = isset($mod->groupmembersonly) ? $mod->groupmembersonly : 0; $this->indent = isset($mod->indent) ? $mod->indent : 0; - $this->completion = isset($mod->completion) ? $mod->completion : 0; $this->extra = isset($mod->extra) ? $mod->extra : ''; $this->extraclasses = isset($mod->extraclasses) ? $mod->extraclasses : ''; $this->onclick = isset($mod->onclick) ? $mod->onclick : ''; @@ -809,22 +863,32 @@ class cm_info extends stdClass { $this->extra = ''; } - if (!empty($CFG->enableavailability)) { - // We must have completion information from modinfo. If it's not - // there, cache needs rebuilding - if (!isset($mod->showavailability)) { - throw new modinfo_rebuild_cache_exception( - 'enableavailability option was changed; rebuilding '. - 'cache for course ' . $course->id); - } - $this->showavailability = $mod->showavailability; - $this->availablefrom = isset($mod->availablefrom) ? $mod->availablefrom : 0; - $this->availableuntil = isset($mod->availableuntil) ? $mod->availableuntil : 0; - $this->conditionscompletion = isset($mod->conditionscompletion) - ? $mod->conditionscompletion : array(); - $this->conditionsgrade = isset($mod->conditionsgrade) - ? $mod->conditionsgrade : array(); - } + // Note: These fields from $cm were not present in cm_info in Moodle + // 2.0.2 and prior. They may not be available if course cache hasn't + // been rebuilt since then. + $this->section = isset($mod->sectionid) ? $mod->sectionid : 0; + $this->module = isset($mod->module) ? $mod->module : 0; + $this->added = isset($mod->added) ? $mod->added : 0; + $this->score = isset($mod->score) ? $mod->score : 0; + $this->visibleold = isset($mod->visibleold) ? $mod->visibleold : 0; + + // Note: it saves effort and database space to always include the + // availability and completion fields, even if availability or completion + // are actually disabled + $this->completion = isset($mod->completion) ? $mod->completion : 0; + $this->completiongradeitemnumber = isset($mod->completiongradeitemnumber) + ? $mod->completiongradeitemnumber : null; + $this->completionview = isset($mod->completionview) + ? $mod->completionview : 0; + $this->completionexpected = isset($mod->completionexpected) + ? $mod->completionexpected : 0; + $this->showavailability = isset($mod->showavailability) ? $mod->showavailability : 0; + $this->availablefrom = isset($mod->availablefrom) ? $mod->availablefrom : 0; + $this->availableuntil = isset($mod->availableuntil) ? $mod->availableuntil : 0; + $this->conditionscompletion = isset($mod->conditionscompletion) + ? $mod->conditionscompletion : array(); + $this->conditionsgrade = isset($mod->conditionsgrade) + ? $mod->conditionsgrade : array(); // Get module plural name. // TODO This was a very old performance hack and should now be removed as the information @@ -963,18 +1027,6 @@ class cm_info extends stdClass { } -/** - * Special exception that may only be thrown within the constructor for course_modinfo to - * indicate that the cache needs to be rebuilt. Not for use anywhere else. - */ -class modinfo_rebuild_cache_exception extends coding_exception { - function __construct($why) { - // If it ever escapes, that's a code bug - parent::__construct('This exception should be caught by code', $why); - } -} - - /** * Returns reference to full info about modules in course (including visibility). * Cached and as fast as possible (0 or 1 db query). @@ -1016,16 +1068,7 @@ function get_fast_modinfo(&$course, $userid=0) { unset($cache[$course->id]); // prevent potential reference problems when switching users - try { - $cache[$course->id] = new course_modinfo($course, $userid); - } catch (modinfo_rebuild_cache_exception $e) { - debugging($e->debuginfo); - rebuild_course_cache($course->id, true); - $course = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); - // This second time we don't catch the exception - if you request cache rebuild twice - // in a row, that's a bug => coding_exception - $cache[$course->id] = new course_modinfo($course, $userid); - } + $cache[$course->id] = new course_modinfo($course, $userid); // Ensure cache does not use too much RAM if (count($cache) > MAX_MODINFO_CACHE_SIZE) {