GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#124)
by
unknown
01:00
created

ArrayToXml::addNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
rs 9.9332
cc 2
nc 2
nop 3
1
<?php
2
3
namespace Spatie\ArrayToXml;
4
5
use DOMImplementation;
6
use Exception;
7
use DOMElement;
8
use DOMDocument;
9
use DOMException;
10
11
class ArrayToXml
12
{
13
    protected $document;
14
15
    protected $replaceSpacesByUnderScoresInKeyNames = true;
16
17
    protected $numericTagNamePrefix = 'numeric_';
18
19
    public function __construct(
20
        array $array,
21
        $rootElement = '',
22
        $docType = '',
23
        $replaceSpacesByUnderScoresInKeyNames = true,
24
        $xmlEncoding = null,
25
        $xmlVersion = '1.0',
26
        $domProperties = []
27
    ) {
28
        $this->document = new DOMDocument($xmlVersion, $xmlEncoding);
29
30
        if (! empty($domProperties)) {
31
            $this->setDomProperties($domProperties);
32
        }
33
34
        $this->replaceSpacesByUnderScoresInKeyNames = $replaceSpacesByUnderScoresInKeyNames;
35
36
        if ($this->isArrayAllKeySequential($array) && ! empty($array)) {
37
            throw new DOMException('Invalid Character Error');
38
        }
39
40
        $this->createDocTypeElement($docType);
41
42
        $root = $this->createRootElement($rootElement);
43
44
        $this->document->appendChild($root);
45
46
        $this->convertElement($root, $array);
47
    }
48
49
    public function setNumericTagNamePrefix(string $prefix)
50
    {
51
        $this->numericTagNamePrefix = $prefix;
52
    }
53
54
    public static function convert(
55
        array $array,
56
        $rootElement = '',
57
        $docType = '',
58
        bool $replaceSpacesByUnderScoresInKeyNames = true,
59
        string $xmlEncoding = null,
60
        string $xmlVersion = '1.0',
61
        array $domProperties = []
62
    ) {
63
        $converter = new static(
64
            $array,
65
            $rootElement,
66
            $docType,
67
            $replaceSpacesByUnderScoresInKeyNames,
68
            $xmlEncoding,
69
            $xmlVersion,
70
            $domProperties
71
        );
72
73
        return $converter->toXml();
74
    }
75
76
    public function toXml(): string
77
    {
78
        return $this->document->saveXML();
79
    }
80
81
    public function toDom(): DOMDocument
82
    {
83
        return $this->document;
84
    }
85
86
    protected function ensureValidDomProperties(array $domProperties)
87
    {
88
        foreach ($domProperties as $key => $value) {
89
            if (! property_exists($this->document, $key)) {
90
                throw new Exception($key.' is not a valid property of DOMDocument');
91
            }
92
        }
93
    }
94
95
    public function setDomProperties(array $domProperties)
96
    {
97
        $this->ensureValidDomProperties($domProperties);
98
99
        foreach ($domProperties as $key => $value) {
100
            $this->document->{$key} = $value;
101
        }
102
103
        return $this;
104
    }
105
106
    private function convertElement(DOMElement $element, $value)
107
    {
108
        $sequential = $this->isArrayAllKeySequential($value);
109
110
        if (! is_array($value)) {
111
            $value = htmlspecialchars($value);
112
113
            $value = $this->removeControlCharacters($value);
114
115
            $element->nodeValue = $value;
116
117
            return;
118
        }
119
120
        foreach ($value as $key => $data) {
121
            if (! $sequential) {
122
                if (($key === '_attributes') || ($key === '@attributes')) {
123
                    $this->addAttributes($element, $data);
124
                } elseif ((($key === '_value') || ($key === '@value')) && is_string($data)) {
125
                    $element->nodeValue = htmlspecialchars($data);
126
                } elseif ((($key === '_cdata') || ($key === '@cdata')) && is_string($data)) {
127
                    $element->appendChild($this->document->createCDATASection($data));
128
                } elseif ((($key === '_mixed') || ($key === '@mixed')) && is_string($data)) {
129
                    $fragment = $this->document->createDocumentFragment();
130
                    $fragment->appendXML($data);
131
                    $element->appendChild($fragment);
132
                } elseif ($key === '__numeric') {
133
                    $this->addNumericNode($element, $data);
134
                } else {
135
                    $this->addNode($element, $key, $data);
136
                }
137
            } elseif (is_array($data)) {
138
                $this->addCollectionNode($element, $data);
139
            } else {
140
                $this->addSequentialNode($element, $data);
141
            }
142
        }
143
    }
144
145
    protected function addNumericNode(DOMElement $element, $value)
146
    {
147
        foreach ($value as $key => $item) {
148
            $this->convertElement($element, [$this->numericTagNamePrefix.$key => $item]);
149
        }
150
    }
151
152
    protected function addNode(DOMElement $element, $key, $value)
153
    {
154
        if ($this->replaceSpacesByUnderScoresInKeyNames) {
155
            $key = str_replace(' ', '_', $key);
156
        }
157
158
        $child = $this->document->createElement($key);
159
        $element->appendChild($child);
160
        $this->convertElement($child, $value);
161
    }
162
163
    protected function addCollectionNode(DOMElement $element, $value)
164
    {
165
        if ($element->childNodes->length === 0 && $element->attributes->length === 0) {
0 ignored issues
show
Bug introduced by
The property length does not seem to exist in DOMNamedNodeMap.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
166
            $this->convertElement($element, $value);
167
168
            return;
169
        }
170
171
        $child = $this->document->createElement($element->tagName);
172
        $element->parentNode->appendChild($child);
173
        $this->convertElement($child, $value);
174
    }
175
176
    protected function addSequentialNode(DOMElement $element, $value)
177
    {
178
        if (empty($element->nodeValue) && ! is_numeric($element->nodeValue)) {
179
            $element->nodeValue = htmlspecialchars($value);
180
181
            return;
182
        }
183
184
        $child = new DOMElement($element->tagName);
185
        $child->nodeValue = htmlspecialchars($value);
186
        $element->parentNode->appendChild($child);
187
    }
188
189
    protected function isArrayAllKeySequential($value)
190
    {
191
        if (! is_array($value)) {
192
            return false;
193
        }
194
195
        if (count($value) <= 0) {
196
            return true;
197
        }
198
199
        if (\key($value) === '__numeric') {
200
            return false;
201
        }
202
203
        return array_unique(array_map('is_int', array_keys($value))) === [true];
204
    }
205
206
    protected function addAttributes(DOMElement $element, array $data)
207
    {
208
        foreach ($data as $attrKey => $attrVal) {
209
            $element->setAttribute($attrKey, $attrVal);
210
        }
211
    }
212
213
    protected function createRootElement($rootElement): DOMElement
214
    {
215
        if (is_string($rootElement)) {
216
            $rootElementName = $rootElement ?: 'root';
217
218
            return $this->document->createElement($rootElementName);
219
        }
220
221
        $rootElementName = $rootElement['rootElementName'] ?? 'root';
222
223
        $element = $this->document->createElement($rootElementName);
224
225
        foreach ($rootElement as $key => $value) {
226
            if ($key !== '_attributes' && $key !== '@attributes') {
227
                continue;
228
            }
229
230
            $this->addAttributes($element, $rootElement[$key]);
231
        }
232
233
        return $element;
234
    }
235
236
    protected function removeControlCharacters(string $value): string
237
    {
238
        return preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $value);
239
    }
240
241
    protected function createDocTypeElement($docTypeStr)
242
    {
243
        if (! empty($docTypeStr)) {
244
            //Added for DOCType
245
            $implementation = new DOMImplementation();
246
            $this->document->appendChild($implementation->createDocumentType($docTypeStr));
247
        }
248
    }
249
}
250