Revert "Revert "Cleanup registry caching." This caused registry methods not to be...
authorMichael M Slusarz <slusarz@curecanti.org>
Mon, 20 Dec 2010 04:31:59 +0000 (21:31 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Mon, 20 Dec 2010 04:31:59 +0000 (21:31 -0700)
This reverts commit 3be8781b0fc7bc17f52b2a65adedd0198a780e5a.

framework/Core/lib/Horde/Registry.php
horde/admin/config/config.php
horde/admin/config/index.php
horde/admin/config/scripts.php

index b119f5c..7acfd07 100644 (file)
@@ -57,18 +57,18 @@ class Horde_Registry
     protected $_appStack = array();
 
     /**
-     * The list of APIs.
+     * The list of external services.
      *
-     * @param array
+     * @var array
      */
-    protected $_apis = array();
+    protected $_apis;
 
     /**
-     * Cached information.
+     * The list of APIs.
      *
      * @var array
      */
-    protected $_cache = array();
+    protected $_apiList = array();
 
     /**
      * Cached configuration information.
@@ -77,6 +77,19 @@ class Horde_Registry
      */
     protected $_confCache = array();
 
+    /**
+     * Interfaces list.
+     *
+     * @var array
+     */
+    protected $_interfaces = array();
+
+    /**
+     * Object (Application/Api) cache.
+     *
+     * @var array
+     */
+    protected $_obCache = array();
 
     /**
      * The last modified time of the newest modified registry file.
@@ -86,11 +99,11 @@ class Horde_Registry
     protected $_regmtime;
 
     /**
-     * The list of cache entries to save on shutdown.
+     * The current vhost configuration file.
      *
-     * @var array
+     * @var string
      */
-    protected $_savecache = array();
+    protected $_vhost = null;
 
     /**
      * Application bootstrap initialization.
@@ -319,7 +332,7 @@ class Horde_Registry
         }
 
         $GLOBALS['registry'] = $this;
-        $injector->setInstance('Horde_Registry', $this);
+        $injector->setInstance(__CLASS__, $this);
 
         /* Setup autoloader instance and callbacks.
          * $__autoloader is defined in horde/lib/core.php */
@@ -358,13 +371,12 @@ class Horde_Registry
         $this->_regmtime = max(filemtime(HORDE_BASE . '/config/registry.php'),
                                filemtime(HORDE_BASE . '/config/registry.d'));
 
-        $vhost = null;
         if (!empty($conf['vhosts'])) {
-            $vhost = HORDE_BASE . '/config/registry-' . $conf['server']['name'] . '.php';
-            if (file_exists($vhost)) {
-                $this->_regmtime = max($this->_regmtime, filemtime($vhost));
+            $this->_vhost = HORDE_BASE . '/config/registry-' . $conf['server']['name'] . '.php';
+            if (file_exists($this->_vhost)) {
+                $this->_regmtime = max($this->_regmtime, filemtime($this->_vhost));
             } else {
-                $vhost = null;
+                $this->_vhost = null;
             }
         }
 
@@ -388,7 +400,7 @@ class Horde_Registry
         $injector->setInstance('Horde_Session', $session);
 
         /* Always need to load applications information. */
-        $this->_loadApplicationsCache($vhost);
+        $this->_loadApplications();
 
         /* Load the language configuration. */
         $this->nlsconfig = Horde::loadConfiguration('nls.php', 'horde_nls_config', 'horde');
@@ -421,27 +433,6 @@ class Horde_Registry
      */
     public function shutdown()
     {
-        /* Store cache entries to persistent storage. */
-        if (!empty($this->_savecache)) {
-            $ob = $GLOBALS['injector']->getInstance('Horde_Cache');
-
-            foreach ($this->_savecache as $key => $val) {
-                if ($val) {
-                    // Entry has been updated.
-                    $data = serialize($this->_cache[$key]);
-                    $md5sum = hash('md5', $data);
-                    $GLOBALS['session']->set('horde', 'registry/' . $key, $md5sum);
-                    $id = $this->_getCacheId($key, false) . '|' . $md5sum;
-                    if ($ob->set($id, $data, 86400)) {
-                        Horde::logMessage('Horde_Registry: stored ' . $key . ' with cache ID ' . $id, 'DEBUG');
-                    }
-                } elseif ($id = $this->_getCacheId($key)) {
-                    // Entry has been deleted.
-                    $ob->expire($id);
-                }
-            }
-        }
-
         /* Register access key logger for translators. */
         if (!empty($GLOBALS['conf']['log_accesskeys'])) {
             Horde::getAccessKey(null, null, true);
@@ -470,7 +461,7 @@ class Horde_Registry
      */
     public function __clone()
     {
-        throw new Horde_Exception('Horde_Registry objects should never be cloned.');
+        throw new Horde_Exception('Registry objects should never be cloned.');
     }
 
     /**
@@ -480,36 +471,40 @@ class Horde_Registry
      */
     public function __sleep()
     {
-        throw new Horde_Exception('Horde_Registry objects should never be serialized.');
+        throw new Horde_Exception('Registry objects should never be serialized.');
     }
 
     /**
-     * Clear the registry cache.
+     * Rebuild the registry configuration.
      */
-    public function clearCache()
+    public function rebuild()
     {
+        $app = $this->getApp();
+
+        $this->applications = $this->_apiList = $this->_apis = $this->_confCache = $this->_interfaces = array();
+
         $GLOBALS['session']->remove('horde', 'registry/');
-        $this->_cache = array();
-        $this->_savecache['api'] = false;
-        $this->_savecache['appcache'] = false;
+        $this->_saveCache('apis');
+        $this->_saveCache('app');
+
+        $this->_loadApplications();
+
+        $this->importConfig('horde');
+        $this->importConfig($app);
     }
 
     /**
-     * Fills the registry's application cache with application information.
-     *
-     * @param string $vhost  TODO
+     * Load application configuration information.
      */
-    protected function _loadApplicationsCache($vhost)
+    protected function _loadApplications()
     {
         /* First, try to load from cache. */
-        if ($this->_loadCache('appcache')) {
-            $this->applications = $this->_cache['appcache'][0];
-            $this->_cache['interfaces'] = $this->_cache['appcache'][1];
+        if ($ret = $this->_loadCache('app')) {
+            $this->applications = $ret[0];
+            $this->_interfaces = $ret[1];
             return;
         }
 
-        $this->_cache['interfaces'] = array();
-
         /* Read the registry configuration files. */
         if (!file_exists(HORDE_BASE . '/config/registry.php')) {
             throw new Horde_Exception('Missing registry.php configuration file');
@@ -520,8 +515,8 @@ class Horde_Registry
             include $r;
         }
 
-        if ($vhost) {
-            include $vhost;
+        if ($this->_vhost) {
+            include $this->_vhost;
         }
 
         /* Scan for all APIs provided by each app, and set other common
@@ -551,10 +546,10 @@ class Horde_Registry
                 (($app['status'] != 'admin') || $this->isAdmin())) {
                 if (is_array($app['provides'])) {
                     foreach ($app['provides'] as $interface) {
-                        $this->_cache['interfaces'][$interface] = $appName;
+                        $this->_interfaces[$interface] = $appName;
                     }
                 } else {
-                    $this->_cache['interfaces'][$app['provides']] = $appName;
+                    $this->_interfaces[$app['provides']] = $appName;
                 }
             }
 
@@ -575,24 +570,21 @@ class Horde_Registry
             }
         }
 
-        $this->_cache['appcache'] = array(
-            // Index 0
+        $this->_saveCache('app', array(
             $this->applications,
-            // Index 1
-            $this->_cache['interfaces']
-        );
-        $this->_savecache['appcache'] = true;
+            $this->_interfaces
+        ));
     }
 
     /**
-     * Fills the registry's API cache with the available external services.
+     * Load the list of available external services.
      *
      * @throws Horde_Exception
      */
-    protected function _loadApiCache()
+    protected function _loadApis()
     {
-        /* First, try to load from cache. */
-        if ($this->_loadCache('api')) {
+        if (isset($this->_apis) ||
+            ($this->_apis = $this->_loadCache('apis'))) {
             return;
         }
 
@@ -602,13 +594,13 @@ class Horde_Registry
             $status[] = 'admin';
         }
 
-        $this->_cache['api'] = array();
+        $this->_apis = array();
 
         foreach (array_keys($this->applications) as $app) {
             if (in_array($this->applications[$app]['status'], $status)) {
                 try {
                     $api = $this->getApiInstance($app, 'api');
-                    $this->_cache['api'][$app] = array(
+                    $this->_apis[$app] = array(
                         'api' => array_diff(get_class_methods($api), array('__construct'), $api->disabled),
                         'links' => $api->links,
                         'noperms' => $api->noPerms
@@ -619,7 +611,7 @@ class Horde_Registry
             }
         }
 
-        $this->_savecache['api'] = true;
+        $this->_saveCache('apis', $this->_api);
     }
 
     /**
@@ -633,8 +625,8 @@ class Horde_Registry
      */
     public function getApiInstance($app, $type)
     {
-        if (isset($this->_cache['ob'][$app][$type])) {
-            return $this->_cache['ob'][$app][$type];
+        if (isset($this->_obCache[$app][$type])) {
+            return $this->_obCache[$app][$type];
         }
 
         $cname = Horde_String::ucfirst($type);
@@ -646,15 +638,16 @@ class Horde_Registry
         if (file_exists($path)) {
             include_once $path;
         } else {
-            $classname = 'Horde_Registry_' . $cname;
+            $classname = __CLASS__ . '_' . $cname;
         }
 
         if (!class_exists($classname, false)) {
             throw new Horde_Exception("$app does not have an API");
         }
 
-        $this->_cache['ob'][$app][$type] = new $classname();
-        return $this->_cache['ob'][$app][$type];
+        $this->_obCache[$app][$type] = new $classname();
+
+        return $this->_obCache[$app][$type];
     }
 
     /**
@@ -712,16 +705,18 @@ class Horde_Registry
      */
     public function listAPIs()
     {
-        if (empty($this->_apis)) {
-            if (!empty($this->_cache['interfaces'])) {
-                foreach (array_keys($this->_cache['interfaces']) as $interface) {
-                    list($api,) = explode('/', $interface, 2);
-                    $this->_apis[$api] = true;
-                }
+        if (empty($this->_apiList) && !empty($this->_interfaces)) {
+            $apis = array();
+
+            foreach (array_keys($this->_interfaces) as $interface) {
+                list($api,) = explode('/', $interface, 2);
+                $apis[$api] = true;
             }
+
+            $this->_apiList = array_keys($apis);
         }
 
-        return array_keys($this->_apis);
+        return $this->_apiList;
     }
 
     /**
@@ -737,7 +732,7 @@ class Horde_Registry
     {
         $methods = array();
 
-        $this->_loadApiCache();
+        $this->_loadApis();
 
         foreach (array_keys($this->applications) as $app) {
             if (isset($this->applications[$app]['provides'])) {
@@ -745,17 +740,17 @@ class Horde_Registry
                 if (!is_array($provides)) {
                     $provides = array($provides);
                 }
+
                 foreach ($provides as $method) {
                     if (strpos($method, '/') !== false) {
                         if (is_null($api) ||
                             (substr($method, 0, strlen($api)) == $api)) {
                             $methods[$method] = true;
                         }
-                    } elseif (is_null($api) || ($method == $api)) {
-                        if (isset($this->_cache['api'][$app])) {
-                            foreach ($this->_cache['api'][$app]['api'] as $service) {
-                                $methods[$method . '/' . $service] = true;
-                            }
+                    } elseif (isset($this->_apis[$app]) &&
+                              (is_null($api) || ($method == $api))) {
+                        foreach ($this->_apis[$app]['api'] as $service) {
+                            $methods[$method . '/' . $service] = true;
                         }
                     }
                 }
@@ -775,8 +770,8 @@ class Horde_Registry
      */
     public function hasInterface($interface)
     {
-        return !empty($this->_cache['interfaces'][$interface]) ?
-            $this->_cache['interfaces'][$interface] :
+        return !empty($this->interfaces[$interface]) ?
+            $this->interfaces[$interface] :
             false;
     }
 
@@ -793,10 +788,10 @@ class Horde_Registry
     {
         if (is_null($app)) {
             list($interface, $call) = explode('/', $method, 2);
-            if (!empty($this->_cache['interfaces'][$method])) {
-                $app = $this->_cache['interfaces'][$method];
-            } elseif (!empty($this->_cache['interfaces'][$interface])) {
-                $app = $this->_cache['interfaces'][$interface];
+            if (!empty($this->interfaces[$method])) {
+                $app = $this->interfaces[$method];
+            } elseif (!empty($this->interfaces[$interface])) {
+                $app = $this->interfaces[$interface];
             } else {
                 return false;
             }
@@ -804,9 +799,9 @@ class Horde_Registry
             $call = $method;
         }
 
-        $this->_loadApiCache();
+        $this->_loadApis();
 
-        return (isset($this->_cache['api'][$app]) && in_array($call, $this->_cache['api'][$app]['api']))
+        return (isset($this->_apis[$app]) && in_array($call, $this->_apis[$app]['api']))
             ? $app
             : false;
     }
@@ -826,7 +821,9 @@ class Horde_Registry
         } catch (Horde_Exception $e) {
             return false;
         }
-        return (method_exists($appob, $method) && !in_array($method, $appob->disabled));
+
+        return (method_exists($appob, $method) &&
+                !in_array($method, $appob->disabled));
     }
 
     /**
@@ -845,10 +842,10 @@ class Horde_Registry
     {
         list($interface, $call) = explode('/', $method, 2);
 
-        if (!empty($this->_cache['interfaces'][$method])) {
-            $app = $this->_cache['interfaces'][$method];
-        } elseif (!empty($this->_cache['interfaces'][$interface])) {
-            $app = $this->_cache['interfaces'][$interface];
+        if (!empty($this->interfaces[$method])) {
+            $app = $this->interfaces[$method];
+        } elseif (!empty($this->interfaces[$interface])) {
+            $app = $this->interfaces[$interface];
         } else {
             throw new Horde_Exception('The method "' . $method . '" is not defined in the Horde Registry.');
         }
@@ -891,7 +888,7 @@ class Horde_Registry
         /* Switch application contexts now, if necessary, before
          * including any files which might do it for us. Return an
          * error immediately if pushApp() fails. */
-        $pushed = $this->pushApp($app, array('check_perms' => !in_array($call, $this->_cache['api'][$app]['noperms']) && empty($options['noperms'])));
+        $pushed = $this->pushApp($app, array('check_perms' => !in_array($call, $this->_apis[$app]['noperms']) && empty($options['noperms'])));
 
         try {
             $result = call_user_func_array(array($api, $call), $args);
@@ -977,10 +974,10 @@ class Horde_Registry
     {
         list($interface, $call) = explode('/', $method, 2);
 
-        if (!empty($this->_cache['interfaces'][$method])) {
-            $app = $this->_cache['interfaces'][$method];
-        } elseif (!empty($this->_cache['interfaces'][$interface])) {
-            $app = $this->_cache['interfaces'][$interface];
+        if (!empty($this->interfaces[$method])) {
+            $app = $this->interfaces[$method];
+        } elseif (!empty($this->interfaces[$interface])) {
+            $app = $this->interfaces[$interface];
         } else {
             throw new Horde_Exception('The method "' . $method . '" is not defined in the Horde Registry.');
         }
@@ -1002,13 +999,13 @@ class Horde_Registry
     public function linkByPackage($app, $call, $args = array(), $extra = '')
     {
         /* Make sure the link is defined. */
-        $this->_loadApiCache();
-        if (empty($this->_cache['api'][$app]['links'][$call])) {
+        $this->_loadApis();
+        if (empty($this->_apis[$app]['links'][$call])) {
             throw new Horde_Exception('The link ' . $call . ' is not defined in ' . $app . '\'s API.');
         }
 
         /* Initial link value. */
-        $link = $this->_cache['api'][$app]['links'][$call];
+        $link = $this->_apis[$app]['links'][$call];
 
         /* Fill in html-encoded arguments. */
         foreach ($args as $key => $val) {
@@ -1525,20 +1522,15 @@ class Horde_Registry
      *
      * @param string $name  Cache variable name.
      *
-     * @return boolean  True if value loaded from cache.
+     * @return mixed  The cached data or false if no data retrieved.
      */
     protected function _loadCache($name)
     {
-        if (isset($this->_cache[$name])) {
-            return true;
-        }
-
         if ($id = $this->_getCacheId($name)) {
             $result = $GLOBALS['injector']->getInstance('Horde_Cache')->get($id, 86400);
             if ($result !== false) {
-                $this->_cache[$name] = unserialize($result);
-                Horde::logMessage('Horde_Registry: retrieved ' . $name . ' with cache ID ' . $id, 'DEBUG');
-                return true;
+                Horde::logMessage(__CLASS__ . ': retrieved ' . $name . ' with cache ID ' . $id, 'DEBUG');
+                return unserialize($result);
             }
         }
 
@@ -1549,25 +1541,51 @@ class Horde_Registry
      * Get the cache storage ID for a particular cache name.
      *
      * @param string $name  Cache variable name.
-     * @param string $md5   Append MD5 value?
+     * @param string $md5   Use this MD5 value instead of session MD5 value.
      *
      * @return mixed  The cache ID or false if cache entry doesn't exist in
      *                the session.
      */
-    protected function _getCacheId($name, $md5 = true)
+    protected function _getCacheId($name, $md5 = null)
     {
-        $id = 'horde_registry_' . $name . '|' . $this->_regmtime;
+        $id = 'horde_registry|' . $name . '|' . $this->_regmtime;
 
-        if (!$md5) {
-            return $id;
-        } elseif ($hash = $GLOBALS['session']->get('horde', 'registry/' . $name)) {
-            return $id . '|' . $hash;
+        if (!is_null($md5) ||
+            ($md5 = $GLOBALS['session']->get('horde', 'registry/' . $name))) {
+            return $id . '|' . $md5;
         }
 
         return false;
     }
 
     /**
+     * Save a registry cache entry.
+     *
+     * @param string $key  The cache key.
+     * @param mixed $data  The cache data. If null, deletes the item.
+     */
+    protected function _saveCache($key, $data = null)
+    {
+        $ob = $GLOBALS['injector']->getInstance('Horde_Cache');
+
+        if (is_null($data)) {
+            if ($id = $this->_getCacheId($key)) {
+                // Entry has been deleted.
+                $ob->expire($id);
+            }
+        } else {
+            // Entry has been updated.
+            $data = serialize($data);
+            $md5sum = hash('md5', $data);
+            $GLOBALS['session']->set('horde', 'registry/' . $key, $md5sum);
+            $id = $this->_getCacheId($key, $md5sum);
+            if ($ob->set($id, $data, 86400)) {
+                Horde::logMessage(__CLASS__ . ': stored ' . $key . ' with cache ID ' . $id, 'DEBUG');
+            }
+        }
+    }
+
+    /**
      * Destroys any existing session on login and make sure to use a new
      * session ID, to avoid session fixation issues. Should be called before
      * checking a login.
@@ -2179,10 +2197,7 @@ class Horde_Registry
             if ($GLOBALS['language'] == $lang) {
                 return;
             }
-            $this->clearCache();
-            $this->_confCache = array();
-            $this->importConfig('horde');
-            $this->importConfig($this->getApp());
+            $changed = true;
         }
         $GLOBALS['language'] = $lang;
 
@@ -2191,6 +2206,10 @@ class Horde_Registry
         @putenv('LC_ALL=' . $lang_charset);
         @putenv('LANG=' . $lang_charset);
         @putenv('LANGUAGE=' . $lang_charset);
+
+        if ($changed) {
+            $this->rebuild();
+        }
     }
 
     /**
index e217d8b..e4c748c 100644 (file)
@@ -61,7 +61,7 @@ if (Horde_Util::getFormData('submitbutton') == _("Revert Configuration")) {
         fwrite($fp, $php);
         fclose($fp);
         $notification->push(sprintf(_("Successfully wrote %s"), Horde_Util::realPath($configFile)), 'horde.success');
-        $registry->clearCache();
+        $registry->rebuild();
         Horde::url('admin/config/index.php', true)->redirect();
     } else {
         /* Cannot write. */
index f764cbf..7abec06 100644 (file)
@@ -51,7 +51,9 @@ function _uploadFTP($params)
             $notification->push(sprintf(_("Could not write configuration for \"%s\": %s"), $app, $e->getMessage()), 'horde.error');
         }
     }
-    $registry->clearCache();
+
+    $registry->rebuild();
+
     return $no_errors;
 }
 
index 89ff4d3..b78b8b7 100644 (file)
@@ -34,7 +34,7 @@ if ($clean == 'tmp') {
     } else {
         $notification->push(sprintf(_("Could not delete configuration upgrade script \"%s\"."), Horde_Util::realPath($path)), 'horde.error');
     }
-    $registry->clearCache();
+    $registry->rebuild();
     Horde::url('admin/config/index.php', true)->redirect();
 }