| // | Christian Stocker | // +----------------------------------------------------------------------+ // // $Id$ require_once( "PEAR.php") ; /** * Partly implementation of the Config-Interface-API * * This class implements a part of the API for working on configuration data * ConfigDefault implements getValues(), getBlocks(), getValue(), setValue() * The data is internally saved in a nested array. * * Example: * include("Config.php"); * $i = new Config("IniFile"); * $i -> parseInput( "yourfile.ini"); * $ret = $i->getValues('/section'); * * * @author Alexander Merz * @access public * @version $Id$ * @package Config */ class Config { /** * contains the data source given by parseInput * @var string */ var $datasrc ; /** * contains the internal data structure * @var array */ var $data = array() ; /** * Constructor * * requires the type of the data container, if the container needs * special parameters during creation, set them with $storage_options * * @access public * @param string $storage_driver type of container * @param string $storage_options parameter for container constructor */ function Config($storage_driver,$storage_options = "") { $storage_class = 'Config_Container_' . $storage_driver; $storage_classfile = 'Config/Container/' . $storage_driver . '.php'; include_once $storage_classfile; $this->container = new $storage_class($storage_options); } // end func Config() /** * returns all key-value-pairs of the given block * * If the block not exists, a PEAR_Error will returned, else * a hash: $array["key"] = value * * @access public * @param string $block block path * @return array returns a hash containing all values, but a PEAR_Error if fails */ function getValues( $block = "/") { if( !empty( $this -> data ) ) { // if leading slash was forgotten... if( "/" != substr( $block, 0, 1) ) { $block = "/".$block ; } if( isset( $this -> data[ $block ] ) ) { if( is_array( $this -> data[ $block ] ) ) { $ret = $this -> data[ $block ] ; } else { $ret = false ; } } else { $ret = new PEAR_Error("Block path '".$block."' doesn't exists! Request couldn't be answered.", 12, PEAR_ERROR_RETURN, null, null ); } } else { $ret = new PEAR_Error("No internal data! Request couldn't be answered.", 11, PEAR_ERROR_RETURN, null, null ); } return $ret ; } // end func getValues /** * returns all blocks of the given block * * If the block not exists, a PEAR_Error will returned, else * a array containing all child blocks * * @access public * @param string $block block path * @return array returns a array containing all values, or a PEAR_Error, if fails */ function getBlocks( $block = "/") { if( !empty( $this -> data ) ) { // if leading slash was forgotten... if( "/" != substr( $block, 0, 1) ) { $block = "/".$block ; } $ret = array() ; foreach( $this -> data as $key => $value) { $key = $key."/" ; if( $block == substr( $key, 0, strlen( $block ) ) ) { array_push ( $ret, trim( substr( $key, strlen( $block ), strpos( substr( $key, strlen( $block ) ), "/" ) ) ) ) ; } } } else { $ret = new PEAR_Error("No internal data! Request couldn't be answered.", 21, PEAR_ERROR_RETURN, null, null ); } return $ret ; } // end func getBlocks /** * sets the value of the key of the given block * * If the block or the key not exists, both will be created. * The value will be returned. * * @access public * @param string $block block path * @param string $key key to set * @param string $value value for the key * @return mixed type depends on $value * @see getValue() */ function setValue( $block = "/", $key, $value = "") { // if leading slash was forgotten... if( "/" != substr( $block, 0, 1) ) { $block = "/".$block ; } // check for existing block and key if( !isset ( $this -> data[ $block ] ) ) { $this->data[ $block ] = array() ; } $kvp = $this -> data[ $block ] ; $kvp[ $key ] = $value ; $this -> data[ $block ] = $kvp ; $ret = $value ; return $ret ; } // end func setValue /** * return the value of the key of the given block * * If the block or the key not exists, both will be created and * sets on the default. * The value or if not exists the default will be returned. * * @access public * @param string $block block path * @param string $key key to set * @param string $default default value for the key * @return mixed type depends of the value */ function getValue( $block = "/", $key, $default = "") { // if leading slash was forgotten... if( "/" != substr( $block, 0, 1) ) { $block = "/".$block ; } // check for existing block and key $values = $this -> getValues( $block ) ; if( PEAR::isError($values) or !in_array( $key, array_keys( $values) ) ) { $this -> setValue( $block, $key, $default) ; $values = $this -> getValues( $block ) ; } $ret = $values[ $key ] ; return $ret ; } // end func getValue /** * parses the input of the given data source * * The format and required content of $datasrc depends of the implementation. * If the implemention requires additional data, for example a comment char, it have to * deliver in a hash as second argument. * * @access public * @param string $files Name of the datasource to parse * @param array $feature Contains a hash of features depending on the implentation * @return mixed returns a PEAR_ERROR, if error occurs */ function parseInput ($files ,$feature = array() ) { if (is_array($files)) { $totaldata = array(); foreach ($files as $datasrc) { if (Pear::isError($error = $this->container->parseInput($datasrc,$feature))) return $error; $totaldata = $this->array_merge_clobber($totaldata,$this->container->data); unset ($this->data); $this->datasrc = $datasrc; } $this->data = $totaldata; } else { if (Pear::isError($error = $this->container->parseInput($files,$feature))) return $error; $this->data = $this->container->data; $this->datasrc = $files; } } // end func parseInput() /** * writes the data to the given data source or if not given to the datasource of parseInput * If $datasrc was a array, the last file will used. * * See parseInput for $datasrc. If the second argument $preserve is true, the implementation * should try to preserve the original format and data of the source except changed or added values. * This mean to preserve for example comments in files or so. * * @access public * @param string $datasrc Name of the datasource to parse * @param boolean $preserve preserving behavior * @return mixed returns PEAR_Error, if fails * @see parseInput() */ function writeInput( $datasrc = "", $preserve = True ) { if( empty( $datasrc ) ) { $datasrc = $this -> datasrc ; } $this->container->data = $this->data; $this->container->writeInput($datasrc,$preserve); } //taken from kc@hireability.com at http://www.php.net/manual/en/function.array-merge-recursive.php /** * There seemed to be no built in function that would merge two arrays recursively and clobber * any existing key/value pairs. Array_Merge() is not recursive, and array_merge_recursive * seemed to give unsatisfactory results... it would append duplicate key/values. * * So here's a cross between array_merge and array_merge_recursive * * @param array first array to be merged * @param array second array to be merged * @return array merged array * @acces private */ function array_merge_clobber($a1,$a2) { if(!is_array($a1) || !is_array($a2)) return false; $newarray = $a1; while (list($key, $val) = each($a2)) { if (is_array($val) && is_array($newarray[$key])) { $newarray[$key] = $this->array_merge_clobber($newarray[$key], $val); } else { $newarray[$key] = $val; } } return $newarray; } }; // end class Config ?>