* @license PHP License * @package WB * @subpackage base */ /** * XML config unserializer * * Unserialitze config string from XML to array * * @version 1.1.0 * @package WB * @subpackage base */ class WBConfig_Unserializer extends WBStdClass { /** * XML Unserializer * @var XML_Unserializer */ private $unser; /** * loader sub class * @var WBConfig_Loader */ private $loader; /** * constructor * * start patI18n */ public function __construct() { WBClass::create('patI18n'); // prepare XML_Userializer WBClass::load('XML_Unserializer'); $params = array( XML_UNSERIALIZER_OPTION_WHITESPACE => XML_UNSERIALIZER_WHITESPACE_KEEP, XML_UNSERIALIZER_OPTION_COMPLEXTYPE => 'array', XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY => 'id', XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => true, XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY => '_attributes', XML_UNSERIALIZER_OPTION_FORCE_ENUM => array('item') ); $this->unser = new XML_Unserializer($params); } /** * Choose loader * * Tell config class how to load XML-strings of config * * @param string $loader */ public function setLoader($loader = 'File') { $this->loader = WBClass::create('WBConfig_Loader_'. $loader); } /** * unserializer XML string * * @param string $in * @return array * @throws WBException_File */ public function unserialize($in) { $res = $this->unser->unserialize($in, false); if ($res instanceof PEAR_Error) { WBClass::load('WBException_Pear'); throw new WBException_Pear( $res->getMessage(), 2, __CLASS__ ); } $raw = $this->unser->getUnserializedData(); $config = array(); if (empty($raw)) { return $config; } $this->raw2array($raw, $config); return $config; } /** * convert raw array to configuration array * * Recursive function that walks through raw condig data * * @param array $raw input data * @param array $tmp current position in current configuration value * @return bool true on success */ private function raw2Array($raw, &$tmp) { // this is trivial if (is_scalar($raw)) { $tmp = $raw; return true; } foreach ($raw as $key => $value) { if( $key == '_attributes' ) { continue; } // if( $key == 'xinc' ) { $this->xInc($value, $tmp); continue; } // if( $key == 'xmerge' ) { $this->xMerge($value, $tmp); continue; } // if ($key == 'xcall') { $this->xCall($value, $tmp); continue; } // simple value if( !is_array( $value ) ) { $tmp[$key] = $value; continue; } // is always an indexed array if( $key == 'item' ) { unset( $raw['item'] ); unset( $tmp['item'] ); for( $i = 0; $i < count( $value ); ++$i ) { $this->translate($value[$i]); if (is_array($value[$i]) && isset($value[$i]['_content'])) { $value[$i] = $value[$i]['_content']; } // append $j = count($tmp); $tmp[$j] = array(); $this->raw2Array($value[$i], $tmp[$j]); } continue; } // sequential arrays if (isset($value[0])) { if (!is_array($tmp[$key])) { $tmp[$key] = array(); } for ($i = 0; $i < count($value); ++$i) { $this->translate($value[$i]); if (isset($value[$i]['_content'])) { $value[$i] = $value[$i]['_content']; } // append $j = count($tmp[$key]); $tmp[$key][$j] = array(); $this->raw2Array($value[$i], $tmp[$key][$j]); } continue; } $this->parameter($value); $this->cast($value); // manage attributes if (isset($value['_attributes'])) { // "id" is the key if (isset($value['_attributes']['id']) && isset($value['_content'])) { $this->translate($value); $tmp[$key] = $value['_content']; continue; } $this->translate($value); if (isset($value['_content'])) { $value = $value['_content']; } } // recursion $tmp[$key] = array(); $this->raw2Array($value, $tmp[$key]); } return true; } /** * translate values markt as such * * check for nls-attributes and use patI18n to translate content * * @param array $value */ private function translate(&$value) { if (!is_array($value)) { return; } // translate if (!isset($value['_attributes']) || !isset($value['_attributes']['nls:translate']) || !$value['_attributes']['nls:translate']) { return; } if (empty($value['_content'])) { return; } if (isset($value['_attributes']['nls:domain'])) { $value['_content'] = patI18n::dgettext($value['_attributes']['nls:domain'], $value['_content']); } else { $value['_content'] = patI18n::gettext($value['_content']); } } /** * Use WBParam to populate XML content * * Listen for attributes: param:get and param:sprintf. * * @param array $value */ private function parameter(&$value) { if (!is_array($value)) { return; } // no attributes if (!isset($value['_attributes']) || empty($value['_attributes'])) { return; } $action = ''; $param = ''; foreach ($value['_attributes'] as $k => $v) { if (0 != strncmp('param:', $k, 6)) { continue; } $action = explode(':', $k, 2); $action = $action[1]; $param = WBParam::get($v); break; } // not found? don't do a thing if (empty($action)) { return; } switch ($action) { case 'sprintf': $value['_content'] = sprintf($value['_content'], $param); break; default: case 'get': $value['_content'] = $param; break; } } /** * Cast Value to specific data types * * @param array $value */ private function cast(&$value) { if (!is_array($value)) { return; } // no attributes if (!isset($value['_attributes']) || empty($value['_attributes'])) { return; } if (!isset($value['_attributes']['cast']) || empty($value['_attributes']['cast'])) { return; } switch (strtolower($value['_attributes']['cast'])) { case 'bool': if ('true' == $value['_content']) { $value['_content'] = 1; } else if ('false' == $value['_content']) { $value['_content'] = 0; } else { $value['_content'] = intval($value['_content']); } if (0 < $value['_content']) { $value['_content'] = true; } else { $value['_content'] = false; } break; case 'int': $value['_content'] = intval($value['_content']); break; case 'float': $value['_content'] = floatval($value['_content']); break; default: break; } } /** * Merge Value with Other Config * * @param array $value */ private function xMerge($value, &$tmp) { if (!is_array($value) || !isset($value[0])) { $value = array($value); } $incConfig = WBClass::create('WBConfig'); $incConfig->setLoader($this->loader->getName()); foreach ($value as $v) { $incConfig->load($v); $this->xMergeArray($tmp, $incConfig->get()); } } /** * Recursive Function to Actually Merge Values * * @param array $value * @param array $merge values */ private function xMergeArray(&$value, $merge) { if (!is_array($merge)) { $value = $merge; return; } foreach ($merge as $k => $mv) { if (!isset($value[$k])) { $value[$k] = $mv; continue; } if (is_array($mv)) { $this->xMergeArray($value[$k], $mv); continue; } $value[$k] = $mv; } } /** * xinc * * Include other files * * @param array $value config file to include * @param array $tmp current position in current configuration value * @return bool true on success */ private function xInc($value, &$tmp) { if (!is_array($value) || !isset($value[0])) { $value = array($value); } /** @var WBConfig */ $incConfig = WBClass::create('WBConfig'); $incConfig->setLoader($this->loader->getName()); foreach ($value as $v) { if (!is_array($v) || !isset($v['_attributes'])) { $this->debugPrint(sprintf('xinc %s', $v), 20); $incConfig->load($v); $inc = $incConfig->get(); if (is_array($tmp) && is_array($inc)) { $inc = array_merge($tmp, $inc); } $tmp = $inc; continue; } $this->debugPrint(sprintf('xinc %s', $v['_content']), 20); $incConfig->load($v['_content']); $path = null; if (isset($v['_attributes']['path'])) { $path = $v['_attributes']['path']; } $inc = $incConfig->get($path); if (isset($v['_attributes']['as'])) { $key = $v['_attributes']['as']; $tmp[$key] = $inc; if (is_array($inc) && 1 == count($inc)) { $tmp[$key] = array_shift($inc); } } else { if (is_array($tmp) && is_array($inc)) { $inc = array_merge($tmp, $inc); } $tmp = $inc; } } return true; } /** * xCall * * Load config dynamically * * @param array $value config file to include * @param array $tmp current position in current configuration value * @return bool true on success */ private function xCall($value, &$tmp) { if (!is_array($value) || !isset($value[0])) { $value = array($value); } foreach ($value as $v) { if (!is_array($v)) { $v = array( '_content' => $v, '_attributes' => array() ); } $callee = $v['_content']; $callee = str_replace('/', '_', $callee); $callee = WBClass::create('WBConfig_Call_' . $callee); $callee->setAttributes($v['_attributes']); $inc = $callee->call(); if (empty($v['_attributes']['as'])) { $tmp = $inc; continue; } $tmp[$v['_attributes']['as']] = $inc; } } }