diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md
index 8426abd57b..63c244078f 100644
--- a/src/Symfony/Component/Config/CHANGELOG.md
+++ b/src/Symfony/Component/Config/CHANGELOG.md
@@ -6,6 +6,7 @@ CHANGELOG
* added numerical type handling for config definitions
* added convenience methods for optional configuration sections to ArrayNodeDefinition
+ * added a utils class for XML manipulations
2.1.0
-----
diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Util/document_type.xml b/src/Symfony/Component/Config/Tests/Fixtures/Util/document_type.xml
new file mode 100644
index 0000000000..4c25228263
--- /dev/null
+++ b/src/Symfony/Component/Config/Tests/Fixtures/Util/document_type.xml
@@ -0,0 +1,3 @@
+
+]>
+
diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Util/invalid.xml b/src/Symfony/Component/Config/Tests/Fixtures/Util/invalid.xml
new file mode 100644
index 0000000000..a07af9fd85
--- /dev/null
+++ b/src/Symfony/Component/Config/Tests/Fixtures/Util/invalid.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Util/invalid_schema.xml b/src/Symfony/Component/Config/Tests/Fixtures/Util/invalid_schema.xml
new file mode 100644
index 0000000000..e2725a2c2a
--- /dev/null
+++ b/src/Symfony/Component/Config/Tests/Fixtures/Util/invalid_schema.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Util/schema.xsd b/src/Symfony/Component/Config/Tests/Fixtures/Util/schema.xsd
new file mode 100644
index 0000000000..e56820f691
--- /dev/null
+++ b/src/Symfony/Component/Config/Tests/Fixtures/Util/schema.xsd
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Util/valid.xml b/src/Symfony/Component/Config/Tests/Fixtures/Util/valid.xml
new file mode 100644
index 0000000000..a96bb38267
--- /dev/null
+++ b/src/Symfony/Component/Config/Tests/Fixtures/Util/valid.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
new file mode 100644
index 0000000000..a3d264e189
--- /dev/null
+++ b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
@@ -0,0 +1,129 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Loader;
+
+use Symfony\Component\Config\Util\XmlUtils;
+
+class XmlUtilsTest extends \PHPUnit_Framework_TestCase
+{
+ public function testLoadFile()
+ {
+ $fixtures = __DIR__.'/../Fixtures/Util/';
+
+ try {
+ XmlUtils::loadFile($fixtures.'invalid.xml');
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('ERROR 77', $e->getMessage());
+ }
+
+ try {
+ XmlUtils::loadFile($fixtures.'document_type.xml');
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('Document types are not allowed', $e->getMessage());
+ }
+
+ try {
+ XmlUtils::loadFile($fixtures.'invalid_schema.xml', $fixtures.'schema.xsd');
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('ERROR 1845', $e->getMessage());
+ }
+
+ try {
+ XmlUtils::loadFile($fixtures.'invalid_schema.xml', 'invalid_callback_or_file');
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('XSD file or callable', $e->getMessage());
+ }
+
+ $mock = $this->getMock(__NAMESPACE__.'\Validator');
+ $mock->expects($this->exactly(2))->method('validate')->will($this->onConsecutiveCalls(false, true));
+
+ try {
+ XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate'));
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('is not valid', $e->getMessage());
+ }
+
+ $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate')));
+ }
+
+ /**
+ * @dataProvider getDataForConvertDomToArray
+ */
+ public function testConvertDomToArray($expected, $xml, $root = false, $checkPrefix = true)
+ {
+ $dom = new \DOMDocument();
+ $dom->loadXML($root ? $xml : ''.$xml.'');
+
+ $this->assertSame($expected, XmlUtils::convertDomElementToArray($dom->documentElement, $checkPrefix));
+ }
+
+ public function getDataForConvertDomToArray()
+ {
+ return array(
+ array(null, ''),
+ array('bar', 'bar'),
+ array(array('bar' => 'foobar'), '', true),
+ array(array('foo' => null), ''),
+ array(array('foo' => 'bar'), 'bar'),
+ array(array('foo' => array('foo' => 'bar')), ''),
+ array(array('foo' => array('foo' => 'bar')), 'bar'),
+ array(array('foo' => array('foo' => 'bar', 'value' => 'text')), 'text'),
+ array(array('foo' => array('attr' => 'bar', 'foo' => 'text')), 'text'),
+ array(array('foo' => array('bar', 'text')), 'bartext'),
+ array(array('foo' => array(array('foo' => 'bar'), array('foo' => 'text'))), ''),
+ array(array('foo' => array('foo' => array('bar', 'text'))), 'text'),
+ array(array('foo' => 'bar'), 'bar'),
+ array(array('foo' => 'text'), 'text'),
+ array(array('foo' => array('bar' => 'bar', 'value' => 'text')), 'text', false, false),
+ array(array('attr' => 1, 'b' => 'hello'), 'hello2', true),
+ );
+ }
+
+ /**
+ * @dataProvider getDataForPhpize
+ */
+ public function testPhpize($expected, $value)
+ {
+ $this->assertSame($expected, XmlUtils::phpize($value));
+ }
+
+ public function getDataForPhpize()
+ {
+ return array(
+ array(null, 'null'),
+ array(true, 'true'),
+ array(false, 'false'),
+ array(null, 'Null'),
+ array(true, 'True'),
+ array(false, 'False'),
+ array(0, '0'),
+ array(1, '1'),
+ array(0777, '0777'),
+ array(255, '0xFF'),
+ array(100.0, '1e2'),
+ array(-120.0, '-1.2E2'),
+ array(-10100.1, '-10100.1'),
+ array(-10100.1, '-10,100.1'),
+ array('foo', 'foo'),
+ );
+ }
+}
+
+interface Validator
+{
+ public function validate();
+}
diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php
new file mode 100644
index 0000000000..9317e15e7c
--- /dev/null
+++ b/src/Symfony/Component/Config/Util/XmlUtils.php
@@ -0,0 +1,222 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Util;
+
+/**
+ * XMLUtils is a bunch of utility methods to XML operations.
+ *
+ * This class contains static methods only and is not meant to be instantiated.
+ *
+ * @author Fabien Potencier
+ * @author Martin HasoĊ
+ */
+class XmlUtils
+{
+ /**
+ * This class should not be instantiated
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Loads an XML file.
+ *
+ * @param string $file An XML file path
+ * @param string|callable $schemaOrCallable An XSD schema file path or callable
+ *
+ * @return \DOMDocument
+ *
+ * @throws \InvalidArgumentException When loading of XML file returns error
+ */
+ public static function loadFile($file, $schemaOrCallable = null)
+ {
+ $internalErrors = libxml_use_internal_errors(true);
+ $disableEntities = libxml_disable_entity_loader(true);
+ libxml_clear_errors();
+
+ $dom = new \DOMDocument();
+ $dom->validateOnParse = true;
+ if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
+ libxml_disable_entity_loader($disableEntities);
+
+ throw new \InvalidArgumentException(implode("\n", static::getXmlErrors($internalErrors)));
+ }
+
+ $dom->normalizeDocument();
+
+ libxml_use_internal_errors($internalErrors);
+ libxml_disable_entity_loader($disableEntities);
+
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ throw new \InvalidArgumentException('Document types are not allowed.');
+ }
+ }
+
+ if (null !== $schemaOrCallable) {
+ $internalErrors = libxml_use_internal_errors(true);
+ libxml_clear_errors();
+
+ $e = null;
+ if (is_callable($schemaOrCallable)) {
+ try {
+ $valid = call_user_func($schemaOrCallable, $dom, $internalErrors);
+ } catch (\Exception $e) {
+ $valid = false;
+ }
+ } elseif (!is_array($schemaOrCallable) && is_file((string) $schemaOrCallable)) {
+ $valid = @$dom->schemaValidate($schemaOrCallable);
+ } else {
+ libxml_use_internal_errors($internalErrors);
+
+ throw new \InvalidArgumentException('The schemaOrCallable argument has to be a valid path to XSD file or callable.');
+ }
+
+ if (!$valid) {
+ $messages = static::getXmlErrors($internalErrors);
+ if (empty($messages)) {
+ $messages = array(sprintf('The XML file "%s" is not valid.', $file));
+ }
+ throw new \InvalidArgumentException(implode("\n", $messages), 0, $e);
+ }
+
+ libxml_use_internal_errors($internalErrors);
+ }
+
+ return $dom;
+ }
+
+ /**
+ * Converts a \DomElement object to a PHP array.
+ *
+ * The following rules applies during the conversion:
+ *
+ * * Each tag is converted to a key value or an array
+ * if there is more than one "value"
+ *
+ * * The content of a tag is set under a "value" key (bar)
+ * if the tag also has some nested tags
+ *
+ * * The attributes are converted to keys ()
+ *
+ * * The nested-tags are converted to keys (bar)
+ *
+ * @param \DomElement $element A \DomElement instance
+ * @param Boolean $checkPrefix Check prefix in an element or an attribute name
+ *
+ * @return array A PHP array
+ */
+ public static function convertDomElementToArray(\DomElement $element, $checkPrefix = true)
+ {
+ $prefix = (string) $element->prefix;
+ $empty = true;
+ $config = array();
+ foreach ($element->attributes as $name => $node) {
+ if ($checkPrefix && !in_array((string) $node->prefix, array('', $prefix), true)) {
+ continue;
+ }
+ $config[$name] = static::phpize($node->value);
+ $empty = false;
+ }
+
+ $nodeValue = false;
+ foreach ($element->childNodes as $node) {
+ if ($node instanceof \DOMText) {
+ if (trim($node->nodeValue)) {
+ $nodeValue = trim($node->nodeValue);
+ $empty = false;
+ }
+ } elseif ($checkPrefix && $prefix != (string) $node->prefix) {
+ continue;
+ } elseif (!$node instanceof \DOMComment) {
+ $value = static::convertDomElementToArray($node, $checkPrefix);
+
+ $key = $node->localName;
+ if (isset($config[$key])) {
+ if (!is_array($config[$key]) || !is_int(key($config[$key]))) {
+ $config[$key] = array($config[$key]);
+ }
+ $config[$key][] = $value;
+ } else {
+ $config[$key] = $value;
+ }
+
+ $empty = false;
+ }
+ }
+
+ if (false !== $nodeValue) {
+ $value = static::phpize($nodeValue);
+ if (count($config)) {
+ $config['value'] = $value;
+ } else {
+ $config = $value;
+ }
+ }
+
+ return !$empty ? $config : null;
+ }
+
+ /**
+ * Converts an xml value to a php type.
+ *
+ * @param mixed $value
+ *
+ * @return mixed
+ */
+ public static function phpize($value)
+ {
+ $value = (string) $value;
+ $lowercaseValue = strtolower($value);
+
+ switch (true) {
+ case 'null' === $lowercaseValue:
+ return null;
+ case ctype_digit($value):
+ $raw = $value;
+ $cast = intval($value);
+
+ return '0' == $value[0] ? octdec($value) : (((string) $raw == (string) $cast) ? $cast : $raw);
+ case 'true' === $lowercaseValue:
+ return true;
+ case 'false' === $lowercaseValue:
+ return false;
+ case is_numeric($value):
+ return '0x' == $value[0].$value[1] ? hexdec($value) : floatval($value);
+ case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $value):
+ return floatval(str_replace(',', '', $value));
+ default:
+ return $value;
+ }
+ }
+
+ protected static function getXmlErrors($internalErrors)
+ {
+ $errors = array();
+ foreach (libxml_get_errors() as $error) {
+ $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
+ LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
+ $error->code,
+ trim($error->message),
+ $error->file ? $error->file : 'n/a',
+ $error->line,
+ $error->column
+ );
+ }
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+
+ return $errors;
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
index 6f2c8eba1a..f8f4336736 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Alias;
@@ -202,33 +203,17 @@ class XmlFileLoader extends FileLoader
*
* @return SimpleXMLElement
*
- * @throws \InvalidArgumentException When loading of XML file returns error
+ * @throws InvalidArgumentException When loading of XML file returns error
*/
protected function parseFile($file)
{
- $internalErrors = libxml_use_internal_errors(true);
- $disableEntities = libxml_disable_entity_loader(true);
- libxml_clear_errors();
-
- $dom = new \DOMDocument();
- $dom->validateOnParse = true;
- if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
- libxml_disable_entity_loader($disableEntities);
-
- throw new InvalidArgumentException(implode("\n", $this->getXmlErrors($internalErrors)));
- }
- $dom->normalizeDocument();
-
- libxml_use_internal_errors($internalErrors);
- libxml_disable_entity_loader($disableEntities);
-
- foreach ($dom->childNodes as $child) {
- if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
- throw new InvalidArgumentException('Document types are not allowed.');
- }
+ try {
+ $dom = XmlUtils::loadFile($file, array($this, 'validateSchema'));
+ } catch (\InvalidArgumentException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
- $this->validate($dom, $file);
+ $this->validateExtensions($dom, $file);
return simplexml_import_dom($dom, 'Symfony\\Component\\DependencyInjection\\SimpleXMLElement');
}
@@ -285,28 +270,14 @@ class XmlFileLoader extends FileLoader
}
}
- /**
- * Validates an XML document.
- *
- * @param \DOMDocument $dom
- * @param string $file
- */
- private function validate(\DOMDocument $dom, $file)
- {
- $this->validateSchema($dom, $file);
- $this->validateExtensions($dom, $file);
- }
-
/**
* Validates a documents XML schema.
*
* @param \DOMDocument $dom
- * @param string $file
*
- * @throws RuntimeException When extension references a non-existent XSD file
- * @throws InvalidArgumentException When xml doesn't validate its xsd schema
+ * @throws RuntimeException When extension references a non-existent XSD file
*/
- private function validateSchema(\DOMDocument $dom, $file)
+ public function validateSchema(\DOMDocument $dom)
{
$schemaLocations = array('http://symfony.com/schema/dic/services' => str_replace('\\', '/', __DIR__.'/schema/dic/services/services-1.0.xsd'));
@@ -360,18 +331,13 @@ $imports
EOF
;
- $current = libxml_use_internal_errors(true);
- libxml_clear_errors();
-
$valid = @$dom->schemaValidateSource($source);
foreach ($tmpfiles as $tmpfile) {
@unlink($tmpfile);
}
- if (!$valid) {
- throw new InvalidArgumentException(implode("\n", $this->getXmlErrors($current)));
- }
- libxml_use_internal_errors($current);
+
+ return $valid;
}
/**
@@ -403,33 +369,6 @@ EOF
}
}
- /**
- * Returns an array of XML errors.
- *
- * @param Boolean $internalErrors
- *
- * @return array
- */
- private function getXmlErrors($internalErrors)
- {
- $errors = array();
- foreach (libxml_get_errors() as $error) {
- $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
- LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
- $error->code,
- trim($error->message),
- $error->file ? $error->file : 'n/a',
- $error->line,
- $error->column
- );
- }
-
- libxml_clear_errors();
- libxml_use_internal_errors($internalErrors);
-
- return $errors;
- }
-
/**
* Loads from an extension.
*
@@ -472,50 +411,6 @@ EOF
*/
public static function convertDomElementToArray(\DomElement $element)
{
- $empty = true;
- $config = array();
- foreach ($element->attributes as $name => $node) {
- $config[$name] = SimpleXMLElement::phpize($node->value);
- $empty = false;
- }
-
- $nodeValue = false;
- foreach ($element->childNodes as $node) {
- if ($node instanceof \DOMText) {
- if (trim($node->nodeValue)) {
- $nodeValue = trim($node->nodeValue);
- $empty = false;
- }
- } elseif (!$node instanceof \DOMComment) {
- if ($node instanceof \DOMElement && '_services' === $node->nodeName) {
- $value = new Reference($node->getAttribute('id'));
- } else {
- $value = static::convertDomElementToArray($node);
- }
-
- $key = $node->localName;
- if (isset($config[$key])) {
- if (!is_array($config[$key]) || !is_int(key($config[$key]))) {
- $config[$key] = array($config[$key]);
- }
- $config[$key][] = $value;
- } else {
- $config[$key] = $value;
- }
-
- $empty = false;
- }
- }
-
- if (false !== $nodeValue) {
- $value = SimpleXMLElement::phpize($nodeValue);
- if (count($config)) {
- $config['value'] = $value;
- } else {
- $config = $value;
- }
- }
-
- return !$empty ? $config : null;
+ return XmlUtils::convertDomElementToArray($element);
}
}
diff --git a/src/Symfony/Component/DependencyInjection/SimpleXMLElement.php b/src/Symfony/Component/DependencyInjection/SimpleXMLElement.php
index d154602fd3..cc5e311987 100644
--- a/src/Symfony/Component/DependencyInjection/SimpleXMLElement.php
+++ b/src/Symfony/Component/DependencyInjection/SimpleXMLElement.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\DependencyInjection;
+use Symfony\Component\Config\Util\XmlUtils;
+
/**
* SimpleXMLElement class.
*
@@ -101,27 +103,6 @@ class SimpleXMLElement extends \SimpleXMLElement
*/
public static function phpize($value)
{
- $value = (string) $value;
- $lowercaseValue = strtolower($value);
-
- switch (true) {
- case 'null' === $lowercaseValue:
- return null;
- case ctype_digit($value):
- $raw = $value;
- $cast = intval($value);
-
- return '0' == $value[0] ? octdec($value) : (((string) $raw == (string) $cast) ? $cast : $raw);
- case 'true' === $lowercaseValue:
- return true;
- case 'false' === $lowercaseValue:
- return false;
- case is_numeric($value):
- return '0x' == $value[0].$value[1] ? hexdec($value) : floatval($value);
- case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $value):
- return floatval(str_replace(',', '', $value));
- default:
- return $value;
- }
+ return XmlUtils::phpize($value);
}
}
diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
index a07c7f80a5..00a6012719 100644
--- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
@@ -15,6 +15,7 @@ use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Loader\FileLoader;
+use Symfony\Component\Config\Util\XmlUtils;
/**
* XmlFileLoader loads XML routing files.
@@ -172,74 +173,7 @@ class XmlFileLoader extends FileLoader
*/
protected function loadFile($file)
{
- $internalErrors = libxml_use_internal_errors(true);
- $disableEntities = libxml_disable_entity_loader(true);
- libxml_clear_errors();
-
- $dom = new \DOMDocument();
- $dom->validateOnParse = true;
- if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
- libxml_disable_entity_loader($disableEntities);
-
- throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($internalErrors)));
- }
- $dom->normalizeDocument();
-
- libxml_use_internal_errors($internalErrors);
- libxml_disable_entity_loader($disableEntities);
-
- foreach ($dom->childNodes as $child) {
- if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
- throw new \InvalidArgumentException('Document types are not allowed.');
- }
- }
-
- $this->validate($dom);
-
- return $dom;
- }
-
- /**
- * Validates a loaded XML file.
- *
- * @param \DOMDocument $dom A loaded XML file
- *
- * @throws \InvalidArgumentException When XML doesn't validate its XSD schema
- */
- protected function validate(\DOMDocument $dom)
- {
- $current = libxml_use_internal_errors(true);
- libxml_clear_errors();
-
- if (!$dom->schemaValidate(__DIR__ . static::SCHEME_PATH)) {
- throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($current)));
- }
- libxml_use_internal_errors($current);
- }
-
- /**
- * Retrieves libxml errors and clears them.
- *
- * @return array An array of libxml error strings
- */
- private function getXmlErrors($internalErrors)
- {
- $errors = array();
- foreach (libxml_get_errors() as $error) {
- $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
- LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
- $error->code,
- trim($error->message),
- $error->file ? $error->file : 'n/a',
- $error->line,
- $error->column
- );
- }
-
- libxml_clear_errors();
- libxml_use_internal_errors($internalErrors);
-
- return $errors;
+ return XmlUtils::loadFile($file, __DIR__ . static::SCHEME_PATH);
}
/**
diff --git a/src/Symfony/Component/Validator/Mapping/Loader/XmlFileLoader.php b/src/Symfony/Component/Validator/Mapping/Loader/XmlFileLoader.php
index 4925abb44d..6b25f18817 100644
--- a/src/Symfony/Component/Validator/Mapping/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/Validator/Mapping/Loader/XmlFileLoader.php
@@ -13,6 +13,7 @@ namespace Symfony\Component\Validator\Mapping\Loader;
use Symfony\Component\Validator\Exception\MappingException;
use Symfony\Component\Validator\Mapping\ClassMetadata;
+use Symfony\Component\Config\Util\XmlUtils;
class XmlFileLoader extends FileLoader
{
@@ -185,54 +186,12 @@ class XmlFileLoader extends FileLoader
*/
protected function parseFile($file)
{
- $internalErrors = libxml_use_internal_errors(true);
- $disableEntities = libxml_disable_entity_loader(true);
- libxml_clear_errors();
-
- $dom = new \DOMDocument();
- $dom->validateOnParse = true;
- if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
- libxml_disable_entity_loader($disableEntities);
-
- throw new MappingException(implode("\n", $this->getXmlErrors($internalErrors)));
- }
-
- libxml_disable_entity_loader($disableEntities);
-
- if (!$dom->schemaValidate(__DIR__.'/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd')) {
- throw new MappingException(implode("\n", $this->getXmlErrors($internalErrors)));
- }
-
- $dom->normalizeDocument();
-
- libxml_use_internal_errors($internalErrors);
-
- foreach ($dom->childNodes as $child) {
- if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
- throw new MappingException('Document types are not allowed.');
- }
+ try {
+ $dom = XmlUtils::loadFile($file, __DIR__.'/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd');
+ } catch (\Exception $e) {
+ throw new MappingException($e->getMessage(), $e->getCode(), $e);
}
return simplexml_import_dom($dom);
}
-
- protected function getXmlErrors($internalErrors)
- {
- $errors = array();
- foreach (libxml_get_errors() as $error) {
- $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
- LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
- $error->code,
- trim($error->message),
- $error->file ? $error->file : 'n/a',
- $error->line,
- $error->column
- );
- }
-
- libxml_clear_errors();
- libxml_use_internal_errors($internalErrors);
-
- return $errors;
- }
}
diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json
index a52d33bb21..e3cb106914 100644
--- a/src/Symfony/Component/Validator/composer.json
+++ b/src/Symfony/Component/Validator/composer.json
@@ -21,12 +21,14 @@
"require-dev": {
"symfony/http-foundation": "2.2.*",
"symfony/locale": "2.2.*",
- "symfony/yaml": "2.2.*"
+ "symfony/yaml": "2.2.*",
+ "symfony/config": "2.2.*"
},
"suggest": {
"doctrine/common": ">=2.1,<2.4-dev",
"symfony/http-foundation": "2.2.*",
- "symfony/yaml": "2.2.*"
+ "symfony/yaml": "2.2.*",
+ "symfony/config": "2.2.*"
},
"autoload": {
"psr-0": { "Symfony\\Component\\Validator\\": "" }