MDL-71410 mod_lesson: Cache user and group overrides

This commit is contained in:
Shamim Rezaie 2021-04-25 04:19:24 +10:00
parent 18efd91d2f
commit 47fcfa0af8
7 changed files with 177 additions and 10 deletions

110
mod/lesson/classes/cache/overrides.php vendored Normal file
View File

@ -0,0 +1,110 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Cache data source for the lesson overrides.
*
* @package mod_lesson
* @copyright 2021 Shamim Rezaie <shamim@moodle.com>
* @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 <shamim@moodle.com>
* @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;
}
}

35
mod/lesson/db/caches.php Normal file
View File

@ -0,0 +1,35 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Defined caches used internally by the plugin.
*
* @package mod_lesson
* @copyright 2021 Shamim Rezaie <shamim@moodle.com>
* @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',
],
];

View File

@ -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';

View File

@ -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;
}

View File

@ -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(

View File

@ -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;

View File

@ -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;