Completed
Push — master ( ab7ebf...740609 )
by Grégoire
02:23
created

XmlFile::getConfiguration()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 17
c 0
b 0
f 0
nc 5
nop 0
dl 0
loc 30
ccs 18
cts 18
cp 1
crap 4
rs 9.7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Migrations\Configuration\Configuration;
6
7
use Doctrine\Migrations\Configuration\Configuration;
8
use Doctrine\Migrations\Configuration\Configuration\Exception\XmlNotValid;
9
use Doctrine\Migrations\Configuration\Exception\FileNotFound;
10
use Doctrine\Migrations\Tools\BooleanStringFormatter;
11
use DOMDocument;
12
use SimpleXMLElement;
13
use const DIRECTORY_SEPARATOR;
14
use const LIBXML_NOCDATA;
15
use function assert;
16
use function file_exists;
17
use function file_get_contents;
18
use function libxml_clear_errors;
19
use function libxml_use_internal_errors;
20
use function simplexml_load_string;
21
use function strtr;
22
23
final class XmlFile extends ConfigurationFile
24
{
25 10
    public function getConfiguration() : Configuration
26
    {
27 10
        if (! file_exists($this->file)) {
28 1
            throw FileNotFound::new($this->file);
29
        }
30
31 9
        $this->validateXml($this->file);
32
33 6
        $rawXML = file_get_contents($this->file);
34 6
        assert($rawXML !== false);
35
36 6
        $root = simplexml_load_string($rawXML, SimpleXMLElement::class, LIBXML_NOCDATA);
37 6
        assert($root !== false);
38
39 6
        $config = $this->extractParameters($root, true);
40
41 6
        if (isset($config['all_or_nothing'])) {
42 2
            $config['all_or_nothing'] = BooleanStringFormatter::toBoolean(
43 2
                $config['all_or_nothing'],
44 2
                false
45
            );
46
        }
47 6
        if (isset($config['migrations_paths'])) {
48 3
            $config['migrations_paths'] = $this->getDirectoriesRelativeToFile(
49 3
                $config['migrations_paths'],
50 3
                $this->file
51
            );
52
        }
53
54 6
        return (new ConfigurationArray($config))->getConfiguration();
55
    }
56
57
    /**
58
     * @return mixed[]
59
     */
60 6
    private function extractParameters(SimpleXMLElement $root, bool $loopOverNodes) : array
61
    {
62 6
        $config = [];
63
64 6
        $itemsToCheck = $loopOverNodes ? $root->children() : $root->attributes();
65
66 6
        if (! ($itemsToCheck instanceof SimpleXMLElement)) {
0 ignored issues
show
introduced by
$itemsToCheck is always a sub-type of SimpleXMLElement.
Loading history...
67
            return $config;
68
        }
69 6
        foreach ($itemsToCheck as $node) {
70 6
            $nodeName = strtr($node->getName(), '-', '_');
71 6
            if ($nodeName === 'migrations_paths') {
72 3
                $config['migrations_paths'] = [];
73 3
                foreach ($node->{'path'} as $pathNode) {
74 3
                    $config['migrations_paths'][(string) $pathNode['namespace']] = (string) $pathNode;
75
                }
76 5
            } elseif ($nodeName === 'storage' && $node->{'table-storage'} instanceof SimpleXMLElement) {
77 2
                $config['table_storage'] = $this->extractParameters($node->{'table-storage'}, false);
78 5
            } elseif ($nodeName === 'migrations') {
79 2
                $config['migrations'] = [];
80 2
                foreach ($node->{'migration'} as $pathNode) {
81 2
                    $config['migrations'][] = (string) $pathNode;
82
                }
83
            } else {
84 5
                $config[$nodeName] = (string) $node;
85
            }
86
        }
87
88 6
        return $config;
89
    }
90
91 9
    private function validateXml(string $file) : void
92
    {
93
        try {
94 9
            libxml_use_internal_errors(true);
95
96 9
            $xml = new DOMDocument();
97
98 9
            if ($xml->load($file) === false) {
99 1
                throw XmlNotValid::malformed();
100
            }
101
102 8
            $xsdPath = __DIR__ . DIRECTORY_SEPARATOR . 'XML' . DIRECTORY_SEPARATOR . 'configuration.xsd';
103
104 8
            if ($xml->schemaValidate($xsdPath) === false) {
105 2
                throw XmlNotValid::failedValidation();
106
            }
107 6
        } finally {
108 9
            libxml_clear_errors();
109 9
            libxml_use_internal_errors(false);
110
        }
111 6
    }
112
}
113