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.
*/
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.
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.
}
$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 */
$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;
}
}
$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');
*/
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);
*/
public function __clone()
{
- throw new Horde_Exception('Horde_Registry objects should never be cloned.');
+ throw new Horde_Exception('Registry objects should never be cloned.');
}
/**
*/
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');
include $r;
}
- if ($vhost) {
- include $vhost;
+ if ($this->_vhost) {
+ include $this->_vhost;
}
/* Scan for all APIs provided by each app, and set other common
(($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;
}
}
}
}
- $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;
}
$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
}
}
- $this->_savecache['api'] = true;
+ $this->_saveCache('apis', $this->_api);
}
/**
*/
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);
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];
}
/**
*/
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;
}
/**
{
$methods = array();
- $this->_loadApiCache();
+ $this->_loadApis();
foreach (array_keys($this->applications) as $app) {
if (isset($this->applications[$app]['provides'])) {
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;
}
}
}
*/
public function hasInterface($interface)
{
- return !empty($this->_cache['interfaces'][$interface]) ?
- $this->_cache['interfaces'][$interface] :
+ return !empty($this->interfaces[$interface]) ?
+ $this->interfaces[$interface] :
false;
}
{
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;
}
$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;
}
} 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));
}
/**
{
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.');
}
/* 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);
{
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.');
}
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) {
*
* @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);
}
}
* 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.
if ($GLOBALS['language'] == $lang) {
return;
}
- $this->clearCache();
- $this->_confCache = array();
- $this->importConfig('horde');
- $this->importConfig($this->getApp());
+ $changed = true;
}
$GLOBALS['language'] = $lang;
@putenv('LC_ALL=' . $lang_charset);
@putenv('LANG=' . $lang_charset);
@putenv('LANGUAGE=' . $lang_charset);
+
+ if ($changed) {
+ $this->rebuild();
+ }
}
/**