Skip to content

Commit 3ec9263

Browse files
mazhalaiIvan Gavryshko
authored andcommitted
Merge remote-tracking branch 'ogresce/MAGETWO-31422-file-xml-syntax-error-handling' into develop
2 parents 4f17c22 + 8f5b804 commit 3ec9263

File tree

4 files changed

+103
-14
lines changed

4 files changed

+103
-14
lines changed

dev/tests/unit/testsuite/Magento/Framework/Module/ModuleList/LoaderTest.php

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Magento\Framework\Module\ModuleList;
88

99
use Magento\Framework\App\Filesystem\DirectoryList;
10+
use Magento\Framework\Xml\Parser;
1011

1112
class LoaderTest extends \PHPUnit_Framework_TestCase
1213
{
@@ -32,6 +33,11 @@ class LoaderTest extends \PHPUnit_Framework_TestCase
3233
*/
3334
private $converter;
3435

36+
/*
37+
* @var \PHPUnit_Framework_MockObject_MockObject
38+
*/
39+
private $parser;
40+
3541
protected function setUp()
3642
{
3743
$this->filesystem = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
@@ -41,6 +47,7 @@ protected function setUp()
4147
->with(DirectoryList::MODULES)
4248
->willReturn($this->dir);
4349
$this->converter = $this->getMock('Magento\Framework\Module\Declaration\Converter\Dom', [], [], '', false);
50+
$this->parser = $this->getMock('Magento\Framework\Xml\Parser', [], [], '', false);
4451
}
4552

4653
public function testLoad()
@@ -57,11 +64,13 @@ public function testLoad()
5764
['b', null, null, self::$sampleXml],
5865
['c', null, null, self::$sampleXml],
5966
]));
60-
$dom = new \PHPUnit_Framework_Constraint_IsInstanceOf('DOMDocument');
61-
$this->converter->expects($this->at(0))->method('convert')->with($dom)->willReturn(['a' => $fixture['a']]);
62-
$this->converter->expects($this->at(1))->method('convert')->with($dom)->willReturn(['b' => $fixture['b']]);
63-
$this->converter->expects($this->at(2))->method('convert')->with($dom)->willReturn(['c' => $fixture['c']]);
64-
$object = new Loader($this->filesystem, $this->converter);
67+
$this->converter->expects($this->at(0))->method('convert')->willReturn(['a' => $fixture['a']]);
68+
$this->converter->expects($this->at(1))->method('convert')->willReturn(['b' => $fixture['b']]);
69+
$this->converter->expects($this->at(2))->method('convert')->willReturn(['c' => $fixture['c']]);
70+
$this->parser->expects($this->once())->method('initErrorHandler');
71+
$this->parser->expects($this->atLeastOnce())->method('loadXML');
72+
$this->parser->expects($this->atLeastOnce())->method('getDom');
73+
$object = new Loader($this->filesystem, $this->converter, $this->parser);
6574
$result = $object->load();
6675
$this->assertSame(['a', 'c', 'b'], array_keys($result));
6776
$this->assertSame($fixture['a'], $result['a']);
@@ -84,10 +93,9 @@ public function testLoadCircular()
8493
['a', null, null, self::$sampleXml],
8594
['b', null, null, self::$sampleXml],
8695
]));
87-
$dom = new \PHPUnit_Framework_Constraint_IsInstanceOf('DOMDocument');
88-
$this->converter->expects($this->at(0))->method('convert')->with($dom)->willReturn(['a' => $fixture['a']]);
89-
$this->converter->expects($this->at(1))->method('convert')->with($dom)->willReturn(['b' => $fixture['b']]);
90-
$object = new Loader($this->filesystem, $this->converter);
96+
$this->converter->expects($this->at(0))->method('convert')->willReturn(['a' => $fixture['a']]);
97+
$this->converter->expects($this->at(1))->method('convert')->willReturn(['b' => $fixture['b']]);
98+
$object = new Loader($this->filesystem, $this->converter, $this->parser);
9199
$object->load();
92100
}
93101
}

dev/tests/unit/testsuite/Magento/Framework/Xml/ParserTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,15 @@ public function testGetXml()
3131
$this->parser->load(__DIR__ . '/_files/data.xml')->xmlToArray()
3232
);
3333
}
34+
35+
/**
36+
* @expectedException \Magento\Framework\Exception
37+
* @expectedExceptionMessage DOMDocument::loadXML(): Opening and ending tag mismatch
38+
*/
39+
public function testLoadXmlInvalid()
40+
{
41+
$sampleInvalidXml = '<?xml version="1.0"?><config></onfig>';
42+
$this->parser->initErrorHandler();
43+
$this->parser->loadXML($sampleInvalidXml);
44+
}
3445
}

lib/internal/Magento/Framework/Module/ModuleList/Loader.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Magento\Framework\App\Filesystem\DirectoryList;
1010
use Magento\Framework\Filesystem;
1111
use Magento\Framework\Module\Declaration\Converter\Dom;
12+
use Magento\Framework\Xml\Parser;
1213

1314
/**
1415
* Loader of module list information from the filesystem
@@ -29,21 +30,32 @@ class Loader
2930
*/
3031
private $converter;
3132

33+
/**
34+
* Parser
35+
*
36+
* @var \Magento\Framework\Xml\Parser
37+
*/
38+
private $parser;
39+
3240
/**
3341
* Constructor
3442
*
3543
* @param Filesystem $filesystem
3644
* @param Dom $converter
45+
* @param Parser $parser
3746
*/
38-
public function __construct(Filesystem $filesystem, Dom $converter)
47+
public function __construct(Filesystem $filesystem, Dom $converter, Parser $parser)
3948
{
4049
$this->filesystem = $filesystem;
4150
$this->converter = $converter;
51+
$this->parser = $parser;
52+
$this->parser->initErrorHandler();
4253
}
4354

4455
/**
4556
* Loads the full module list information
4657
*
58+
* @throws \Magento\Framework\Exception
4759
* @return array
4860
*/
4961
public function load()
@@ -52,9 +64,18 @@ public function load()
5264
$dir = $this->filesystem->getDirectoryRead(DirectoryList::MODULES);
5365
foreach ($dir->search('*/*/etc/module.xml') as $file) {
5466
$contents = $dir->readFile($file);
55-
$dom = new \DOMDocument();
56-
$dom->loadXML($contents);
57-
$data = $this->converter->convert($dom);
67+
68+
try {
69+
$this->parser->loadXML($contents);
70+
} catch (\Magento\Framework\Exception $e) {
71+
throw new \Magento\Framework\Exception(
72+
'Invalid Document: ' . $file . PHP_EOL . ' Error: ' . $e->getMessage(),
73+
$e->getCode(),
74+
$e
75+
);
76+
}
77+
78+
$data = $this->converter->convert($this->parser->getDom());
5879
$name = key($data);
5980
$result[$name] = $data[$name];
6081
}

lib/internal/Magento/Framework/Xml/Parser.php

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
namespace Magento\Framework\Xml;
77

8+
use \Magento\Framework\Exception;
9+
810
class Parser
911
{
1012
/**
@@ -22,6 +24,11 @@ class Parser
2224
*/
2325
protected $_content = [];
2426

27+
/**
28+
* @var boolean
29+
*/
30+
protected $errorHandlerIsActive = false;
31+
2532
/**
2633
*
2734
*/
@@ -32,6 +39,16 @@ public function __construct()
3239
return $this;
3340
}
3441

42+
/**
43+
* Initializes error handler
44+
*
45+
* @return void
46+
*/
47+
public function initErrorHandler()
48+
{
49+
$this->errorHandlerIsActive = true;
50+
}
51+
3552
/**
3653
* @return \DOMDocument|null
3754
*/
@@ -135,7 +152,39 @@ public function load($file)
135152
*/
136153
public function loadXML($string)
137154
{
138-
$this->getDom()->loadXML($string);
155+
if ($this->errorHandlerIsActive) {
156+
set_error_handler([$this, 'errorHandler']);
157+
}
158+
159+
try {
160+
$this->getDom()->loadXML($string);
161+
} catch (\Magento\Framework\Exception $e) {
162+
restore_error_handler();
163+
throw new \Magento\Framework\Exception($e->getMessage(), $e->getCode(), $e);
164+
}
165+
166+
if ($this->errorHandlerIsActive) {
167+
restore_error_handler();
168+
}
169+
139170
return $this;
140171
}
172+
173+
/**
174+
* Custom XML lib error handler
175+
*
176+
* @param int $errorNo
177+
* @param string $errorStr
178+
* @param string $errorFile
179+
* @param int $errorLine
180+
* @throws \Magento\Framework\Exception
181+
* @return void
182+
*/
183+
public function errorHandler($errorNo, $errorStr, $errorFile, $errorLine)
184+
{
185+
if ($errorNo != 0) {
186+
$message = "{$errorStr} in {$errorFile} on line {$errorLine}";
187+
throw new \Magento\Framework\Exception($message);
188+
}
189+
}
141190
}

0 commit comments

Comments
 (0)