Skip to content

Commit

Permalink
Merge branch 'wip-MDL-46960-master' of https://github.com/marinaglanc…
Browse files Browse the repository at this point in the history
  • Loading branch information
danpoltawski committed Mar 31, 2015
2 parents 7e5c5b8 + d368ce2 commit 7d9df98
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 149 deletions.
17 changes: 6 additions & 11 deletions badges/criteria/award_criteria_activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class award_criteria_activity extends award_criteria {
public $criteriatype = BADGE_CRITERIA_TYPE_ACTIVITY;

private $courseid;
private $coursestartdate;
private $course;

public $required_param = 'module';
public $optional_params = array('bydate');
Expand All @@ -46,11 +46,10 @@ public function __construct($record) {
global $DB;
parent::__construct($record);

$course = $DB->get_record_sql('SELECT b.courseid, c.startdate
$this->course = $DB->get_record_sql('SELECT c.id, c.enablecompletion, c.cacherev, c.startdate
FROM {badge} b INNER JOIN {course} c ON b.courseid = c.id
WHERE b.id = :badgeid ', array('badgeid' => $this->badgeid));
$this->courseid = $course->courseid;
$this->coursestartdate = $course->startdate;
$this->courseid = $this->course->id;
}

/**
Expand Down Expand Up @@ -107,13 +106,11 @@ public function get_details($short = '') {
*
*/
public function get_options(&$mform) {
global $DB;

$none = true;
$existing = array();
$missing = array();

$course = $DB->get_record('course', array('id' => $this->courseid));
$course = $this->course;
$info = new completion_info($course);
$mods = $info->get_activities();
$mids = array_keys($mods);
Expand Down Expand Up @@ -187,14 +184,12 @@ public function get_options(&$mform) {
*/
public function review($userid, $filtered = false) {
$completionstates = array(COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS);
$course = new stdClass();
$course->id = $this->courseid;

if ($this->coursestartdate > time()) {
if ($this->course->startdate > time()) {
return false;
}

$info = new completion_info($course);
$info = new completion_info($this->course);

$overall = false;
foreach ($this->params as $param) {
Expand Down
12 changes: 5 additions & 7 deletions badges/criteria/award_criteria_course.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class award_criteria_course extends award_criteria {
public $criteriatype = BADGE_CRITERIA_TYPE_COURSE;

private $courseid;
private $coursestartdate;
private $course;

public $required_param = 'course';
public $optional_params = array('grade', 'bydate');
Expand All @@ -48,11 +48,10 @@ public function __construct($record) {
global $DB;
parent::__construct($record);

$course = $DB->get_record_sql('SELECT b.courseid, c.startdate
$this->course = $DB->get_record_sql('SELECT c.id, c.enablecompletion, c.cacherev, c.startdate
FROM {badge} b INNER JOIN {course} c ON b.courseid = c.id
WHERE b.id = :badgeid ', array('badgeid' => $this->badgeid));
$this->courseid = $course->courseid;
$this->coursestartdate = $course->startdate;
$this->courseid = $this->course->id;
}

/**
Expand Down Expand Up @@ -180,10 +179,9 @@ public function get_options(&$mform) {
* @return bool Whether criteria is complete
*/
public function review($userid, $filtered = false) {
$course = new stdClass();
$course->id = $this->courseid;
$course = $this->course;

if ($this->coursestartdate > time()) {
if ($this->course->startdate > time()) {
return false;
}

Expand Down
3 changes: 2 additions & 1 deletion lang/en/cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
$string['cachedef_coursecontacts'] = 'List of course contacts';
$string['cachedef_coursecattree'] = 'Course categories tree';
$string['cachedef_coursemodinfo'] = 'Accumulated information about modules and sections for each course';
$string['cachedef_completion'] = 'Activity completion status';
$string['cachedef_databasemeta'] = 'Database meta information';
$string['cachedef_eventinvalidation'] = 'Event invalidation';
$string['cachedef_externalbadges'] = 'External badges for particular user';
Expand Down Expand Up @@ -173,4 +174,4 @@
// Deprecated since 2.9.
$string['lockingmeans'] = 'Locking mechanism';
$string['lockmethod'] = 'Lock method';
$string['lockmethod_help'] = 'This is the method used for locking when required of this store.';
$string['lockmethod_help'] = 'This is the method used for locking when required of this store.';
123 changes: 51 additions & 72 deletions lib/completionlib.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,6 @@
*/
define('COMPLETION_NOT_VIEWED', 0);

/**
* Cache expiry time in seconds (10 minutes)
* Completion cacheing
*/
define('COMPLETION_CACHE_EXPIRY', 10*60);

/**
* Completion details should be ORed together and you should return false if
* none apply.
Expand Down Expand Up @@ -250,7 +244,9 @@ public static function get_aggregation_methods() {
* Constructs with course details.
*
* When instantiating a new completion info object you must provide a course
* object with at least id, and enablecompletion properties.
* object with at least id, and enablecompletion properties. Property
* cacherev is needed if you check completion of the current user since
* it is used for cache validation.
*
* @param stdClass $course Moodle course object.
*/
Expand Down Expand Up @@ -290,7 +286,7 @@ public function is_enabled($cm = null) {

// Load data if we do not have enough
if (!isset($this->course->enablecompletion)) {
$this->course->enablecompletion = $DB->get_field('course', 'enablecompletion', array('id' => $this->course->id));
$this->course = get_course($this->course_id);
}

// Check course completion
Expand Down Expand Up @@ -553,7 +549,7 @@ public function is_course_complete($user_id) {
* @return void
*/
public function update_state($cm, $possibleresult=COMPLETION_UNKNOWN, $userid=0) {
global $USER, $SESSION;
global $USER;

// Do nothing if completion is not enabled for that activity
if (!$this->is_enabled($cm)) {
Expand Down Expand Up @@ -783,6 +779,9 @@ public function delete_course_completion_data() {

$DB->delete_records('course_completions', array('course' => $this->course_id));
$DB->delete_records('course_completion_crit_compl', array('course' => $this->course_id));

// Difficult to find affected users, just purge all completion cache.
cache::make('core', 'completion')->purge();
}

/**
Expand All @@ -792,20 +791,13 @@ public function delete_course_completion_data() {
* Used by course reset page.
*/
public function delete_all_completion_data() {
global $DB, $SESSION;
global $DB;

// Delete from database.
$DB->delete_records_select('course_modules_completion',
'coursemoduleid IN (SELECT id FROM {course_modules} WHERE course=?)',
array($this->course_id));

// Reset cache for current user.
if (isset($SESSION->completioncache) &&
array_key_exists($this->course_id, $SESSION->completioncache)) {

unset($SESSION->completioncache[$this->course_id]);
}

// Wipe course completion data too.
$this->delete_course_completion_data();
}
Expand All @@ -818,19 +810,11 @@ public function delete_all_completion_data() {
* @param stdClass|cm_info $cm Activity
*/
public function delete_all_state($cm) {
global $SESSION, $DB;
global $DB;

// Delete from database
$DB->delete_records('course_modules_completion', array('coursemoduleid'=>$cm->id));

// Erase cache data for current user if applicable
if (isset($SESSION->completioncache) &&
array_key_exists($cm->course, $SESSION->completioncache) &&
array_key_exists($cm->id, $SESSION->completioncache[$cm->course])) {

unset($SESSION->completioncache[$cm->course][$cm->id]);
}

// Check if there is an associated course completion criteria
$criteria = $this->get_criteria(COMPLETION_CRITERIA_TYPE_ACTIVITY);
$acriteria = false;
Expand All @@ -846,6 +830,9 @@ public function delete_all_state($cm) {
$DB->delete_records('course_completion_crit_compl', array('course' => $this->course_id, 'criteriaid' => $acriteria->id));
$DB->delete_records('course_completions', array('course' => $this->course_id));
}

// Difficult to find affected users, just purge all completion cache.
cache::make('core', 'completion')->purge();
}

/**
Expand Down Expand Up @@ -876,7 +863,7 @@ public function reset_all_state($cm) {
}
$rs->close();

// Delete all existing state [also clears session cache for current user]
// Delete all existing state.
$this->delete_all_state($cm);

// Merge this with list of planned users (according to roles)
Expand All @@ -894,7 +881,7 @@ public function reset_all_state($cm) {

/**
* Obtains completion data for a particular activity and user (from the
* session cache if available, or by SQL query)
* completion cache if available, or by SQL query)
*
* @param stcClass|cm_info $cm Activity; only required field is ->id
* @param bool $wholecourse If true (default false) then, when necessary to
Expand All @@ -908,39 +895,33 @@ public function reset_all_state($cm) {
* @return object Completion data (record from course_modules_completion)
*/
public function get_data($cm, $wholecourse = false, $userid = 0, $modinfo = null) {
global $USER, $CFG, $SESSION, $DB;
global $USER, $CFG, $DB;
$completioncache = cache::make('core', 'completion');

// Get user ID
if (!$userid) {
$userid = $USER->id;
}

// Is this the current user?
$currentuser = $userid==$USER->id;

if ($currentuser && is_object($SESSION)) {
// Make sure cache is present and is for current user (loginas
// changes this)
if (!isset($SESSION->completioncache) || $SESSION->completioncacheuserid!=$USER->id) {
$SESSION->completioncache = array();
$SESSION->completioncacheuserid = $USER->id;
// See if requested data is present in cache (use cache for current user only).
$usecache = $userid == $USER->id;
$cacheddata = array();
if ($usecache) {
if (!isset($this->course->cacherev)) {
$this->course = get_course($this->course_id);
}
// Expire any old data from cache
foreach ($SESSION->completioncache as $courseid=>$activities) {
if (empty($activities['updated']) || $activities['updated'] < time()-COMPLETION_CACHE_EXPIRY) {
unset($SESSION->completioncache[$courseid]);
if ($cacheddata = $completioncache->get($userid . '_' . $this->course->id)) {
if ($cacheddata['cacherev'] != $this->course->cacherev) {
// Course structure has been changed since the last caching, forget the cache.
$cacheddata = array();
} else if (array_key_exists($cm->id, $cacheddata)) {
return $cacheddata[$cm->id];
}
}
// See if requested data is present, if so use cache to get it
if (isset($SESSION->completioncache) &&
array_key_exists($this->course->id, $SESSION->completioncache) &&
array_key_exists($cm->id, $SESSION->completioncache[$this->course->id])) {
return $SESSION->completioncache[$this->course->id][$cm->id];
}
}

// Not there, get via SQL
if ($currentuser && $wholecourse) {
if ($wholecourse) {
// Get whole course data for cache
$alldatabycmc = $DB->get_records_sql("
SELECT
Expand Down Expand Up @@ -976,14 +957,12 @@ public function get_data($cm, $wholecourse = false, $userid = 0, $modinfo = null
$data->viewed = 0;
$data->timemodified = 0;
}
$SESSION->completioncache[$this->course->id][$othercm->id] = $data;
$cacheddata[$othercm->id] = $data;
}
$SESSION->completioncache[$this->course->id]['updated'] = time();

if (!isset($SESSION->completioncache[$this->course->id][$cm->id])) {
if (!isset($cacheddata[$cm->id])) {
$this->internal_systemerror("Unexpected error: course-module {$cm->id} could not be found on course {$this->course->id}");
}
return $SESSION->completioncache[$this->course->id][$cm->id];

} else {
// Get single record
Expand All @@ -1000,16 +979,14 @@ public function get_data($cm, $wholecourse = false, $userid = 0, $modinfo = null
}

// Put in cache
if ($currentuser) {
$SESSION->completioncache[$this->course->id][$cm->id] = $data;
// For single updates, only set date if it was empty before
if (empty($SESSION->completioncache[$this->course->id]['updated'])) {
$SESSION->completioncache[$this->course->id]['updated'] = time();
}
}
$cacheddata[$cm->id] = $data;
}

return $data;
if ($usecache) {
$cacheddata['cacherev'] = $this->course->cacherev;
$completioncache->set($userid . '_' . $this->course->id, $cacheddata);
}
return $cacheddata[$cm->id];
}

/**
Expand All @@ -1022,7 +999,7 @@ public function get_data($cm, $wholecourse = false, $userid = 0, $modinfo = null
* @param stdClass $data Data about completion for that user
*/
public function internal_set_data($cm, $data) {
global $USER, $SESSION, $DB;
global $USER, $DB;

$transaction = $DB->start_delegated_transaction();
if (!$data->id) {
Expand Down Expand Up @@ -1054,10 +1031,21 @@ public function internal_set_data($cm, $data) {
$event->add_record_snapshot('course_modules_completion', $data);
$event->trigger();

$completioncache = cache::make('core', 'completion');
if ($data->userid == $USER->id) {
$SESSION->completioncache[$cm->course][$cm->id] = $data;
// Update module completion in user's cache.
if (!($cachedata = $completioncache->get($data->userid . '_' . $cm->course))
|| $cachedata['cacherev'] != $this->course->cacherev) {
$cachedata = array('cacherev' => $this->course->cacherev);
}
$cachedata[$cm->id] = $data;
$completioncache->set($data->userid . '_' . $cm->course, $cachedata);

// reset modinfo for user (no need to call rebuild_course_cache())
get_fast_modinfo($cm->course, 0, true);
} else {
// Remove another user's completion cache for this course.
$completioncache->delete($data->userid . '_' . $cm->course);
}
}

Expand Down Expand Up @@ -1341,13 +1329,4 @@ public function internal_systemerror($error) {
throw new moodle_exception('err_system','completion',
$CFG->wwwroot.'/course/view.php?id='.$this->course->id,null,$error);
}

/**
* For testing only. Wipes information cached in user session.
*/
public static function wipe_session_cache() {
global $SESSION;
unset($SESSION->completioncache);
unset($SESSION->completioncacheuserid);
}
}
9 changes: 9 additions & 0 deletions lib/db/caches.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@
'ttl' => 3600,
),

// Used to cache activity completion status.
'completion' => array(
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true,
'ttl' => 3600,
'staticacceleration' => true,
'staticaccelerationsize' => 2, // Should be current course and site course.
),

// A simple cache that stores whether a user can expand a course in the navigation.
// The key is the course ID and the value will either be 1 or 0 (cast to bool).
// The cache isn't always up to date, it should only ever be used to save a costly call to
Expand Down
Loading

0 comments on commit 7d9df98

Please sign in to comment.