]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
Fixes #3940. Cleaned up caching for access functions. Access caches are now cleared...
authorBrett Profitt <brett.profitt@gmail.com>
Tue, 18 Dec 2012 20:55:42 +0000 (15:55 -0500)
committerBrett Profitt <brett.profitt@gmail.com>
Tue, 18 Dec 2012 20:55:42 +0000 (15:55 -0500)
engine/classes/ElggStaticVariableCache.php
engine/lib/access.php
engine/tests/api/access_collections.php

index 787d35a324d3934f925485d6cbf009713c9a5f87..17d8494004026a512bf1c3034231f5964a8d0060 100644 (file)
@@ -21,8 +21,8 @@ class ElggStaticVariableCache extends ElggSharedMemoryCache {
         * This function creates a variable cache in a static variable in
         * memory, optionally with a given namespace (to avoid overlap).
         *
-        * @param string $namespace The namespace for this cache to write to
-        * note, namespaces of the same name are shared!
+        * @param string $namespace The namespace for this cache to write to.
+        * @note namespaces of the same name are shared!
         */
        function __construct($namespace = 'default') {
                $this->setNamespace($namespace);
index 3b2b7aeaa24a1ac6544549a13ba927bfc17c3511..f7d3bf7ea1f77b6a83660817163db36c6cad89c8 100644 (file)
  * @link http://docs.elgg.org/Access
  */
 
+/**
+ * Return an ElggCache static variable cache for the access caches
+ *
+ * @staticvar ElggStaticVariableCache $access_cache
+ * @return \ElggStaticVariableCache
+ * @access private
+ */
+function _elgg_get_access_cache() {
+       /**
+        * A default filestore cache using the dataroot.
+        */
+       static $access_cache;
+
+       if (!$access_cache) {
+               $access_cache = new ElggStaticVariableCache('access');
+       }
+
+       return $access_cache;
+}
+
 /**
  * Return a string of access_ids for $user_id appropriate for inserting into an SQL IN clause.
  *
  */
 function get_access_list($user_id = 0, $site_id = 0, $flush = false) {
        global $CONFIG, $init_finished;
-       static $access_list;
-
-       if (!isset($access_list)) {
-               $access_list = array();
+       $cache = _elgg_get_access_cache();
+       
+       if ($flush) {
+               $cache->clear();
        }
 
        if ($user_id == 0) {
@@ -45,20 +65,20 @@ function get_access_list($user_id = 0, $site_id = 0, $flush = false) {
        $user_id = (int) $user_id;
        $site_id = (int) $site_id;
 
-       if (isset($access_list[$user_id]) && $flush == false) {
-               return $access_list[$user_id];
-       }
+       $hash = $user_id . $site_id . 'get_access_list';
 
-       $access = "(" . implode(",", get_access_array($user_id, $site_id, $flush)) . ")";
+       if ($cache[$hash]) {
+               return $cache[$hash];
+       }
+       
+       $access_array = get_access_array($user_id, $site_id, $flush);
+       $access = "(" . implode(",", $access_array) . ")";
 
-       // only cache if done with init and access is enabled (unless admin user)
-       // session is loaded before init is finished, so don't need to check for user session
-       if ($init_finished && (elgg_is_admin_logged_in() || !elgg_get_ignore_access())) {
-               $access_list[$user_id] = $access;
-               return $access_list[$user_id];
-       } else {
-               return $access;
+       if ($init_finished) {
+               $cache[$hash] = $access;
        }
+       
+       return $access;
 }
 
 /**
@@ -86,9 +106,11 @@ function get_access_list($user_id = 0, $site_id = 0, $flush = false) {
 function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
        global $CONFIG, $init_finished;
 
-       // @todo everything from the db is cached.
-       // this cache might be redundant. But db cache is flushed on every db write.
-       static $access_array = array();
+       $cache = _elgg_get_access_cache();
+
+       if ($flush) {
+               $cache->clear();
+       }
 
        if ($user_id == 0) {
                $user_id = elgg_get_logged_in_user_guid();
@@ -101,35 +123,41 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
        $user_id = (int) $user_id;
        $site_id = (int) $site_id;
 
-       if (empty($access_array[$user_id]) || $flush == true) {
-               $tmp_access_array = array(ACCESS_PUBLIC);
+       $hash = $user_id . $site_id . 'get_access_array';
+
+       if ($cache[$hash]) {
+               $access_array = $cache[$hash];
+       } else {
+               $access_array = array(ACCESS_PUBLIC);
 
                // The following can only return sensible data if the user is logged in.
                if (elgg_is_logged_in()) {
-                       $tmp_access_array[] = ACCESS_LOGGED_IN;
+                       $access_array[] = ACCESS_LOGGED_IN;
 
                        // Get ACL memberships
                        $query = "SELECT am.access_collection_id"
                                . " FROM {$CONFIG->dbprefix}access_collection_membership am"
                                . " LEFT JOIN {$CONFIG->dbprefix}access_collections ag ON ag.id = am.access_collection_id"
-                               . " WHERE am.user_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
+                               . " WHERE am.user_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)";
 
-                       if ($collections = get_data($query)) {
+                       $collections = get_data($query);
+                       if ($collections) {
                                foreach ($collections as $collection) {
                                        if (!empty($collection->access_collection_id)) {
-                                               $tmp_access_array[] = (int)$collection->access_collection_id;
+                                               $access_array[] = (int)$collection->access_collection_id;
                                        }
                                }
                        }
 
                        // Get ACLs owned.
                        $query = "SELECT ag.id FROM {$CONFIG->dbprefix}access_collections ag ";
-                       $query .= "WHERE ag.owner_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
+                       $query .= "WHERE ag.owner_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)";
 
-                       if ($collections = get_data($query)) {
+                       $collections = get_data($query);
+                       if ($collections) {
                                foreach ($collections as $collection) {
                                        if (!empty($collection->id)) {
-                                               $tmp_access_array[] = (int)$collection->id;
+                                               $access_array[] = (int)$collection->id;
                                        }
                                }
                        }
@@ -137,21 +165,21 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
                        $ignore_access = elgg_check_access_overrides($user_id);
 
                        if ($ignore_access == true) {
-                               $tmp_access_array[] = ACCESS_PRIVATE;
+                               $access_array[] = ACCESS_PRIVATE;
                        }
+               }
 
-                       // only cache if done with init and access is enabled (unless admin user)
-                       // session is loaded before init is finished, so don't need to check for user session
-                       if ($init_finished && (elgg_is_admin_logged_in() || !elgg_get_ignore_access())) {
-                               $access_array[$user_id] = $tmp_access_array;
-                       }
+               if ($init_finished) {
+                       $cache[$hash] = $access_array;
                }
-       } else {
-               $tmp_access_array = $access_array[$user_id];
        }
 
-       $options = array('user_id' => $user_id, 'site_id' => $site_id);
-       return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $tmp_access_array);
+       $options = array(
+               'user_id' => $user_id,
+               'site_id' => $site_id
+       );
+       
+       return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $access_array);
 }
 
 /**
@@ -397,9 +425,12 @@ function has_access_to_entity($entity, $user = null) {
  * @link http://docs.elgg.org/Access
  */
 function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
-       global $CONFIG;
-       //@todo this is probably not needed since caching happens at the DB level.
-       static $access_array;
+       global $CONFIG, $init_finished;
+       $cache = _elgg_get_access_cache();
+
+       if ($flush) {
+               $cache->clear();
+       }
 
        if ($user_id == 0) {
                $user_id = elgg_get_logged_in_user_guid();
@@ -412,37 +443,41 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
        $user_id = (int) $user_id;
        $site_id = (int) $site_id;
 
-       if (empty($access_array[$user_id]) || $flush == true) {
-               $query = "SELECT ag.* FROM {$CONFIG->dbprefix}access_collections ag ";
-               $query .= " WHERE (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
-               $query .= " AND (ag.owner_guid = {$user_id})";
-               // ACCESS_PRIVATE through ACCESS_PUBLIC take 0 through 2
-               // @todo this AND clause is unnecessary because of id starts at 3 for table
-               $query .= " AND ag.id >= 3";
+       $hash = $user_id . $site_id . 'get_write_access_array';
 
-               $tmp_access_array = array(
+       if ($cache[$hash]) {
+               $access_array = $cache[$hash];
+       } else {
+               // @todo is there such a thing as public write access?
+               $access_array = array(
                        ACCESS_PRIVATE => elgg_echo("PRIVATE"),
                        ACCESS_FRIENDS => elgg_echo("access:friends:label"),
                        ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"),
                        ACCESS_PUBLIC => elgg_echo("PUBLIC")
                );
+               
+               $query = "SELECT ag.* FROM {$CONFIG->dbprefix}access_collections ag ";
+               $query .= " WHERE (ag.site_guid = $site_id OR ag.site_guid = 0)";
+               $query .= " AND (ag.owner_guid = $user_id)";
+
                $collections = get_data($query);
                if ($collections) {
                        foreach ($collections as $collection) {
-                               $tmp_access_array[$collection->id] = $collection->name;
+                               $access_array[$collection->id] = $collection->name;
                        }
                }
 
-               $access_array[$user_id] = $tmp_access_array;
-       } else {
-               $tmp_access_array = $access_array[$user_id];
+               if ($init_finished) {
+                       $cache[$hash] = $access_array;
+               }
        }
 
-       $options = array('user_id' => $user_id, 'site_id' => $site_id);
-       $tmp_access_array = elgg_trigger_plugin_hook('access:collections:write', 'user',
-               $options, $tmp_access_array);
-
-       return $tmp_access_array;
+       $options = array(
+               'user_id' => $user_id,
+               'site_id' => $site_id
+       );
+       return elgg_trigger_plugin_hook('access:collections:write', 'user',
+               $options, $access_array);
 }
 
 /**
@@ -871,6 +906,8 @@ function get_readable_access_level($entity_access_id) {
  * @tip Use this to access entities in automated scripts
  * when no user is logged in.
  *
+ * @note This clears the access cache.
+ *
  * @warning This will not show disabled entities.
  * Use {@link access_show_hidden_entities()} to access disabled entities.
  *
@@ -882,6 +919,8 @@ function get_readable_access_level($entity_access_id) {
  * @see elgg_get_ignore_access()
  */
 function elgg_set_ignore_access($ignore = true) {
+       $cache = _elgg_get_access_cache();
+       $cache->clear();
        $elgg_access = elgg_get_access_object();
        return $elgg_access->setIgnoreAccess($ignore);
 }
index bea995a6e9eade52216e073cacd20d7efdd36469..ebcd7d318da7971a71b6f7589414af355476ef38 100644 (file)
@@ -268,4 +268,26 @@ class ElggCoreAccessCollectionsTest extends ElggCoreUnitTest {
 
                $group->delete();
        }
+
+       public function testAccessCaching() {
+               // create a new user to check against
+               $user = new ElggUser();
+               $user->username = 'access_test_user';
+               $user->save();
+
+               foreach (array('get_access_list', 'get_access_array') as $func) {
+                       $cache = _elgg_get_access_cache();
+                       $cache->clear();
+
+                       // admin users run tests, so disable access
+                       elgg_set_ignore_access(true);
+                       $access = $func($user->getGUID());
+
+                       elgg_set_ignore_access(false);
+                       $access2 = $func($user->getGUID());
+                       $this->assertNotEqual($access, $access2, "Access test for $func");
+               }
+
+               $user->delete();        
+       }
 }