Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
70.00% |
14 / 20 |
CRAP | |
80.77% |
105 / 130 |
DomDocument | |
0.00% |
0 / 1 |
|
70.00% |
14 / 20 |
57.77 | |
80.77% |
105 / 130 |
__construct($version = "1.0", $encoding = "UTF-8") | |
100.00% |
1 / 1 |
2 | |
100.00% |
6 / 6 |
|||
load($filename, $options = 0) | |
100.00% |
1 / 1 |
1 | |
100.00% |
8 / 8 |
|||
loadXml($source, $options = 0) | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 8 |
|||
schemaValidate($filename) | |
0.00% |
0 / 1 |
2.01 | |
88.89% |
8 / 9 |
|||
schemaValidateSource($source) | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 9 |
|||
xinclude($options = 0) | |
100.00% |
1 / 1 |
1 | |
100.00% |
7 / 7 |
|||
getXpath() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getElementValue($element_name, $reference_element = null) | |
0.00% |
0 / 1 |
8.02 | |
93.75% |
15 / 16 |
|||
getElement($name) | |
100.00% |
1 / 1 |
6 | |
100.00% |
10 / 10 |
|||
setDefaultNamespace($prefix = self::NAMESPACE_PREFIX, $uri = self::NAMESPACE_ENVIRONAUT_1_0) | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
getDefaultNamespaceUri() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getDefaultNamespacePrefix() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
isEnvironautDocument() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
registerEnvironautNamespace(DOMDocument $doc) | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
isEnvironautConfigurationDocument(DOMDocument $doc) | |
100.00% |
1 / 1 |
3 | |
100.00% |
4 / 4 |
|||
refreshXpath() | |
100.00% |
1 / 1 |
2 | |
100.00% |
6 / 6 |
|||
enableErrorHandling() | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
handleErrors($msg_prefix = '', $msg_suffix = '', $user_error_handling = false) | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
getErrorMessage(array $errors) | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
parseError(\LibXMLError $error) | |
0.00% |
0 / 1 |
5.20 | |
80.00% |
16 / 20 |
<?php | |
namespace Environaut\Config\Reader\Dom; | |
/** | |
* Environaut DOM document implementation with convenience wrapper methods | |
* that by default use the Environaut configuration namespace for queries. | |
*/ | |
class DomDocument extends \DOMDocument | |
{ | |
/** | |
* Default namespace of Environaut configuration files. | |
*/ | |
const NAMESPACE_ENVIRONAUT_1_0 = 'http://mivesto.de/environaut/config/1.0'; | |
/** | |
* Default namespace prefix for Environaut configuration files. | |
*/ | |
const NAMESPACE_PREFIX = 'ec'; | |
/** | |
* @var \DOMXpath xpath instance for this document | |
*/ | |
protected $xpath = null; | |
/** | |
* @var string default URI used as namespace for the document | |
*/ | |
protected $default_namespace_uri; | |
/** | |
* @var string default prefix for the default namespace of this document | |
*/ | |
protected $default_namespace_prefix; | |
/** | |
* @var array map of DOM classes and our implementations of them | |
*/ | |
protected $class_map = array( | |
'DOMAttr' => 'Environaut\Config\Reader\Dom\DomAttribute', | |
'DOMDocument' => 'Environaut\Config\Reader\Dom\DomDocument', | |
'DOMElement' => 'Environaut\Config\Reader\Dom\DomElement' | |
); | |
/** | |
* Creates a new DomDocument instance. | |
* | |
* @param string $version | |
* @param string $encoding | |
*/ | |
public function __construct($version = "1.0", $encoding = "UTF-8") | |
{ | |
parent::__construct($version, $encoding); | |
foreach ($this->class_map as $dom_class => $environaut_class) { | |
$this->registerNodeClass($dom_class, $environaut_class); | |
} | |
$this->xpath = new \DOMXPath($this); | |
} | |
/** | |
* Loads XML from a file and registers the Environaut configuration | |
* namespace if the XML document is an Environaut configuration file. | |
* | |
* @param string $filename xml file to load | |
* @param int $options libXml flags to use for loading (like LIBXML_NOCDATA etc.) | |
* | |
* @return bool true on success; false on error | |
* | |
* @throws \DOMException in case of errors loading the document from the given file | |
*/ | |
public function load($filename, $options = 0) | |
{ | |
$user_error_handling = $this->enableErrorHandling(); | |
$success = parent::load($filename, $options); | |
$this->handleErrors( | |
'Loading the document failed. Details are:' . PHP_EOL . PHP_EOL, | |
PHP_EOL . 'Please fix the mentioned errors.', | |
$user_error_handling | |
); | |
$this->refreshXpath(); | |
return $success; | |
} | |
/** | |
* Loads XML from a string and registers the Environaut configuration | |
* namespace if the XML document is an Environaut configuration file. | |
* | |
* @param string $source xml string to load | |
* @param int $options libXml flags to use for loading (like LIBXML_NOCDATA etc.) | |
* | |
* @return bool true on success; false on error | |
* | |
* @throws \DOMException in case of errors loading the document from the given string | |
*/ | |
public function loadXml($source, $options = 0) | |
{ | |
$user_error_handling = $this->enableErrorHandling(); | |
$success = parent::loadXML($source, $options); | |
$this->handleErrors( | |
'Loading the document failed. Details are:' . PHP_EOL . PHP_EOL, | |
PHP_EOL . 'Please fix the mentioned errors.', | |
$user_error_handling | |
); | |
$this->refreshXpath(); | |
return $success; | |
} | |
/** | |
* Validates the current document according to the given schema file. | |
* | |
* @param string $filename path to the schema file | |
* | |
* @return bool true on success | |
* | |
* @throws \DomException in case of validation errors or non-readable file | |
*/ | |
public function schemaValidate($filename) | |
{ | |
if (!is_readable($filename)) { | |
throw new \DOMException("Schema file is not readable: $filename"); | |
} | |
$user_error_handling = $this->enableErrorHandling(); | |
$success = parent::schemaValidate($filename); | |
$this->handleErrors( | |
'Validating the document failed. Details are:' . PHP_EOL . PHP_EOL, | |
PHP_EOL . 'Please fix the mentioned errors or use another schema file.', | |
$user_error_handling | |
); | |
return $success; | |
} | |
/** | |
* Validates the current document according to the given schema file content. | |
* | |
* @param string $source content of a schema file | |
* | |
* @return bool true on success | |
* | |
* @throws \DomException in case of validation errors or empty schema | |
*/ | |
public function schemaValidateSource($source) | |
{ | |
if (empty($source)) { | |
throw new \DOMException('Schema is empty.'); | |
} | |
$user_error_handling = $this->enableErrorHandling(); | |
$success = parent::schemaValidateSource($source); | |
$this->handleErrors( | |
'Validating the document failed. Details are:' . PHP_EOL . PHP_EOL, | |
PHP_EOL . 'Please fix the mentioned errors or use another schema.', | |
$user_error_handling | |
); | |
return $success; | |
} | |
/** | |
* Substitutes XIncludes present in the current document. | |
* | |
* @param int $options libXml flags to use for loading (like LIBXML_NOCDATA etc.) | |
* | |
* @return int number of XIncludes or false if no xincludes were found | |
* | |
* @throws \DOMException in case of errors xincluding content | |
*/ | |
public function xinclude($options = 0) | |
{ | |
$user_error_handling = $this->enableErrorHandling(); | |
$number_of_xincludes = parent::xinclude($options); | |
$this->handleErrors( | |
'Resolving XInclude directives in the current document failed. Details are:' . PHP_EOL . PHP_EOL, | |
PHP_EOL . 'Please fix the XInclude directives according to the mentioned errors.', | |
$user_error_handling | |
); | |
return $number_of_xincludes; | |
} | |
/** | |
* Returns the xpath instance that handles this document. | |
* | |
* @return \DOMXpath instance | |
*/ | |
public function getXpath() | |
{ | |
return $this->xpath; | |
} | |
/** | |
* Returns the nodeValue of the child element with the given name. | |
* | |
* @param string $element_name name of child element | |
* @param \DomElement $reference_element reference element for child node iteration, default to documentElement | |
* | |
* @return mixed nodeValue or null if Environaut element with that name does not exist | |
* | |
* @throws \InvalidArgumentException if name is empty | |
*/ | |
public function getElementValue($element_name, $reference_element = null) | |
{ | |
$element_name = trim($element_name); | |
if (empty($element_name)) { | |
throw new \InvalidArgumentException('Element name must not be empty.'); | |
} | |
if (null === $reference_element) { | |
$reference_element = $this->documentElement; | |
} | |
if ($this->isEnvironautDocument()) { | |
foreach ($reference_element->childNodes as $node) { | |
if ($node->nodeType == XML_ELEMENT_NODE && | |
$node->localName == $element_name && | |
$node->namespaceURI == $this->documentElement->namespaceURI | |
) { | |
return $node->nodeValue; | |
} | |
} | |
} | |
return null; | |
} | |
/** | |
* Returns the DomElement with the given name. | |
* | |
* @param string $name of the element to get | |
* | |
* @return DomElement of that name or null if does not exist in the Environaut namespace | |
*/ | |
public function getElement($name) | |
{ | |
if ($this->isEnvironautDocument()) { | |
foreach ($this->documentElement->childNodes as $node) { | |
if ($node->nodeType == XML_ELEMENT_NODE && | |
$node->localName == $name && | |
$node->namespaceURI == $this->documentElement->namespaceURI | |
) { | |
return $node; | |
} | |
} | |
} | |
return null; | |
} | |
/** | |
* Set the default namespace that should be used when accessing elements via | |
* convenience methods and bind it to the internal xpath instance. | |
* | |
* @param string $prefix default prefix to use | |
* @param string $uri namespace URI | |
*/ | |
public function setDefaultNamespace($prefix = self::NAMESPACE_PREFIX, $uri = self::NAMESPACE_ENVIRONAUT_1_0) | |
{ | |
$this->default_namespace_uri = $uri; | |
$this->default_namespace_prefix = $prefix; | |
$this->xpath->registerNamespace($prefix, $uri); | |
} | |
/** | |
* Returns the default namespace URI used by Environaut. | |
* | |
* @return string default namespace URI | |
*/ | |
public function getDefaultNamespaceUri() | |
{ | |
return $this->default_namespace_uri; | |
} | |
/** | |
* Returns the default namespace prefix used by Environaut | |
* | |
* @return string default namespace prefix | |
*/ | |
public function getDefaultNamespacePrefix() | |
{ | |
return $this->default_namespace_prefix; | |
} | |
/** | |
* Returns whether the current document is an Environaut configuration file. | |
* | |
* @return bool true if it's an Environaut document; false otherwise | |
*/ | |
public function isEnvironautDocument() | |
{ | |
return self::isEnvironautConfigurationDocument($this); | |
} | |
/** | |
* Registers the default Environaut namespace on the internal xpath | |
* instance of the given DomDocument instance. | |
* | |
* @param DOMDocument $doc document instance | |
*/ | |
public static function registerEnvironautNamespace(DOMDocument $doc) | |
{ | |
$doc->getXpath()->registerNamespace(self::NAMESPACE_PREFIX, self::NAMESPACE_ENVIRONAUT_1_0); | |
} | |
/** | |
* Returns whether the given document instance is an Environaut configuration file. | |
* | |
* @param DOMDocument $doc document to check | |
* | |
* @return bool true if it's an Environaut document; false otherwise | |
*/ | |
public static function isEnvironautConfigurationDocument(DOMDocument $doc) | |
{ | |
return ( | |
$doc->documentElement && | |
$doc->documentElement->localName === 'environaut' && | |
$doc->documentElement->namespaceURI === self::NAMESPACE_ENVIRONAUT_1_0 | |
); | |
} | |
/** | |
* Re-instantiates the internal xpath instance and then | |
* registers the Environaut config namespace if necessary. | |
*/ | |
protected function refreshXpath() | |
{ | |
unset($this->xpath); | |
$this->xpath = new \DOMXPath($this); | |
if ($this->isEnvironautDocument()) { | |
$this->setDefaultNamespace(self::NAMESPACE_PREFIX, self::NAMESPACE_ENVIRONAUT_1_0); | |
} | |
} | |
/** | |
* Disables libXml errors to let us handle errors by ourselves. | |
* | |
* @return bool whether or not the internal error handling was enabled before | |
*/ | |
protected function enableErrorHandling() | |
{ | |
$user_error_handling = libxml_use_internal_errors(true); | |
libxml_clear_errors(); | |
return $user_error_handling; | |
} | |
/** | |
* Evaluates the last libXml operation and throws an exception | |
* with a verbose multiline error message as text. | |
* | |
* @param string $msg_prefix prefix for the error message of the exception | |
* @param string $msg_suffix suffix for the error message of the exception | |
* @param bool $user_error_handling | |
* | |
* @throws \DOMException when libXml errors occurred | |
*/ | |
protected function handleErrors($msg_prefix = '', $msg_suffix = '', $user_error_handling = false) | |
{ | |
if (libxml_get_last_error() !== false) { | |
$errors = libxml_get_errors(); | |
libxml_clear_errors(); | |
libxml_use_internal_errors($user_error_handling); | |
throw new \DOMException( | |
$msg_prefix . | |
$this->getErrorMessage($errors) . | |
$msg_suffix | |
); | |
} | |
libxml_use_internal_errors($user_error_handling); | |
} | |
/** | |
* Returns a formatted error message from the given libXml errors. | |
* | |
* @param array $errors array of \LibXMLError instances | |
* | |
* @return string formatted error message | |
*/ | |
protected function getErrorMessage(array $errors) | |
{ | |
$error_message = ''; | |
foreach ($errors as $error) { | |
$error_message .= $this->parseError($error) . PHP_EOL . PHP_EOL; | |
} | |
return $error_message; | |
} | |
/** | |
* Formats the given libXml error as a multiline string. | |
* | |
* @param \LibXMLError $error error to get as formatted string | |
* | |
* @return string formatted error message | |
*/ | |
protected function parseError(\LibXMLError $error) | |
{ | |
$msg = ''; | |
switch ($error->level) { | |
case LIBXML_ERR_WARNING: | |
$msg .= 'Warning ' . $error->code . ': '; | |
break; | |
case LIBXML_ERR_FATAL: | |
$msg .= 'Fatal error: ' . $error->code . ': '; | |
break; | |
case LIBXML_ERR_ERROR: | |
default: | |
$msg .= 'Error ' . $error->code . ': '; | |
break; | |
} | |
$msg .= trim($error->message) . PHP_EOL . | |
' Line: ' . $error->line . PHP_EOL . | |
'Column: ' . $error->column; | |
if ($error->file) { | |
$msg .= PHP_EOL . ' File: ' . $error->file; | |
} | |
return $msg; | |
} | |
} |