Completed
Pull Request — master (#1)
by Guillaume
07:09
created

Dom::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 9
nc 2
nop 1
dl 0
loc 15
rs 9.4285
c 1
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the hogosha-monitor package
5
 *
6
 * Copyright (c) 2016 Guillaume Cavana
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * Feel free to edit as you please, and have fun.
12
 *
13
 * @author Guillaume Cavana <[email protected]>
14
 */
15
16
namespace Hogosha\Monitor\Utils;
17
18
/**
19
 * Thanks to sanpii for this class.
20
 *
21
 * @link https://github.com/Behatch/contexts/blob/master/src/Xml/Dom.php
22
 *
23
 * Class Dom.
24
 */
25
class Dom
26
{
27
    private $dom;
28
29
    /**
30
     * Constructor.
31
     *
32
     * @param string $content
33
     *
34
     * @throws \DomException
35
     */
36
    public function __construct($content)
37
    {
38
        $internalErrors = libxml_use_internal_errors(true);
0 ignored issues
show
Unused Code introduced by
$internalErrors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
39
        $disableEntities = libxml_disable_entity_loader(true);
40
        libxml_clear_errors();
41
42
        $this->dom = new \DomDocument();
43
        $this->dom->validateOnParse = true;
44
45
        if (!$this->dom->loadXML($content, LIBXML_PARSEHUGE)) {
46
            libxml_disable_entity_loader($disableEntities);
47
48
            $this->throwError();
49
        }
50
    }
51
52
    /**
53
     * __toString.
54
     *
55
     * @return string
56
     */
57
    public function __toString()
58
    {
59
        $this->dom->formatOutput = true;
60
61
        return $this->dom->saveXML();
62
    }
63
64
    /**
65
     * validate.
66
     *
67
     * @throws \DomException
68
     */
69
    public function validate()
70
    {
71
        $this->dom->validate();
72
        $this->throwError();
73
    }
74
75
    /**
76
     * validateXsd.
77
     *
78
     * @param string $xsd
79
     *
80
     * @throws \DomException
81
     */
82
    public function validateXsd($xsd)
83
    {
84
        $this->dom->schemaValidateSource($xsd);
85
        $this->throwError();
86
    }
87
88
    /**
89
     * validateNg.
90
     *
91
     * @param string $ng
92
     *
93
     * @throws \RuntimeException
94
     */
95
    public function validateNg($ng)
96
    {
97
        try {
98
            $this->dom->relaxNGValidateSource($ng);
99
            $this->throwError();
100
        } catch (\DOMException $e) {
101
            throw new \RuntimeException($e->getMessage());
102
        }
103
    }
104
105
    /**
106
     * xpath.
107
     *
108
     * @param string $element
109
     *
110
     * @return DOMNodeList
111
     */
112
    public function xpath($element)
113
    {
114
        $xpath = new \DOMXpath($this->dom);
115
        $this->registerNamespace($xpath);
116
117
        $element = $this->fixNamespace($element);
118
        $elements = $xpath->query($element);
119
120
        return ($elements === false) ? new \DOMNodeList() : $elements;
121
    }
122
123
    /**
124
     * getNamespaces.
125
     *
126
     * @return string
127
     */
128
    public function getNamespaces()
129
    {
130
        $xml = simplexml_import_dom($this->dom);
131
132
        return $xml->getNamespaces(true);
133
    }
134
135
    /**
136
     * registerNamespace.
137
     *
138
     * @param \DOMXpath $xpath
139
     */
140
    private function registerNamespace(\DOMXpath $xpath)
141
    {
142
        $namespaces = $this->getNamespaces();
143
144
        foreach ($namespaces as $prefix => $namespace) {
145
            if (empty($prefix) && $this->hasDefaultNamespace()) {
146
                $prefix = 'rootns';
147
            }
148
            $xpath->registerNamespace($prefix, $namespace);
149
        }
150
    }
151
152
    /**
153
     * "fix" queries to the default namespace if any namespaces are defined.
154
     *
155
     * @param string $element
156
     */
157
    private function fixNamespace($element)
158
    {
159
        $namespaces = $this->getNamespaces();
160
161
        if (!empty($namespaces) && $this->hasDefaultNamespace()) {
162
            for ($i = 0; $i < 2; ++$i) {
163
                $element = preg_replace('/\/(\w+)(\[[^]]+\])?\//', '/rootns:$1$2/', $element);
164
            }
165
            $element = preg_replace('/\/(\w+)(\[[^]]+\])?$/', '/rootns:$1$2', $element);
166
        }
167
168
        return $element;
169
    }
170
171
    private function hasDefaultNamespace()
172
    {
173
        $defaultNamespaceUri = $this->dom->lookupNamespaceURI(null);
174
        $defaultNamespacePrefix = $defaultNamespaceUri ? $this->dom->lookupPrefix($defaultNamespaceUri) : null;
175
176
        return empty($defaultNamespacePrefix) && !empty($defaultNamespaceUri);
177
    }
178
179
    private function throwError()
180
    {
181
        $error = libxml_get_last_error();
182
        if (!empty($error)) {
183
            // https://bugs.php.net/bug.php?id=46465
184
            if ($error->message != 'Validation failed: no DTD found !') {
185
                throw new \DomException($error->message.' at line '.$error->line);
186
            }
187
        }
188
    }
189
}
190