]> git.mjollnir.org Git - moodle.git/commitdiff
accesslib: Introduce $DIRTYCONTEXTS, $USER->access[time],is_contextpath_clean()
authormartinlanghoff <martinlanghoff>
Wed, 19 Sep 2007 07:10:24 +0000 (07:10 +0000)
committermartinlanghoff <martinlanghoff>
Wed, 19 Sep 2007 07:10:24 +0000 (07:10 +0000)
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...

lib/accesslib.php

index bced2ff91a7cca5b659d96f7dfd6ecf6b36e6a2d..328ca4a68be7fa10b685582a28bc75d4f2c77654 100755 (executable)
@@ -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;
+}
+
 ?>