accesslib: Introduce $DIRTYCONTEXTS, $USER->access[time],is_contextpath_clean()

has_capability() now (ab)uses a new global: DIRTYCONTEXTS where we
load the contexts that have changed since since $USER->access[time]

The shallow/easy checks are done in has_capability(), deeper checks
go into the newfangled is_contextpath_clean().

The only complication now is to reload the relevant caps without losing
switches, loginas, etc...
This commit is contained in:
martinlanghoff
2007-09-19 07:10:24 +00:00
parent 0d25cd3a81
commit 148eb2a749
+67 -9
View File
@@ -363,7 +363,7 @@ function get_parent_cats($context) {
function has_capability($capability, $context=NULL, $userid=NULL, $doanything=true) {
global $USER, $CONTEXT, $ACCESS, $CFG;
global $USER, $CONTEXT, $ACCESS, $CFG, $DIRTYCONTEXTS;
/// Make sure we know the current context
if (empty($context)) { // Use default CONTEXT if none specified
@@ -381,11 +381,11 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr
$userid = $USER->id;
}
//error_log(print_r($context,1));
$contexts = array();
$basepath = '/' . SYSCONTEXTID;
if (empty($context->path)) {
$contexts[] = SYSCONTEXTID;
$context->path = '/' . SYSCONTEXTID;
$context->path = $basepath;
if (isset($context->id) && $context->id ==! SYSCONTEXTID) {
$contexts[] = $context->id;
$context->path .= '/' . $context->id;
@@ -399,6 +399,28 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr
load_all_capabilities();
}
// Careful check for staleness...
$clean = true;
if (!isset($DIRTYCONTEXTS)) {
// Load dirty contexts list
$DIRTYCONTEXTS = get_dirty_contexts($USER->access['time']);
// Check basepath only once, when
// we load the dirty contexts...
if (isset($DIRTYCONTEXTS->{$basepath})) {
// sitewide change, dirty
$clean = false;
}
}
// Check for staleness in the whole parenthood
if ($clean && !is_contextpath_clean($context->path, $DIRTYCONTEXTS)) {
$clean = false;
}
if (!$clean) {
// TODO: reload all capabilities but
// preserve loginas, roleswitches, etc
}
// divulge how many times we are called
//// error_log("has_capability: id:{$context->id} path:{$context->path} userid:$userid cap:$capability");
@@ -1545,6 +1567,7 @@ function load_all_capabilities() {
$USER->access['ra']["$base:def"] = array($roleid);
}
}
$USER->access['time'] = time();
}
@@ -4636,17 +4659,13 @@ function make_context_subobj($rec) {
* Uses config_plugins.
*
*/
function get_dirty_contexts($time=NULL) {
function get_dirty_contexts($time) {
global $CFG;
$timecond = '';
if (!is_null($time)) {
$timecond = " AND CAST(value to integer) > $time";
}
$sql = "SELECT name, value
FROM {$CFG->prefix}config_plugins
WHERE plugin='accesslib/dirtycontexts'
$timecond";
AND CAST(value AS integer) > $time";
if ($ctx = get_records_sql($sql)) {
return $ctx;
}
@@ -4678,4 +4697,43 @@ function cleanup_dirty_contexts() {
delete_records_select('config_plugins', $sql);
}
/*
* Will walk the contextpath to answer whether
* the contextpath is clean
*
* NOTE: it will *NOT* test the base path
* as it assumes that the caller has checked
* that beforehand.
*
* @param string path
* @param obj/array dirty from get_dirty_contexts()
*
*/
function is_contextpath_clean($path, $dirty) {
$basepath = '/' . SYSCONTEXTID;
// all clean, no dirt!
if (count($dirty) === 0) {
return true;
}
// is _this_ context dirty?
if (isset($dirty->{$path})) {
return false;
}
while (preg_match('!^(/.+)/\d+$!', $path, $matches)) {
$path = $matches[1];
if ($path === $basepath) {
// we don't test basepath
// assume caller did it already
return true;
}
if (isset($dirty->{$path})) {
return false;
}
}
return true;
}
?>