:: Config_Registry (proposal)
/**
* Returns the current API version
*
* @return float
* @since 0.1
* @access public
*/
function apiVersion()
{
return 0.1;
}
/**
* 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 array $files (optional) files to read user-defined options from
* and/or to read system-wide defaults from
*
* @return object The Registry instance.
* @since 0.1
* @access public
*/
function &singleton()
{
static $registry;
if (!isset($registry)) {
$registry = new Config_Registry();
}
return $registry;
}
[Top]
/**
* Return a list of the installed and registered applications.
* If no applications are defined return a null array.
*
* @return array List of applications registered
* @since 0.1
* @access public
* @see registerApplication(), isApplicationRegistered()
*/
function getApplicationsRegistered()
{
$apps = array();
foreach ($this->applications as $app => $opt) {
$apps[] = array('handler' => $app, 'name' => $opt['name']);
}
return $apps;
}
[Top]
/**
* Returns whether or not the application is registered
*
* @param string $app The desired application
*
* @return boolean
* @since 0.1
* @access public
* @see registerApplication(), getApplicationsRegistered()
*/
function isApplicationRegistered($app)
{
return isset($this->applications[$app]);
}
[Top]
/**
* Registers a new application. All configuration layers
* ('user', 'system', 'default') are reset.
*
* @param string $app The desired application
* @param string $name (optional) The desired application name
* @param string $fileroot (optional) The directory where we can find the application
*
* @return mixed PEAR::Error is failure, TRUE otherwise
* @since 0.1
* @access public
* @see isApplicationRegistered(), getApplicationsRegistered(), registerApplication()
*/
function registerApplication($app, $name = '', $fileroot = '.')
{
if (empty($app)) {
return PEAR::raiseError('Application handler is required');
}
if ($this->isApplicationRegistered($app)) {
return PEAR::raiseError('Application "'.$name.'" ('.$app.') is already defined');
}
if (!is_dir($fileroot)) {
return PEAR::raiseError('Directory of application "'.$name.'" ('.$app.') is invalid');
}
$this->applications[$app]['fileroot'] = $fileroot;
$this->applications[$app]['name'] = $name;
$layers = $this->_getLayers(true);
foreach ($layers as $layer) {
$this->configurations[$app][$layer] = null;
}
return true;
}
[Top]
/**
* Removes an old application with all configuration layers
* ('user', 'system', 'default') and registered services.
*
* @param string $app The desired application
*
* @return mixed PEAR::Error is failure, TRUE otherwise
* @since 0.1
* @access public
* @see registerApplication(), isApplicationRegistered(), getApplicationsRegistered()
*/
function unregisterApplication($app)
{
if (!$this->isApplicationRegistered($app)) {
return PEAR::raiseError('Application "'.$app.'" is not registered');
}
$layers = $this->_getLayers(true);
foreach ($layers as $layer) {
// removes all configuration layers data
if (isset($this->configurations[$app][$layer])) {
$this->configurations[$app][$layer] = null;
}
$this->resources[$layer] = null; // marks last-used resource as empty
}
// removes all hooks for this application
if (isset($this->services[$app])) {
unset($this->services[$app]);
}
unset($this->applications[$app]);
return true;
}
[Top]
/**
* Gets the configuration for a layer
*
* @param string $layer Config layer name ('user', 'system' or 'default')
* @param string $app The desired application
* @param bool $compress (optional) set it to TRUE if you want serialized data
*
* @return mixed The config layer on success and PEAR error on failure
* @since 0.1
* @access public
*/
function getConfigLayer($layer, $app, $compress = false)
{
$layers = $this->_getLayers(true);
if (!in_array($layer, $layers)) {
return PEAR::raiseError('unknown layer "'.$layer.'"');
}
if (!$this->isApplicationRegistered($app)) {
return PEAR::raiseError('Application "' .$app. '" is not registered');
}
$cfg =& $this->configurations[$app][$layer];
if ($compress) {
return serialize($cfg->toArray());
}
return $cfg->toArray();
}
[Top]
/**
* Gets the resource used for storing the layer configuration.
*
* @param string $layer Config layer name ('user', 'system' or 'default')
*
* @return mixed The resource if layer is valid and null otherwise
* @since 0.1
* @access public
*/
function getConfigResource($layer)
{
return (!empty($this->resources[$layer])) ? $this->resources[$layer] : null;
}
[Top]
/**
* Reads configuration data from an external resource.
* All existing values in the application configuration layer
* may be:
* - discarded and replaced with data from the external resource
* - merged with existing config data.
*
* @param string $app The target application
* @param string $name (optional) Resource to read from,
* if NULL or not specified,
* the last-used resource for the same layer is used
* @param string $type (optional) Type of data source (phpArray, Ini, XML, ...)
* @param array $options (optional) Options for the parser
* @param bool $override (optional) Whether to overwrite existing data
* @param string $layer (optional) Config layer to insert data into
*
* @return bool TRUE on success or a PEAR error on failure
* @since 0.1
* @access public
* @see exportConfig(), setDefaults()
*/
function importConfig($app, $name = null, $type = 'phpArray', $options = array(),
$override = true, $layer = 'user')
{
$layers = $this->_getLayers(true);
if (!in_array($layer, $layers)) {
return PEAR::raiseError('unknown config type '. $layer);
}
if ($name === null) {
if (empty($this->resources[$layer])) {
return PEAR::raiseError('none last-used config resource type '. $layer);
} else {
$name = $this->resources[$layer]['name'];
$type = $this->resources[$layer]['type'];
$options = $this->resources[$layer]['opts'];
}
}
$conf = new Config();
$reg = $conf->parseConfig($name, $type, $options);
if (PEAR::isError($reg)) {
return $reg;
}
$cfg =& $this->configurations[$app][$layer];
if ($override || is_null($cfg)) {
$this->configurations[$app][$layer] = $reg;
} else {
for ($i = 0; $i < $reg->countChildren('section'); $i++) {
$c = $reg->getItem('section',null,null,null,$i);
$cfg->additem($c);
}
}
$this->resources[$layer] = array('name' => $name, 'type' => $type, 'opts' => $options);
return true;
}
[Top]
/**
* Writes data from an application configuration layer
* into external resource.
*
* @param string $app The source application
* @param string $name (optional) Name of resource to write to
* @param string $type (optional) Type of data source (phpArray, Ini, XML, ...)
* @param array $options (optional) Options for the parser
* @param string $layer (optional) Config layer to read data from
*
* @return bool TRUE on success or a PEAR error on failure
* @since 0.1
* @access public
* @see importConfig(), setDefaults()
*/
function exportConfig($app, $name = null, $type = 'phpArray', $options = array(),
$layer = 'user')
{
if (!$this->isApplicationRegistered($app)) {
return PEAR::raiseError('Application ' .$app. ' is not registered');
}
$layers = $this->_getLayers(true);
if (!in_array($layer, $layers)) {
return PEAR::raiseError('unknown config type '. $layer);
}
if ($name === null) {
if (empty($this->resources[$layer])) {
return PEAR::raiseError('none last-used config resource type '. $layer);
}
$name = $this->resources[$layer]['name'];
$this->resources[$layer]['type'] = $type; // in case of file-type changed
$this->resources[$layer]['opts'] = $options; // in case of file-options changed too
}
$cfg =& $this->configurations[$app][$layer];
return $cfg->writeDatasrc($name, $type, $options);
}
[Top]
/**
* A convenience function for initialize
* a default configuration for an application.
*
* @param string $app The target application
* @param string $name (optional) Resource to read from,
* if NULL or not specified,
* the last-used resource for the same layer is used
* @param string $type (optional) Type of data source (phpArray, Ini, XML, ...)
* @param array $options (optional) Options for the parser
*
* @return mixed TRUE on success and PEAR error on failure
* @since 0.1
* @access public
* @see importConfig()
*/
function setDefaults($app, $name = null, $type = 'phpArray', $options = array())
{
return $this->importConfig($app, $name, $type, $options, true, 'default');
}
[Top]
/**
* Returns the requested configuration parameter.
* If no layer is specified, then configuration parameter
* will be search in layer order (if a 'user' value exists,
* it will be returned first, then 'system' and finally 'default').
* However, if parameter is not present, we return null.
*
* @param string $parameter The configuration value to retrieve.
* @param string $app The application to get the value for.
* @param string $bloc (optional) The section where to search for value.
* @param string $layer (optional) Config layer to get data from
*
* @return string The requested parameter, or null if it is not set.
* @since 0.1
* @access public
* @see searchParam()
*/
function getParam($parameter, $app, $bloc = 'root', $layer = null)
{
if ($layer === null) {
$layers = $this->_getLayers(true);
foreach ($layers as $layer) {
$cfg =& $this->configurations[$app][$layer];
if ($this->_isConfig($cfg)) {
if (strtolower($bloc) == 'root') {
$section =& $cfg;
} else {
$section =& $cfg->getItem('section',$bloc);
}
if (is_object($section)) {
$param = $section->getItem('directive',$parameter);
if (is_object($param)) {
return $param->getContent();
}
}
}
}
} else {
$cfg =& $this->configurations[$app][$layer];
if (in_array($layer, $layers) && $this->_isConfig($cfg)) {
if (strtolower($bloc) == 'root') {
$section =& $cfg;
} else {
$section =& $cfg->getItem('section',$bloc);
}
if (is_object($section)) {
$param = $section->getItem('directive',$parameter);
if (is_object($param)) {
return $param->getContent();
}
}
}
}
return null;
}
[Top]
/**
* Sets the given parameter to the specific value, if the parameter
* of the configuration already exists.
*
* @param string $parameter The configuration directive to set
* @param string $value The configuration parameter value
* @param string $app The application to set the value to
* @param string $bloc (optional) The section where to set the parameter.
* @param string $layer (optional) Config layer to set data to
*
* @return bool TRUE on success or a PEAR error on failure
* @since 0.1
* @access public
* @see addParam(), removeParam()
*/
function setParam($parameter, $value, $app, $bloc = 'root', $layer = 'user')
{
$layers = $this->_getLayers(true);
$cfg =& $this->configurations[$app][$layer];
if (!in_array($layer, $layers) || !$this->_isConfig($cfg)) {
return PEAR::raiseError('unknown config resource type '.$layer);
} else {
if (strtolower($bloc) == 'root') {
$section =& $cfg;
} else {
$section =& $cfg->getItem('section',$bloc);
}
if ($section === false) {
return PEAR::raiseError('unknown section '.$bloc.' in layer '.$layer);
} else {
$param =& $section->getItem('directive',$parameter);
if ($param === false) {
return PEAR::raiseError('unknown directive '.$parameter.' on section '.$bloc.' of layer '.$layer);
} else {
$param->setContent($value);
return true;
}
}
}
}
[Top]
/**
* Add a new config parameter in a specific layer (defaults to 'user').
*
* @param string $parameter The configuration directive to add
* @param string $value The configuration parameter value
* @param mixed $attributes The parameter (directive) attributes
* @param string $app The application to add the new value
* @param string $bloc (optional) The section where to add the parameter
* @param string $layer (optional) Config layer to set data to
*
* @return bool TRUE on success or a PEAR error on failure
* @since 0.1
* @access public
* @see setParam(), removeParam()
*/
function addParam($parameter, $value, $attributes, $app, $bloc = 'root', $layer = 'user')
{
$layers = $this->_getLayers(true);
$cfg =& $this->configurations[$app][$layer];
if (!in_array($layer, $layers) || !$this->_isConfig($cfg)) {
return PEAR::raiseError('unknown config resource type '.$layer);
} else {
if (strtolower($bloc) == 'root') {
$section =& $cfg;
} else {
$section =& $cfg->getItem('section',$bloc);
}
if ($section === false) {
// creates the $bloc if does not exists
$section =& $cfg->createSection($bloc);
if (PEAR::isError($section)) {
return $section;
}
}
$param = $section->getItem('directive',$parameter);
if ($param === false) {
$param =& $section->createDirective($parameter, $value, $attributes);
}
if (PEAR::isError($param)) {
return $param;
}
return true;
}
}
[Top]
/**
* Remove a config parameter from a specific layer (defaults from 'user').
*
* @param string $parameter The configuration parameter to remove
* @param string $app The application to remove the value from
* @param string $bloc (optional) The section where to remove the parameter
* @param string $layer (optional) Config layer to remove data
*
* @return bool TRUE on success, FALSE on failure
* @since 0.1
* @access public
* @see setParam(), addParam()
*/
function removeParam($parameter, $app, $bloc = 'root', $layer = 'user')
{
$layers = $this->_getLayers(true);
$cfg =& $this->configurations[$app][$layer];
if (!in_array($layer, $layers) || !$this->_isConfig($cfg)) {
return PEAR::raiseError('unknown config resource type '.$layer);
} else {
if (strtolower($bloc) == 'root') {
$section =& $cfg;
} else {
$section =& $cfg->getItem('section',$bloc);
}
if ($section === false) {
return PEAR::raiseError('unknown section '.$bloc.' in layer '.$layer);
} else {
$param =& $section->getItem('directive',$parameter);
if ($param === false) {
return PEAR::raiseError('unknown directive '.$parameter.' on section '.$bloc.' of layer '.$layer);
} else {
$param->removeItem();
return true;
}
}
}
}
[Top]
/**
* Tells what config layer that gets to define a parameter.
*
* @param string $parameter The configuration parameter to retrieve
* @param string $app The desired application
* @param string $bloc (optional) The section where to search the parameter
*
* @return string The config layer, or NULL if not found
* @since 0.1
* @access public
* @see getParam()
*/
function searchParam($parameter, $app, $bloc = 'root')
{
$layers = $this->_getLayers(true);
foreach ($layers as $layer) {
$cfg =& $this->configurations[$app][$layer];
if ($this->_isConfig($cfg)) {
if (strtolower($bloc) == 'root') {
$section =& $cfg;
} else {
$section =& $cfg->getItem('section',$bloc);
}
if (is_object($section)) {
$param = $section->getItem('directive',$parameter);
if (is_object($param)) {
return $layer;
}
}
}
}
return null;
}
[Top]
/**
* Determine if a method has been registered with the registry.
* May be restrict to a specific handler (if second param not null).
*
* @param string $method The full name of the method to check for
* @param string $handler (optional) Identify a specific handler
*
* @return boolean Whether or not the method is registered
* @since 0.1
* @access public
* @see getHandler(), callService(), registerService()
*/
function hasMethod($method, $handler = null)
{
list($type, $subtype) = explode('/', $method);
if (is_null($handler)) {
return !empty($this->registry[$type][$subtype]);
} else {
return isset($this->services[$handler][$type][$subtype]);
}
}
[Top]
/**
* Returns the handler for the given method.
*
* @param string $method The full name of the method to check for
*
* @return string The handler for the method
* @since 0.1
* @access public
* @see hasMethod(), callService(), registerService()
*/
function getHandler($method)
{
list($type, $subtype) = explode('/', $method);
return !empty($this->registry[$type][$subtype]) ? $this->registry[$type][$subtype] : null;
}
[Top]
/**
* Returns the hook corresponding to the specific handler that
* provides the functionality requested by the $method parameter.
* $method is a string consisting of "packagetype/methodname".
*
* @param string $app The desired application
* @param string $method The method to call
* @param array $args (optional) Arguments to the method
* @param mixed $extra (optional) Non-standard arguments to the method
*
* @return mixed
* @since 0.1
* @access public
* @see hasMethod(), getHandler(), registerService()
*/
function callService($app, $method, $args = array(), $extra = null)
{
if (!$this->hasMethod($method, $app)) {
// no callback defined
return PEAR::raiseError('The method "'.$method.'" is not defined in the Registry');
}
list($type, $subtype) = explode('/', $method);
$file = $this->services[$app][$type][$subtype]['file'];
$function = $this->services[$app][$type][$subtype]['function'];
if (!@is_readable($file)) {
return PEAR::raiseError('The file "'.$file.'" is not readable.');
}
include_once $file;
if (is_array($function) && count($function) == 2) {
list($className, $methodName) = $function;
$obj = new $className();
if (!method_exists($obj, $methodName)) {
return PEAR::raiseError('The method implementing "'.$method.'" ('.$methodName.') is not defined');
}
} elseif (is_string($function)) {
if (!function_exists($function)) {
return PEAR::raiseError('The function implementing "'.$method.'" ('.$methodName.') is not defined');
}
} else {
return PEAR::raiseError('Callback should be either function or class-method');
}
if (!is_null($extra)) {
// Add non-standard $extra to arguments if necessary before the call to the method
if (is_array($extra)) {
foreach ($extra as $item) {
array_push($args, $item);
}
} else {
array_push($args, $extra);
}
}
if (isset($className)) {
return call_user_func_array(array(&$obj, $methodName), $args);
} else {
return call_user_func_array($function, $args);
}
}
[Top]
/**
* Return a list of the defined services for a specific application.
*
* @param string $app The desired application
*
* @return mixed List of services defined or PEAR_Error if failure
* @since 0.1
* @access public
* @see callService()
*/
function getServices($app)
{
if (!$this->isApplicationRegistered($app)) {
return PEAR::raiseError('Application "' .$app. '" is not registered');
}
return empty($this->services[$app]) ? null : $this->services[$app];
}
[Top]
/**
* Registers set of methods for communication between
* applications (as plugins).
*
* @param string $app The desired application
* @param string $method The full name of the method to register
* @param string $file The filename where to find callbacks
* @param mixed $func The hook to declare (function or class-method)
* @param array $args (optional) Arguments list required for the service
*
* @return mixed PEAR::Error is failure, TRUE otherwise
* @since 0.1
* @access public
* @see hasMethod(), getHandler(), callService()
*/
function registerService($app, $method, $file, $func, $args = array())
{
if (empty($app)) {
return PEAR::raiseError('Application handler is required');
}
if (!$this->isApplicationRegistered($app)) {
return PEAR::raiseError('Application "' .$app. '" is not registered');
}
@list($type, $subtype) = explode('/', $method);
if (empty($type)) {
return PEAR::raiseError('Type part of method "'.$method.'" is missing');
}
if (empty($subtype)) {
return PEAR::raiseError('Subtype part of method "'.$method.'" is missing');
}
if (!is_file($file)) {
return PEAR::raiseError('Resource file "'. $file .'" should be valid');
}
$this->services[$app][$type][$subtype] = array(
'file' => $file,
'function' => $func,
'args' => $args
);
$this->registry[$type][$subtype] = $app;
return true;
}
[Top]
/**
* Returns the layers defined
*
* @param boolean $default (optional) Whether you want the 'default' layer
*
* @return array List of the defined layers
* @since 0.1
* @access private
* @see registerApplication(), getConfigLayer(), importConfig(), exportConfig(),
* getParam(), setParam(), addParam(), removeParam(), searchParam()
*/
function _getLayers($default = false)
{
$layers = array('user', 'system', 'default');
if (!$default) {
array_pop($layers);
}
return $layers;
}
/**
* Tell whether a value is an instance of Config_Container object.
*
* @param mixed $data The value to test
*
* @return bool TRUE if parameter is a Config_Container instance
* @since 0.1
* @access private
* @see getParam(), setParam(), addParam(), removeParam(), searchParam()
*/
function _isConfig($data)
{
if (is_object($data) &&
(strtolower(get_class($data)) == 'config_container' || is_subclass_of($data))) {
return true;
} else {
return false;
}
}
[Top]
continue on [Examples]
return to [Table of Contents]