Location: PHPKode > scripts > Claw > claw/ext/XMLClawConfig.php
<?php

/**
 * Claw configuration handler. Deals with XML files.
 *
 * @package claw.ext
 * @author Tomas Varaneckas <tomas [dot] varaneckas [at] gmail [dot] com>
 * @version $Id: XMLClawConfig.php 120 2006-03-19 19:26:44Z spajus $
 */
class XMLClawConfig implements ClawConfig
{
	/**
	 * Config xml object
	 *
	 * @var SimpleXMLElement
	 */
	protected $config;

	/**
	 * Constructor, which also loads default configuration file
	 * 
	 * @param string $default default configuration file (optional)
	 */
	public function __construct($default = null)
	{
		$default = $default == null ? 'default.cfg.xml' : $default;
		$this->load($default);
	}

	/**
	 * Loads xml file and prepares for data retrieval with $this->get()
	 *
	 * @param string $xml_file path to XML file
	 * @return XMLClawConfig return self (for fluent interfaces)
	 */
	public function load($xml_file)
	{
		$xml = @simplexml_load_string(file_get_contents($xml_file, true));
		if (!($xml instanceof SimpleXMLElement))
		{
			throw new ClawException('Invalid XML file: ' . $xml_file);
		}
		if ($this->config instanceof SimpleXMLElement)
		{
			$this->merge($this->config, $xml);
		}
		else
		{
			$this->config = $xml;
		}
		return $this;
	}

	/**
	 * Gets configuration variable from loaded xmls.
	 * Accepts infinite xml tree depth.
	 *
	 * Usage:
	 *    $clawconfig->get('some', 'other') would get
	 *          <some><other>VALUE</other></some>
	 *    $clawconfig->get('third') would get <third>CONTENTS</third>
	 *    $clawconfig->get(array('some', 'other'))
	 *          would get same as example 1
	 *
	 * Returns mixed value if xml node has no children
	 * OR SimpleXMLElement object if children exist.
	 *
	 * @return string
	 */
	public function get()
	{
		return trim(strval($this->getPart(func_get_args())));
	}

	
	/**
	 * Checks if a variable or variable group exists in configuration file
	 * (depending on implementation)
	 *
	 * @return bool
	 */		
	public function has()
	{
		$args = func_get_args();
		if (is_array($args[0]))
		{
			$args = $args[0];
		}
		$var = $this->config;
		foreach ($args as $arg)
		{
			$var = & $var->$arg;
			if (empty($var))
			{
				return false;
			}
		}
		return true;	
	}

	/**
	 * Gets a segment of XML config as SimpleXMLElement
	 *
	 * @return SimpleXMLElement
	 */
	public function getPart()
	{
		$args = func_get_args();
		if (is_array($args[0]))
		{
			$args = $args[0];
		}
		$var = $this->config;
		foreach ($args as $arg)
		{
			$var = & $var->$arg;
			if (empty($var))
			{
				throw new ClawException('Config part '
					. implode('->', $args) . ' is not defined.');
			}
		}
		return $var;
	}

	/**
	 * Gets part of configuration as array
	 * Limitation of 1 level of depth...
	 *
	 * @return Array
	 */
	public function getArray()
	{
		$array = array();
		$xml = $this->getPart(func_get_args());
		foreach ($xml->children() as $key => $value)
		{
			$array[$key] = strval($value);
		}
		return $array;
	}

	/**
	 * Sets configuration variable.
	 * At least two parameters (key and value) are required.
	 * First arguments are keys (can be one to infinity)
	 * Last argument is value
	 *
	 * Usage:
	 *    $cfg->set('claw_renderer', 'engine', 'SmartyClawRenderer');
	 *    would virtually append configuration file with:
	 *    <claw_renderer><engine>SmartyClawRenderer</engine></claw_renderer>
	 *    Safely merges variables.
	 * 
	 * @return XMLClawConfig return self (for fluent interfaces)
	 */
	public function set()
	{
		$args = func_get_args();
		if (count($args) < 2)
		{
			throw new ClawException('At least two parameters are required.');
		}
		$value = array_pop($args);
		while ($arg = array_pop($args))
		{
			$value = "<$arg>$value</$arg>";
		}
		$this->merge($this->config,
		             simplexml_load_string('<?xml version="1.0"?><config>'
		             . $value . '</config>'));
		return $this;
	}

	/**
	 * Either returns or saves current config as XML string/file
	 *
	 * @param string $xml_file_path Path to new file
	 *        (optional, if not given - a string will be returned)
	 * @return string|bool
	 */
	public function asXML($xml_file_path = null)
	{
		if (strlen($xml_file_path))
		{
			@touch($xml_file_path);
			if (!is_writable($xml_file_path))
			{
				throw new ClawException('File not writable: '
					. $xml_file_path);
			}
		}
		return $this->config->asXML($xml_file_path);
	}

	/**
	 * Merges two SimpleXMLElement objects into one.
	 * Overwrites existing values!
	 *
	 * @param SimpleXMLElement $xml1 first object
	 *        (that will be filled with second one)
	 * @param SimpleXMLElement $xml2 second object
	 */
	protected function merge(SimpleXMLElement &$xml1, SimpleXMLElement $xml2)
	{
		$dom1 = new DomDocument();
		$dom2 = new DomDocument();
		$dom1->loadXML($xml1->asXML());
		$dom2->loadXML($xml2->asXML());

		$xpath = new domXPath($dom1);
		$xpath_query = $xpath->query('/*/*');
		for ($i = 0; $i < $xpath_query->length; $i++)
		{
			$dom2->documentElement->appendChild(
			$dom2->importNode($xpath_query->item($i), true));
		}
		$xml1 = simplexml_import_dom($dom2);
	}
}
?>
Return current item: Claw