diff --git a/mod/lesson/classes/cache/overrides.php b/mod/lesson/classes/cache/overrides.php new file mode 100644 index 00000000000..889d9728c14 --- /dev/null +++ b/mod/lesson/classes/cache/overrides.php @@ -0,0 +1,110 @@ +. + +/** + * Cache data source for the lesson overrides. + * + * @package mod_lesson + * @copyright 2021 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +declare(strict_types=1); + +namespace mod_lesson\cache; + +use cache_definition; + +/** + * Class lesson_overrides + * + * @package mod_lesson + * @copyright 2021 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class overrides implements \cache_data_source { + + /** @var overrides the singleton instance of this class. */ + protected static $instance = null; + + /** + * Returns an instance of the data source class that the cache can use for loading data using the other methods + * specified by this interface. + * + * @param cache_definition $definition + * @return object + */ + public static function get_instance_for_cache(cache_definition $definition): overrides { + if (is_null(self::$instance)) { + self::$instance = new overrides(); + } + return self::$instance; + } + + /** + * Loads the data for the key provided ready formatted for caching. + * + * @param string|int $key The key to load. + * @return mixed What ever data should be returned, or false if it can't be loaded. + * @throws \coding_exception + */ + public function load_for_cache($key) { + global $DB; + + [$lessonid, $ug, $ugid] = explode('_', $key); + $lessonid = (int) $lessonid; + + switch ($ug) { + case 'u': + $userid = (int) $ugid; + $override = $DB->get_record( + 'lesson_overrides', + ['lessonid' => $lessonid, 'userid' => $userid], + 'available, deadline, timelimit, review, maxattempts, retake, password' + ); + break; + case 'g': + $groupid = (int) $ugid; + $override = $DB->get_record( + 'lesson_overrides', + ['lessonid' => $lessonid, 'groupid' => $groupid], + 'available, deadline, timelimit, review, maxattempts, retake, password' + ); + break; + default: + throw new \coding_exception('Invalid cache key'); + } + + // Return null instead of false, because false will not be cached. + return $override ?: null; + } + + /** + * Loads several keys for the cache. + * + * @param array $keys An array of keys each of which will be string|int. + * @return array An array of matching data items. + */ + public function load_many_for_cache(array $keys) { + $results = []; + + foreach ($keys as $key) { + $results[] = $this->load_for_cache($key); + } + + return $results; + } +} diff --git a/mod/lesson/db/caches.php b/mod/lesson/db/caches.php new file mode 100644 index 00000000000..30ad05c6e6f --- /dev/null +++ b/mod/lesson/db/caches.php @@ -0,0 +1,35 @@ +. + +/** + * Defined caches used internally by the plugin. + * + * @package mod_lesson + * @copyright 2021 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +declare(strict_types=1); + +defined('MOODLE_INTERNAL') || die(); + +$definitions = [ + 'overrides' => [ + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, + 'datasource' => '\mod_lesson\cache\overrides', + ], +]; diff --git a/mod/lesson/lang/en/lesson.php b/mod/lesson/lang/en/lesson.php index c4f4b2499a8..5a2fed83495 100644 --- a/mod/lesson/lang/en/lesson.php +++ b/mod/lesson/lang/en/lesson.php @@ -83,6 +83,7 @@ $string['averagescore'] = 'Average score'; $string['averagetime'] = 'Average time'; $string['branch'] = 'Content'; $string['branchtable'] = 'Content'; +$string['cachedef_overrides'] = 'User and group override information'; $string['cancel'] = 'Cancel'; $string['cannotfindanswer'] = 'Error: could not find answer'; $string['cannotfindattempt'] = 'Error: could not find attempt'; diff --git a/mod/lesson/lib.php b/mod/lesson/lib.php index b0a0761cc36..05bd9016d0b 100644 --- a/mod/lesson/lib.php +++ b/mod/lesson/lib.php @@ -924,23 +924,27 @@ function lesson_reset_userdata($data) { $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallattempts', 'lesson'), 'error'=>false); } + $purgeoverrides = false; + // Remove user overrides. if (!empty($data->reset_lesson_user_overrides)) { $DB->delete_records_select('lesson_overrides', 'lessonid IN (SELECT id FROM {lesson} WHERE course = ?) AND userid IS NOT NULL', array($data->courseid)); $status[] = array( - 'component' => $componentstr, - 'item' => get_string('useroverridesdeleted', 'lesson'), - 'error' => false); + 'component' => $componentstr, + 'item' => get_string('useroverridesdeleted', 'lesson'), + 'error' => false); + $purgeoverrides = true; } // Remove group overrides. if (!empty($data->reset_lesson_group_overrides)) { $DB->delete_records_select('lesson_overrides', 'lessonid IN (SELECT id FROM {lesson} WHERE course = ?) AND groupid IS NOT NULL', array($data->courseid)); $status[] = array( - 'component' => $componentstr, - 'item' => get_string('groupoverridesdeleted', 'lesson'), - 'error' => false); + 'component' => $componentstr, + 'item' => get_string('groupoverridesdeleted', 'lesson'), + 'error' => false); + $purgeoverrides = true; } /// updating dates - shift may be negative too if ($data->timeshift) { @@ -953,12 +957,18 @@ function lesson_reset_userdata($data) { WHERE lessonid IN (SELECT id FROM {lesson} WHERE course = ?) AND deadline <> 0", array($data->timeshift, $data->courseid)); + $purgeoverrides = true; + // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset. // See MDL-9367. shift_course_mod_dates('lesson', array('available', 'deadline'), $data->timeshift, $data->courseid); $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged'), 'error'=>false); } + if ($purgeoverrides) { + cache::make('mod_lesson', 'overrides')->purge(); + } + return $status; } diff --git a/mod/lesson/locallib.php b/mod/lesson/locallib.php index d5dc3be6e34..fec6308a1db 100644 --- a/mod/lesson/locallib.php +++ b/mod/lesson/locallib.php @@ -657,14 +657,14 @@ function lesson_process_group_deleted_in_course($courseid, $groupid = null) { if ($groupid) { $params['groupid'] = $groupid; // We just update the group that was deleted. - $sql = "SELECT o.id, o.lessonid + $sql = "SELECT o.id, o.lessonid, o.groupid FROM {lesson_overrides} o JOIN {lesson} lesson ON lesson.id = o.lessonid WHERE lesson.course = :courseid AND o.groupid = :groupid"; } else { // No groupid, we update all orphaned group overrides for all lessons in course. - $sql = "SELECT o.id, o.lessonid + $sql = "SELECT o.id, o.lessonid, o.groupid FROM {lesson_overrides} o JOIN {lesson} lesson ON lesson.id = o.lessonid LEFT JOIN {groups} grp ON grp.id = o.groupid @@ -672,11 +672,15 @@ function lesson_process_group_deleted_in_course($courseid, $groupid = null) { AND o.groupid IS NOT NULL AND grp.id IS NULL"; } - $records = $DB->get_records_sql_menu($sql, $params); + $records = $DB->get_records_sql($sql, $params); if (!$records) { return; // Nothing to do. } $DB->delete_records_list('lesson_overrides', 'id', array_keys($records)); + $cache = cache::make('mod_lesson', 'overrides'); + foreach ($records as $record) { + $cache->delete("{$record->lessonid}_g_{$record->groupid}"); + } } /** @@ -1740,8 +1744,10 @@ class lesson extends lesson_base { 'instance' => $this->properties->id); if (isset($override->userid)) { $conds['userid'] = $override->userid; + $cachekey = "{$cm->instance}_u_{$override->userid}"; } else { $conds['groupid'] = $override->groupid; + $cachekey = "{$cm->instance}_g_{$override->groupid}"; } $events = $DB->get_records('event', $conds); foreach ($events as $event) { @@ -1750,6 +1756,7 @@ class lesson extends lesson_base { } $DB->delete_records('lesson_overrides', array('id' => $overrideid)); + cache::make('mod_lesson', 'overrides')->delete($cachekey); // Set the common parameters for one of the events we will be triggering. $params = array( diff --git a/mod/lesson/overrideedit.php b/mod/lesson/overrideedit.php index 68f8251d9dc..dd7d9b93402 100644 --- a/mod/lesson/overrideedit.php +++ b/mod/lesson/overrideedit.php @@ -175,6 +175,8 @@ if ($mform->is_cancelled()) { if (!empty($override->id)) { $fromform->id = $override->id; $DB->update_record('lesson_overrides', $fromform); + $cachekey = $groupmode ? "{$fromform->lessonid}_g_{$fromform->groupid}" : "{$fromform->lessonid}_u_{$fromform->userid}"; + cache::make('mod_lesson', 'overrides')->delete($cachekey); // Determine which override updated event to fire. $params['objectid'] = $override->id; @@ -191,6 +193,8 @@ if ($mform->is_cancelled()) { } else { unset($fromform->id); $fromform->id = $DB->insert_record('lesson_overrides', $fromform); + $cachekey = $groupmode ? "{$fromform->lessonid}_g_{$fromform->groupid}" : "{$fromform->lessonid}_u_{$fromform->userid}"; + cache::make('mod_lesson', 'overrides')->delete($cachekey); // Determine which override created event to fire. $params['objectid'] = $fromform->id; diff --git a/mod/lesson/version.php b/mod/lesson/version.php index c0c98909a66..bb6829c7692 100644 --- a/mod/lesson/version.php +++ b/mod/lesson/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2021052500; // The current module version (Date: YYYYMMDDXX) +$plugin->version = 2021052501; // The current module version (Date: YYYYMMDDXX) $plugin->requires = 2021052500; // Requires this Moodle version $plugin->component = 'mod_lesson'; // Full name of the plugin (used for diagnostics) $plugin->cron = 0;