From 2660377f72ec22643b3fa58ad95651cd421b5b66 Mon Sep 17 00:00:00 2001 From: tjhunt Date: Tue, 4 Nov 2008 10:49:31 +0000 Subject: [PATCH] user preferences: MDL-17123 cope correctly with multiple sessions. This steals the logic from accesslib used to detect dirty contexts and so reload cached access data when permissions are changed. Here, we track when user preferences are changed, so that if necessary we can trigger a reaload. This helps in two situations: 1. When you are logged into Moodle with two different browsers. 2. When someone else changes one of your preferences. After this change, you will see the changed user pref immediately in all sessions. This adds one cheap DB query to any page that tries to access a user preference (which is almost all of them, because of deciding whether to show the messaging pop-up). It adds a few more queries in the cases when a user preference is changed. This is in the name of correctness. --- lib/moodlelib.php | 158 +++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 71 deletions(-) diff --git a/lib/moodlelib.php b/lib/moodlelib.php index cbc9f7a025..40bff7d6dc 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -916,18 +916,36 @@ function gc_cache_flags() { return $DB->delete_records_select('cache_flags', 'expiry < ?', array(time())); } +/// FUNCTIONS FOR HANDLING USER PREFERENCES //////////////////////////////////// + /** * Refresh current $USER session global variable with all their current preferences. * @uses $USER */ -function reload_user_preferences() { +function check_user_preferences_loaded($time = null) { global $USER, $DB; + static $timenow = null; // Static cache, so we only check up-to-dateness once per request. + + if (!empty($USER->preference)) { + // Already loaded. Are we up to date? - //reset preference + if (is_null($timenow) || (!is_null($time) && $time != $timenow)) { + $timenow = time(); + if (!get_cache_flag('userpreferenceschanged', $USER->id, $USER->preference['_lastloaded'])) { + // We are up-to-date. + return; + } + } else { + // Already checked for up-to-date-ness. + return; + } + } + + // OK, so we have to reload. Reset preference $USER->preference = array(); if (!isloggedin() or isguestuser()) { - // no permanent storage for not-logged-in user and guest + // No permanent storage for not-logged-in user and guest } else if ($preferences = $DB->get_records('user_preferences', array('userid'=>$USER->id))) { foreach ($preferences as $preference) { @@ -935,7 +953,19 @@ function reload_user_preferences() { } } - return true; + $USER->preference['_lastloaded'] = $timenow; +} + +/** + * Called from set/delete_user_preferences, so that the prefs can be correctly reloaded. + * @param integer $userid the user whose prefs were changed. + */ +function mark_user_preferences_changed($userid) { + global $CFG, $USER; + if ($userid == $USER->id) { + check_user_preferences_loaded(time()); + } + set_cache_flag('userpreferenceschanged', $userid, 1, time() + $CFG->sessiontimeout); } /** @@ -952,16 +982,11 @@ function reload_user_preferences() { function set_user_preference($name, $value, $otheruserid=NULL) { global $USER, $DB; - if (!isset($USER->preference)) { - reload_user_preferences(); - } - if (empty($name)) { return false; } $nostore = false; - if (empty($otheruserid)){ if (!isloggedin() or isguestuser()) { $nostore = true; @@ -974,33 +999,52 @@ function set_user_preference($name, $value, $otheruserid=NULL) { $userid = $otheruserid; } - $return = true; if ($nostore) { // no permanent storage for not-logged-in user and guest + $return = true; } else if ($preference = $DB->get_record('user_preferences', array('userid'=>$userid, 'name'=>$name))) { if ($preference->value === $value) { return true; } - if (!$DB->set_field('user_preferences', 'value', (string)$value, array('id'=>$preference->id))) { - $return = false; - } + $return = $DB->set_field('user_preferences', 'value', (string)$value, array('id'=>$preference->id)); } else { $preference = new object(); $preference->userid = $userid; $preference->name = $name; $preference->value = (string)$value; - if (!$DB->insert_record('user_preferences', $preference)) { - $return = false; + $return = $DB->insert_record('user_preferences', $preference); + } + + if ($return) { + mark_user_preferences_changed($userid); + // update value in USER session if needed + if ($userid == $USER->id) { + $USER->preference[$name] = (string)$value; + $USER->preference['_lastloaded'] = time(); } } - // update value in USER session if needed - if ($userid == $USER->id) { - $USER->preference[$name] = (string)$value; + return $return; +} + +/** + * Sets a whole array of preferences for the current user + * @param array $prefarray An array of key/value pairs to be set + * @param int $otheruserid A moodle user ID + * @return bool + */ +function set_user_preferences($prefarray, $otheruserid=NULL) { + + if (!is_array($prefarray) or empty($prefarray)) { + return false; } + $return = true; + foreach ($prefarray as $name => $value) { + $return = (set_user_preference($name, $value, $otheruserid) && $return); + } return $return; } @@ -1014,42 +1058,25 @@ function set_user_preference($name, $value, $otheruserid=NULL) { function unset_user_preference($name, $otheruserid=NULL) { global $USER, $DB; - if (!isset($USER->preference)) { - reload_user_preferences(); - } - if (empty($otheruserid)){ $userid = $USER->id; + check_user_preferences_loaded(); } else { $userid = $otheruserid; } - //Delete the preference from $USER if needed - if ($userid == $USER->id) { - unset($USER->preference[$name]); - } - //Then from DB - return $DB->delete_records('user_preferences', array('userid'=>$userid, 'name'=>$name)); -} - -/** - * Sets a whole array of preferences for the current user - * @param array $prefarray An array of key/value pairs to be set - * @param int $otheruserid A moodle user ID - * @return bool - */ -function set_user_preferences($prefarray, $otheruserid=NULL) { + $return = $DB->delete_records('user_preferences', array('userid'=>$userid, 'name'=>$name)); - if (!is_array($prefarray) or empty($prefarray)) { - return false; + if ($return) { + mark_user_preferences_changed($userid); + //Delete the preference from $USER if needed + if ($userid == $USER->id) { + unset($USER->preference[$name]); + $USER->preference['_lastloaded'] = time(); + } } - $return = true; - foreach ($prefarray as $name => $value) { - // The order is important; test for return is done first - $return = (set_user_preference($name, $value, $otheruserid) && $return); - } return $return; } @@ -1069,36 +1096,25 @@ function set_user_preferences($prefarray, $otheruserid=NULL) { function get_user_preferences($name=NULL, $default=NULL, $otheruserid=NULL) { global $USER, $DB; - if (!isset($USER->preference)) { - reload_user_preferences(); - } - if (empty($otheruserid)){ - $userid = $USER->id; - } else { - $userid = $otheruserid; - } - - if ($userid == $USER->id) { - $preference = $USER->preference; + check_user_preferences_loaded(); - } else { - $preference = array(); - if ($prefdata = $DB->get_records('user_preferences', array('userid'=>$userid))) { - foreach ($prefdata as $pref) { - $preference[$pref->name] = $pref->value; - } + if (empty($name)) { + return $USER->preference; // All values + } else if (array_key_exists($name, $USER->preference)) { + return $USER->preference[$name]; // The single value + } else { + return $default; // Default value (or NULL) } - } - - if (empty($name)) { - return $preference; // All values - - } else if (array_key_exists($name, $preference)) { - return $preference[$name]; // The single value } else { - return $default; // Default value (or NULL) + if (empty($name)) { + return $DB->get_records_menu('user_preferences', array('userid'=>$otheruserid), '', 'name,value'); // All values + } else if ($value = $DB->get_record('user_preferences', array('userid'=>$otheruserid, 'name'=>$name))) { + return $value; // The single value + } else { + return $default; // Default value (or NULL) + } } } @@ -3145,8 +3161,7 @@ function complete_user_login($user) { global $CFG, $USER, $SESSION; $USER = $user; // this is required because we need to access preferences here! - - reload_user_preferences(); + check_user_preferences_loaded(); update_user_login_times(); if (empty($CFG->nolastloggedin)) { @@ -3314,6 +3329,7 @@ function get_complete_user_data($field, $value, $mnethostid=null) { } $user->preference = get_user_preferences(null, null, $user->id); + $user->preference['_lastloaded'] = time(); $user->lastcourseaccess = array(); // during last session $user->currentcourseaccess = array(); // during current session -- 2.39.5