8000 [Config] extracted the xml parsing from XmlUtils::loadFile into XmlUtils::parse by Basster · Pull Request #23485 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Config] extracted the xml parsing from XmlUtils::loadFile into XmlUtils::parse #23485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
16 changes: 15 additions & 1 deletion src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,27 @@ public function testLoadFile()
XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate'));
$this->fail();
} catch (\InvalidArgumentException $e) {
$this->assertContains('is not valid', $e->getMessage());
$this->assertRegExp('/The XML file "[\w:\/\\\.]+" is not valid\./', $e->getMessage());
}

$this->assertInstanceOf('DOMDocument', XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate')));
$this->assertSame(array(), libxml_get_errors());
}

/**
* @expectedException \Symfony\Component\Config\Util\Exception\InvalidXmlException
* @expectedExceptionMessage The XML is not valid
*/
public function testParseWithInvalidValidatorCallable()
{
$fixtures = __DIR__.'/../Fixtures/Util/';

$mock = $this->getMockBuilder(__NAMESPACE__.'\Validator')->getMock();
$mock->expects($this->once())->method('validate')->willReturn(false);

XmlUtils::parse(file_get_contents($fixtures.'valid.xml'), array($mock, 'validate'));
}

public function testLoadFileWithInternalErrorsEnabled()
{
$internalErrors = libxml_use_internal_errors(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Config\Util\Exception;

/**
* Exception class for when XML parsing with an XSD schema file path or a callable validator produces errors unrelated
* to the actual XML parsing.
*
* @author Ole Rößner <ole@roessner.it>
*/
class InvalidXmlException extends XmlParsingException
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Config\Util\Exception;

/**
* Exception class for when XML cannot be parsed properly.
*
* @author Ole Rößner <ole@roessner.it>
*/
class XmlParsingException extends \InvalidArgumentException
{
}
56 changes: 41 additions & 15 deletions src/Symfony/Component/Config/Util/XmlUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@

namespace Symfony\Component\Config\Util;

use Symfony\Component\Config\Util\Exception\InvalidXmlException;
use Symfony\Component\Config\Util\Exception\XmlParsingException;

/**
* 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 <fabien@symfony.com>
* @author Martin Hasoň <martin.hason@gmail.com>
* @author Ole Rößner <ole@roessner.it>
*/
class XmlUtils
{
Expand All @@ -29,27 +33,23 @@ private function __construct()
}

/**
* Loads an XML file.
* Parses an XML string.
*
* @param string $file An XML file path
* @param string $content An XML string
* @param string|callable|null $schemaOrCallable An XSD schema file path, a callable, or null to disable validation
*
* @return \DOMDocument
*
* @throws \InvalidArgumentException When loading of XML file returns error
* @throws \RuntimeException When DOM extension is missing
* @throws \Symfony\Component\Config\Util\Exception\XmlParsingException When parsing of XML file returns error
* @throws \Symfony\Component\Config\Util\Exception\InvalidXmlException When parsing of XML with schema or callable produces any errors unrelated to the XML parsing itself
* @throws \RuntimeException When DOM extension is missing
*/
public static function loadFile($file, $schemaOrCallable = null)
public static function parse($content, $schemaOrCallable = null)
{
if (!extension_loaded('dom')) {
throw new \RuntimeException('Extension DOM is required.');
}

$content = @file_get_contents($file);
if ('' === trim($content)) {
throw new \InvalidArgumentException(sprintf('File %s does not contain valid XML, it is empty.', $file));
}

$internalErrors = libxml_use_internal_errors(true);
$disableEntities = libxml_disable_entity_loader(true);
libxml_clear_errors();
Expand All @@ -59,7 +59,7 @@ public static function loadFile($file, $schemaOrCallable = null)
if (!$dom->loadXML($content, LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
libxml_disable_entity_loader($disableEntities);

throw new \InvalidArgumentException(implode("\n", static::getXmlErrors($internalErrors)));
throw new XmlParsingException(implode("\n", static::getXmlErrors($internalErrors)));
}

$dom->normalizeDocument();
Expand All @@ -69,7 +69,7 @@ public static function loadFile($file, $schemaOrCallable = null)

foreach ($dom->childNodes as $child) {
if (XML_DOCUMENT_TYPE_NODE === $child->nodeType) {
throw new \InvalidArgumentException('Document types are not allowed.');
throw new XmlParsingException('Document types are not allowed.');
}
}

Expand All @@ -90,15 +90,15 @@ public static function loadFile($file, $schemaOrCallable = null)
} else {
libxml_use_internal_errors($internalErrors);

throw new \InvalidArgumentException('The schemaOrCallable argument has to be a valid path to XSD file or callable.');
throw new XmlParsingException('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 InvalidXmlException('The XML is not valid.', 0, $e);
}
throw new \InvalidArgumentException(implode("\n", $messages), 0, $e);
throw new XmlParsingException(implode("\n", $messages), 0, $e);
}
}

Expand All @@ -108,6 +108,32 @@ public static function loadFile($file, $schemaOrCallable = null)
return $dom;
}

/**
* Loads an XML file.
*
* @param string $file An XML file path
* @param string|callable|null $schemaOrCallable An XSD schema file path, a callable, or null to disable validation
*
* @return \DOMDocument
*
* @throws \InvalidArgumentException When loading of XML file returns error
* @throws \Symfony\Component\Config\Util\Exception\XmlParsingException when XML parsing returns any errors
* @throws \RuntimeException When DOM extension is missing
*/
public static function loadFile($file, $schemaOrCallable = null)
{
$content = @file_get_contents($file);
if ('' === trim($content)) {
throw new \InvalidArgumentException(sprintf('File %s does not contain valid XML, it is empty.', $file));
}

try {
return static::parse($content, $schemaOrCallable);
} catch (InvalidXmlException $e) {
throw new XmlParsingException(sprintf('The XML file "%s" is not valid.', $file), 0, $e->getPrevious());
}
}

/**
* Converts a \DomElement object to a PHP array.
*
Expand Down
0