<?php
/**
* $Horde: framework/Horde/Horde/Registry.php,v 1.332 2009/06/24 23:39:22 slusarz Exp $
*
* Copyright 1999-2009 The Horde Project (
http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see
http://www.fsf.org/copyleft/lgpl.html.
*
* @package Horde_Framework
*/
/**
* The Registry:: class provides a set of methods for communication
* between Horde applications and keeping track of application
* configuration information.
*
* @author Chuck Hagenbuch <
chuck@horde.org
* @author Jon Parise <
jon@horde.org
* @author Anil Madhavapeddy <
anil@recoil.org
* @author Michael Slusarz <
slusarz@horde.org
* @package Horde_Framework
*/
class Registry
{
/* Session flags. */
const SESSION_NONE = 1;
const SESSION_READONLY = 2;
/**
* Singleton value.
*
* @var Registry
*/
static protected $_instance;
/**
* Cached information.
*
* @var array
*/
protected $_cache = array();
/**
* The Horde_Cache object.
*
* @var Horde_Cache
*/
protected $_cacheob;
/**
* The last modified time of the newest modified registry file.
*
* @var integer
*/
protected $_regmtime;
/**
* Stack of in-use applications.
*
* @var array
*/
protected $_appStack = array();
/**
* The list of APIs.
*
* @param array
*/
protected $_apis = array();
/**
* Cached values of the image directories.
*
* @param array
*/
protected $_imgDir = array();
/**
* Hash storing information on each registry-aware application.
*
* @var array
*/
public $applications = array();
/**
* Returns a reference to the global Registry object, only creating it
* if it doesn't already exist.
*
* This method must be invoked as:
* $registry = &Registry::singleton()
*
* @param integer $session_flags Any session flags.
*
* @return Registry The Horde Registry instance.
*/
static public function singleton($session_flags = 0)
{
if (!isset(self::$_instance)) {
self::$_instance = new Registry($session_flags);
}
return self::$_instance;
}
/**
* Create a new Registry instance.
*
* @param integer $session_flags Any session flags.
*/
protected function __construct($session_flags = 0)
{
/* Import and global Horde's configuration values. */
$this->_cache['conf-horde'] = Horde::loadConfiguration('conf.php', 'conf', 'horde');
if (is_a($this->_cache['conf-horde'], 'PEAR_Error')) {
return $this->_cache['conf-horde'];
}
$conf = $GLOBALS['conf'] = &$this->_cache['conf-horde'];
/* Initial Horde-wide settings. */
/* Set the maximum execution time in accordance with the config
* settings. */
error_reporting(0);
set_time_limit($conf['max_exec_time']);
/* Set the error reporting level in accordance with the config
* settings. */
error_reporting($conf['debug_level']);
/* Set the umask according to config settings. */
if (isset($conf['umask'])) {
umask($conf['umask']);
}
/* Start a session. */
if ($session_flags & self::SESSION_NONE) {
/* Never start a session if the session flags include
SESSION_NONE. */
$_SESSION = array();
} else {
Horde::setupSessionHandler();
$old_error = error_reporting(0);
session_start();
if ($session_flags & self::SESSION_READONLY) {
/* Close the session immediately so no changes can be
made but values are still available. */
session_write_close();
}
error_reporting($old_error);
if (!isset($_SESSION['_registry'])) {
$_SESSION['_registry'] = array();
}
}
/* Initialize the localization routines and variables. We can't use
* NLS::setLanguageEnvironment() here because that depends on the
* registry to be already initialized. */
NLS::setLang();
NLS::setTextdomain('horde', HORDE_BASE . '/locale', NLS::getCharset());
Horde_String::setDefaultCharset(NLS::getCharset());
/* Check for caching availability. Using cache while not authenticated
* isn't possible because, although storage is possible, retrieval
* isn't since there is no MD5 sum in the session to use to build
* the cache IDs. */
if (Auth::getAuth()) {
try {
$this->_cacheob = Horde_Cache::singleton($conf['cache']['driver'], Horde::getDriverConfig('cache', $conf['cache']['driver']));
} catch (Horde_Exception $e) {}
}
$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));
} else {
$vhost = null;
}
}
/* Always need to load applications information. */
$this->_loadApplicationsCache($vhost);
/* Stop system if Horde is inactive. */
if ($this->applications['horde']['status'] == 'inactive') {
Horde::fatal(_("This system is currently deactivated."), __FILE__, __LINE__);
}
/* Create the global Perms object. */
$GLOBALS['perms'] = &Perms::singleton();
/* Attach javascript notification listener. */
$notification = &Horde_Notification::singleton();
$notification->attach('javascript');
}
/**
* Stores cacheable member variables in the session at shutdown.
*/
public function __destruct()
{
/* Register access key logger for translators. */
if (!empty($GLOBALS['conf']['log_accesskeys'])) {
Horde::getAccessKey(null, null, true);
}
/* Register memory tracker if logging in debug mode. */
if (!empty($GLOBALS['conf']['log']['enabled']) &&
($GLOBALS['conf']['log']['priority'] == PEAR_LOG_DEBUG) &&
function_exists('memory_get_peak_usage')) {
Horde::logMessage('Max memory usage: ' . memory_get_peak_usage(true) . ' bytes', __FILE__, __LINE__, PEAR_LOG_DEBUG);
}
}
/**
* TODO
*/
public function __get($api)
{
if (in_array($api, $this->listAPIs())) {
return new RegistryCaller($this, $api);
}
}
/**
* Clone should never be called on Registry objects. If it is, die.
*/
public function __clone()
{
Horde::fatal('Registry objects should never be cloned.', __FILE__, __LINE__);
}
/**
* Clear the registry cache.
*/
public function clearCache()
{
unset($_SESSION['_registry']);
$this->_saveCacheVar('apicache', true);
$this->_saveCacheVar('appcache', true);
}
/**
* Fills the registry's application cache with application information.
*
* @param string $vhost TODO
*/
protected function _loadApplicationsCache($vhost)
{
/* First, try to load from cache. */
if ($this->_loadCacheVar('appcache')) {
$this->applications = $this->_cache['appcache'][0];
$this->_cache['interfaces'] = $this->_cache['appcache'][1];
return;
}
$this->_cache['interfaces'] = array();
/* Read the registry configuration files. */
require HORDE_BASE . '/config/registry.php';
$files = glob(HORDE_BASE . '/config/registry.d/*.php');
if ($files) {
foreach ($files as $r) {
include $r;
}
}
if ($vhost) {
include $vhost;
}
/* Scan for all APIs provided by each app, and set other common
* defaults like templates and graphics. */
foreach (array_keys($this->applications) as $appName) {
$app = &$this->applications[$appName];
if ($app['status'] == 'heading') {
continue;
}
if (isset($app['fileroot']) && !file_exists($app['fileroot'])) {
$app['status'] = 'inactive';
}
if (($app['status'] != 'inactive') &&
isset($app['provides']) &&
(($app['status'] != 'admin') || Auth::isAdmin())) {
if (is_array($app['provides'])) {
foreach ($app['provides'] as $interface) {
$this->_cache['interfaces'][$interface] = $appName;
}
} else {
$this->_cache['interfaces'][$app['provides']] = $appName;
}
}
if (!isset($app['templates']) && isset($app['fileroot'])) {
$app['templates'] = $app['fileroot'] . '/templates';
}
if (!isset($app['jsuri']) && isset($app['webroot'])) {
$app['jsuri'] = $app['webroot'] . '/js';
}
if (!isset($app['jsfs']) && isset($app['fileroot'])) {
$app['jsfs'] = $app['fileroot'] . '/js';
}
if (!isset($app['themesuri']) && isset($app['webroot'])) {
$app['themesuri'] = $app['webroot'] . '/themes';
}
if (!isset($app['themesfs']) && isset($app['fileroot'])) {
$app['themesfs'] = $app['fileroot'] . '/themes';
}
}
$this->_cache['appcache'] = array(
// Index 0
$this->applications,
// Index 1
$this->_cache['interfaces']
);
$this->_saveCacheVar('appcache');
}
/**
* Fills the registry's API cache with the available services and types.
*/
protected function _loadApiCache()
{
/* First, try to load from cache. */
if ($this->_loadCacheVar('apicache')) {
$this->_cache['api'] = $this->_cache['apicache'][0];
$this->_cache['type'] = $this->_cache['apicache'][1];
return;
}
/* Generate api/type cache. */
$status = array('active', 'notoolbar', 'hidden');
if (Auth::isAdmin()) {
$status[] = 'admin';
}
$this->_cache['api'] = $this->_cache['type'] = array();
$apps = $this->listApps($status);
foreach ($apps as $app) {
$_services = $_types = null;
$api = $this->get('fileroot', $app) . '/lib/api.php';
if (is_readable($api)) {
include_once $api;
}
$this->_cache['api'][$app] = $_services;
if (!is_null($_types)) {
foreach ($_types as $type => $params) {
/* Prefix non-Horde types with the application name. */
$prefix = ($app == 'horde') ? '' : "${app}_";
$this->_cache['type'][$prefix . $type] = $params;
}
}
}
$this->_cache['apicache'] = array(
// Index 0
$this->_cache['api'],
// Index 1
$this->_cache['type']
);
$this->_saveCacheVar('apicache');
}
/**
* Return a list of the installed and registered applications.
*
* @param array $filter An array of the statuses that should be
* returned. Defaults to non-hidden.
* @param boolean $assoc Associative array with app names as keys.
* @param integer $perms The permission level to check for in the list.
*
* @return array List of apps registered with Horde. If no
* applications are defined returns an empty array.
*/
public function listApps($filter = null, $assoc = false,
$perms = PERMS_SHOW)
{
$apps = array();
$ahandler = defined('AUTH_HANDLER');
if (is_null($filter)) {
$filter = array('notoolbar', 'active');
}
foreach ($this->applications as $app => $params) {
if (in_array($params['status'], $filter) &&
($ahandler || $this->hasPermission($app, $perms))) {
$apps[$app] = $app;
}
}
return $assoc ? $apps : array_values($apps);
}
/**
* Returns all available registry APIs.
*
* @return array The API list.
*/
public function listAPIs()
{
if (empty($this->_apis)) {
foreach (array_keys($this->_cache['interfaces']) as $interface) {
list($api,) = explode('/', $interface, 2);
$this->_apis[$api] = true;
}
}
return array_keys($this->_apis);
}
/**
* Returns all of the available registry methods, or alternately
* only those for a specified API.
*
* @param string $api Defines the API for which the methods shall be
* returned.
*
* @return array The method list.
*/
public function listMethods($api = null)
{
$methods = array();
$this->_loadApiCache();
foreach (array_keys($this->applications) as $app) {
if (isset($this->applications[$app]['provides'])) {
$provides = $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 (array_keys($this->_cache['api'][$app]) as $service) {
$methods[$method . '/' . $service] = true;
}
}
}
}
}
}
return array_keys($methods);
}
/**
* Returns all of the available registry data types.
*
* @return array The data type list.
*/
public function listTypes()
{
$this->_loadApiCache();
return $this->_cache['type'];
}
/**
* Returns a method's signature.
*
* @param string $method The full name of the method to check for.
*
* @return array A two dimensional array. The first element contains an
* array with the parameter names, the second one the return
* type.
*/
public function getSignature($method)
{
if (!($app = $this->hasMethod($method))) {
return false;
}
$this->_loadApiCache();
list(,$function) = explode('/', $method, 2);
if (!empty($function) &&
isset($this->_cache['api'][$app][$function]['type']) &&
isset($this->_cache['api'][$app][$function]['args'])) {
return array($this->_cache['api'][$app][$function]['args'], $this->_cache['api'][$app][$function]['type']);
}
return false;
}
/**
* Determine if an interface is implemented by an active application.
*
* @param string $interface The interface to check for.
*
* @return mixed The application implementing $interface if we have it,
* false if the interface is not implemented.
*/
public function hasInterface($interface)
{
return !empty($this->_cache['interfaces'][$interface]) ?
$this->_cache['interfaces'][$interface] :
false;
}
/**
* Determine if a method has been registered with the registry.
*
* @param string $method The full name of the method to check for.
* @param string $app Only check this application.
*
* @return mixed The application implementing $method if we have it,
* false if the method doesn't exist.
*/
public function hasMethod($method, $app = null)
{
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];
} else {
return false;
}
} else {
$call = $method;
}
$this->_loadApiCache();
return empty($this->_cache['api'][$app][$call]) ? false : $app;
}
/**
* Return the hook corresponding to the default package that
* provides the functionality requested by the $method
* parameter. $method is a string consisting of
* "packagetype/methodname".
*
* @param string $method The method to call.
* @param array $args Arguments to the method.
*
* @return TODO
* Returns PEAR_Error on error.
*/
public function call($method, $args = array())
{
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];
} else {
return PEAR::raiseError('The method "' . $method . '" is not defined in the Horde Registry.');
}
return $this->callByPackage($app, $call, $args);
}
/**
* Output the hook corresponding to the specific package named.
*
* @param string $app The application being called.
* @param string $call The method to call.
* @param array $args Arguments to the method.
*
* @return TODO
* Returns PEAR_Error on error.
*/
public function callByPackage($app, $call, $args = array())
{
/* Note: calling hasMethod() makes sure that we've cached
* $app's services and included the API file, so we don't try
* to do it again explicitly in this method. */
if (!$this->hasMethod($call, $app)) {
return PEAR::raiseError(sprintf('The method "%s" is not defined in the API for %s.', $call, $app));
}
/* Load the API now. */
$api = $this->get('fileroot', $app) . '/lib/api.php';
if (is_readable($api)) {
include_once $api;
}
/* Make sure that the function actually exists. */
$function = '_' . $app . '_' . str_replace('/', '_', $call);
if (!function_exists($function)) {
return PEAR::raiseError('The function implementing ' . $call . ' (' . $function . ') is not defined in ' . $app . '\'s API.');
}
$checkPerms = isset($this->_cache['api'][$app][$call]['checkperms'])
? $this->_cache['api'][$app][$call]['checkperms']
: true;
/* 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, $checkPerms);
if (is_a($pushed, 'PEAR_Error')) {
return $pushed;
}
$res = call_user_func_array($function, $args);
/* If we changed application context in the course of this
* call, undo that change now. */
if ($pushed === true) {
$this->popApp();
}
return $res;
}
/**
* Return the hook corresponding to the default package that
* provides the functionality requested by the $method
* parameter. $method is a string consisting of
* "packagetype/methodname".
*
* @param string $method The method to link to.
* @param array $args Arguments to the method.
* @param mixed $extra Extra, non-standard arguments to the method.
*
* @return TODO
* Returns PEAR_Error on error.
*/
public function link($method, $args = array(), $extra = '')
{
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];
} else {
return PEAR::raiseError('The method "' . $method . '" is not defined in the Horde Registry.');
}
return $this->linkByPackage($app, $call, $args, $extra);
}
/**
* Output the hook corresponding to the specific package named.
*
* @param string $app The application being called.
* @param string $call The method to link to.
* @param array $args Arguments to the method.
* @param mixed $extra Extra, non-standard arguments to the method.
*
* @return TODO
* Returns PEAR_Error on error.
*/
public function linkByPackage($app, $call, $args = array(), $extra = '')
{
/* Note: calling hasMethod makes sure that we've cached $app's
* services and included the API file, so we don't try to do
* it it again explicitly in this method. */
if (!$this->hasMethod($call, $app)) {
return PEAR::raiseError('The method "' . $call . '" is not defined in ' . $app . '\'s API.');
}
/* Make sure the link is defined. */
$this->_loadApiCache();
if (empty($this->_cache['api'][$app][$call]['link'])) {
return PEAR::raiseError('The link ' . $call . ' is not defined in ' . $app . '\'s API.');
}
/* Initial link value. */
$link = $this->_cache['api'][$app][$call]['link'];
/* Fill in html-encoded arguments. */
foreach ($args as $key => $val) {
$link = str_replace('%' . $key . '%', htmlentities($val), $link);
}
if (isset($this->applications[$app]['webroot'])) {
$link = str_replace('%application%', $this->get('webroot', $app), $link);
}
/* Replace htmlencoded arguments that haven't been specified with
an empty string (this is where the default would be substituted
in a stricter registry implementation). */
$link = preg_replace('|%.+%|U', '', $link);
/* Fill in urlencoded arguments. */
foreach ($args as $key => $val) {
$link = str_replace('|' . Horde_String::lower($key) . '|', urlencode($val), $link);
}
/* Append any extra, non-standard arguments. */
if (is_array($extra)) {
$extra_args = '';
foreach ($extra as $key => $val) {
$extra_args .= '&' . urlencode($key) . '=' . urlencode($val);
}
} else {
$extra_args = $extra;
}
$link = str_replace('|extra|', $extra_args, $link);
/* Replace html-encoded arguments that haven't been specified with
an empty string (this is where the default would be substituted
in a stricter registry implementation). */
$link = preg_replace('|\|.+\||U', '', $link);
return $link;
}
/**
* Replace any %application% strings with the filesystem path to the
* application.
*
* @param string $path The application string.
* @param string $app The application being called.
*
* @return TODO
* Returns PEAR_Error on error.
*/
public function applicationFilePath($path, $app = null)
{
if (is_null($app)) {
$app = $this->getApp();
}
if (!isset($this->applications[$app])) {
return PEAR::raiseError(sprintf(_("\"%s\" is not configured in the Horde Registry."), $app));
}
return str_replace('%application%', $this->applications[$app]['fileroot'], $path);
}
/**
* Replace any %application% strings with the web path to the application.
*
* @param string $path The application string.
* @param string $app The application being called.
*
* @return TODO
* Returns PEAR_Error on error.
*/
public function applicationWebPath($path, $app = null)
{
if (!isset($app)) {
$app = $this->getApp();
}
return str_replace('%application%', $this->applications[$app]['webroot'], $path);
}
/**
* Set the current application, adding it to the top of the Horde
* application stack. If this is the first application to be
* pushed, retrieve session information as well.
*
* pushApp() also reads the application's configuration file and
* sets up its global $conf hash.
*
* @param string $app The name of the application to push.
* @param boolean $checkPerms Make sure that the current user has
* permissions to the application being loaded
* Defaults to true. Should ONLY be disabled
* by system scripts (cron jobs, etc.) and
* scripts that handle login.
*
* @return boolean Whether or not the _appStack was modified.
* Return PEAR_Error on error.
*/
public function pushApp($app, $checkPerms = true)
{
if ($app == $this->getApp()) {
return false;
}
/* Bail out if application is not present or inactive. */
if (!isset($this->applications[$app]) ||
$this->applications[$app]['status'] == 'inactive' ||
($this->applications[$app]['status'] == 'admin' && !Auth::isAdmin())) {
Horde::fatal($app . ' is not activated', __FILE__, __LINE__);
}
/* If permissions checking is requested, return an error if the
* current user does not have read perms to the application being
* loaded. We allow access:
*
* - To all admins.
* - To all authenticated users if no permission is set on $app.
* - To anyone who is allowed by an explicit ACL on $app. */
if ($checkPerms && !$this->hasPermission($app)) {
Horde::logMessage(sprintf('%s does not have READ permission for %s', Auth::getAuth() ? 'User ' . Auth::getAuth() : 'Guest user', $app), __FILE__, __LINE__, PEAR_LOG_DEBUG);
return PEAR::raiseError(sprintf(_('%s is not authorised for %s.'), Auth::getAuth() ? 'User ' . Auth::getAuth() : 'Guest user', $this->applications[$app]['name']), 'permission_denied');
}
/* Set up autoload paths for the current application. This needs to
* be done here because it is possible to try to load app-specific
* libraries from other applications. */
$app_lib = $this->get('fileroot', $app) . '/lib';
Horde_Autoloader::addClassPath($app_lib);
Horde_Autoloader::addClassPattern('/^' . $app . '_/i', $app_lib);
/* Chicken and egg problem: the language environment has to be loaded
* before loading the configuration file, because it might contain
* gettext strings. Though the preferences can specify a different
* language for this app, the have to be loaded after the
* configuration, because they rely on configuration settings. So try
* with the current language, and reset the language later. */
NLS::setLanguageEnvironment($GLOBALS['language'], $app);
/* Import this application's configuration values. */
$success = $this->importConfig($app);
if (is_a($success, 'PEAR_Error')) {
return $success;
}
/* Load preferences after the configuration has been loaded to make
* sure the prefs file has all the information it needs. */
$this->loadPrefs($app);
/* Reset the language in case there is a different one selected in the
* preferences. */
$language = '';
if (isset($GLOBALS['prefs'])) {
$language = $GLOBALS['prefs']->getValue('language');
if ($language != $GLOBALS['language']) {
NLS::setLanguageEnvironment($language, $app);
}
}
/* Once we know everything succeeded and is in a consistent state
* again, push the new application onto the stack. */
$this->_appStack[] = $app;
/* Call post-push hook. */
Horde::callHook('_horde_hook_post_pushapp', array($app), 'horde', null);
return true;
}
/**
* Remove the current app from the application stack, setting the current
* app to whichever app was current before this one took over.
*
* @return string The name of the application that was popped.
*/
public function popApp()
{
/* Pop the current application off of the stack. */
$previous = array_pop($this->_appStack);
/* Import the new active application's configuration values
* and set the gettext domain and the preferred language. */
$app = $this->getApp();
if ($app) {
$this->importConfig($app);
$this->loadPrefs($app);
$language = $GLOBALS['prefs']->getValue('language');
NLS::setLanguageEnvironment($language, $app);
}
return $previous;
}
/**
* Return the current application - the app at the top of the application
* stack.
*
* @return string The current application.
*/
public function getApp()
{
return end($this->_appStack);
}
/**
* Check permissions on an application.
*
* @param string $app The name of the application
* @param integer $perms The permission level to check for.
*
* @return boolean Whether access is allowed.
*/
public function hasPermission($app, $perms = PERMS_READ)
{
return Auth::isAdmin() ||
($GLOBALS['perms']->exists($app)
? $GLOBALS['perms']->hasPermission($app, Auth::getAuth(), $perms)
: (bool)Auth::getAuth());
}
/**
* Reads the configuration values for the given application and imports
* them into the global $conf variable.
*
* @param string $app The name of the application.
*
* @return boolean True on success, PEAR_Error on error.
*/
public function importConfig($app)
{
if (($app != 'horde') &&
!$this->_loadCacheVar('conf-' . $app)) {
$success = Horde::loadConfiguration('conf.php', 'conf', $app);
if (is_a($success, 'PEAR_Error')) {
return $success;
}
$this->_cache['conf-' . $app] = Horde_Array::array_merge_recursive_overwrite($this->_cache['conf-horde'], $success);
$this->_saveCacheVar('conf-' . $app);
}
$GLOBALS['conf'] = &$this->_cache['conf-' . $app];
return true;
}
/**
* Loads the preferences for the current user for the current application
* and imports them into the global $prefs variable.
*
* @param string $app The name of the application.
*/
public function loadPrefs($app = null)
{
require_once 'Horde/Prefs.php';
if (is_null($app)) {
$app = $this->getApp();
}
/* If there is no logged in user, return an empty Prefs::
* object with just default preferences. */
if (!Auth::getAuth()) {
$GLOBALS['prefs'] = &Prefs::factory('session', $app, '', '', null, false);
} else {
if (!isset($GLOBALS['prefs']) || $GLOBALS['prefs']->getUser() != Auth::getAuth()) {
$GLOBALS['prefs'] = &Prefs::factory($GLOBALS['conf']['prefs']['driver'], $app,
Auth::getAuth(), Auth::getCredential('password'));
} else {
$GLOBALS['prefs']->retrieve($app);
}
}
}
/**
* Unload preferences from an application or (if no application is
* specified) from ALL applications. Useful when a user has logged
* out but you need to continue on the same page, etc.
*
* After unloading, if there is an application on the app stack to
* load preferences from, then we reload a fresh set.
*
* @param string $app The application to unload prefrences for. If null,
* ALL preferences are reset.
*/
public function unloadPrefs($app = null)
{
// TODO: $app not being used?
if ($this->getApp()) {
$this->loadPrefs();
}
}
/**
* Return the requested configuration parameter for the specified
* application. If no application is specified, the value of
* the current application is used. However, if the parameter is not
* present for that application, the Horde-wide value is used instead.
* If that is not present, we return null.
*
* @param string $parameter The configuration value to retrieve.
* @param string $app The application to get the value for.
*
* @return string The requested parameter, or null if it is not set.
*/
public function get($parameter, $app = null)
{
if (is_null($app)) {
$app = $this->getApp();
}
if (isset($this->applications[$app][$parameter])) {
$pval = $this->applications[$app][$parameter];
} else {
$pval = ($parameter == 'icon')
? $this->getImageDir($app) . '/' . $app . '.png'
: (isset($this->applications['horde'][$parameter]) ? $this->applications['horde'][$parameter] : null);
}
return ($parameter == 'name')
? _($pval)
: $pval;
}
/**
* Function to work out an application's graphics URI, optionally taking
* into account any themes directories that may be set up.
*
* @param string $app The application for which to get the image
* directory. If blank will default to current
* application.
* @param boolean $usetheme Take into account any theme directory?
*
* @return string The image directory uri path.
*/
public function getImageDir($app = null, $usetheme = true)
{
if (empty($app)) {
$app = $this->getApp();
}
if ($this->get('status', $app) == 'heading') {
$app = 'horde';
}
$sig = strval($app . '|' . $usetheme);
if (isset($this->_imgDir[$sig])) {
return $this->_imgDir[$sig];
}
/* This is the default location for the graphics. */
$this->_imgDir[$sig] = $this->get('themesuri', $app) . '/graphics';
/* Figure out if this is going to be overridden by any theme
* settings. */
if ($usetheme &&
isset($GLOBALS['prefs']) &&
($theme = $GLOBALS['prefs']->getValue('theme'))) {
/* Since theme information is so limited, store directly in the
* session. */
if (!isset($_SESSION['_registry']['theme'][$theme][$app])) {
$_SESSION['_registry']['theme'][$theme][$app] = file_exists($this->get('themesfs', $app) . '/' . $theme . '/themed_graphics');
}
if ($_SESSION['_registry']['theme'][$theme][$app]) {
$this->_imgDir[$sig] = $this->get('themesuri', $app) . '/' . $theme . '/graphics';
}
}
return $this->_imgDir[$sig];
}
/**
* Query the initial page for an application - the webroot, if there is no
* initial_page set, and the initial_page, if it is set.
*
* @param string $app The name of the application.
*
* @return string URL pointing to the inital page of the application.
* Returns PEAR_Error on error.
*/
public function getInitialPage($app = null)
{
if (is_null($app)) {
$app = $this->getApp();
}
return isset($this->applications[$app])
? $this->applications[$app]['webroot'] . '/' . (isset($this->applications[$app]['initial_page']) ? $this->applications[$app]['initial_page'] : '')
: PEAR::raiseError(sprintf(_("\"%s\" is not configured in the Horde Registry."), $app));
}
/**
* Saves a cache variable.
*
* @param string $name Cache variable name.
* @param boolean $expire Expire the entry?
*/
protected function _saveCacheVar($name, $expire = false)
{
if ($this->_cacheob) {
if ($expire) {
if ($id = $this->_getCacheId($name)) {
$this->_cacheob->expire($id);
}
} else {
$data = serialize($this->_cache[$name]);
$_SESSION['_registry']['md5'][$name] = $md5sum = hash('md5', $data);
$id = $this->_getCacheId($name, false) . '|' . $md5sum;
$this->_cacheob->set($id, $data, 86400);
Horde::logMessage('Registry: stored ' . $name . ' with cache ID ' . $id, __FILE__, __LINE__, PEAR_LOG_DEBUG);
}
}
}
/**
* Retrieves a cache variable.
*
* @param string $name Cache variable name.
*
* @return boolean True if value loaded from cache.
*/
protected function _loadCacheVar($name)
{
if (isset($this->_cache[$name])) {
return true;
}
if ($this->_cacheob &&
($id = $this->_getCacheId($name))) {
$res = $this->_cacheob->get($id, 86400);
if ($res !== false) {
$this->_cache[$name] = unserialize($res);
Horde::logMessage('Registry: retrieved ' . $name . ' with cache ID ' . $id, __FILE__, __LINE__, PEAR_LOG_DEBUG);
return true;
}
}
return false;
}
/**
* Get the cache storage ID for a particular cache name.
*
* @param string $name Cache variable name.
* @param string $md5 Append MD5 value?
*
* @return mixed The cache ID or false if cache entry doesn't exist in
* the session.
*/
protected function _getCacheId($name, $md5 = true)
{
$id = 'horde_registry_' . $name . '|' . $this->_regmtime;
if (!$md5) {
return $id;
} elseif (isset($_SESSION['_registry']['md5'][$name])) {
return $id . '|' . $_SESSION['_registry']['md5'][$name];
} else {
return false;
}
}
}
/**
* @package Horde_Framework
*/
class RegistryCaller
{
/**
* TODO
*/
protected $registry;
/**
* TODO
*/
protected $api;
/**
* TODO
*/
public function __construct($registry, $api)
{
$this->registry = $registry;
$this->api = $api;
}
/**
* TODO
*/
public function __call($method, $args)
{
return $this->registry->call($this->api . '/' . $method, $args);
}
}