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
Push — master ( 7c99e4...3ac0b4 )
by Freek
01:29
created

ArrayToXml::prettify()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Spatie\ArrayToXml;
4
5
use DOMDocument;
6
use DOMElement;
7
use DOMException;
8
use Exception;
9
10
class ArrayToXml
11
{
12
    protected $document;
13
14
    protected $replaceSpacesByUnderScoresInKeyNames = true;
15
16
    protected $numericTagNamePrefix = 'numeric_';
17
18
    public function __construct(
19
        array $array,
20
        $rootElement = '',
21
        $replaceSpacesByUnderScoresInKeyNames = true,
22
        $xmlEncoding = null,
23
        $xmlVersion = '1.0',
24
        $domProperties = []
25
    ) {
26
        $this->document = new DOMDocument($xmlVersion, $xmlEncoding);
27
28
        if (! empty($domProperties)) {
29
            $this->setDomProperties($domProperties);
30
        }
31
32
        $this->replaceSpacesByUnderScoresInKeyNames = $replaceSpacesByUnderScoresInKeyNames;
33
34
        if ($this->isArrayAllKeySequential($array) && ! empty($array)) {
35
            throw new DOMException('Invalid Character Error');
36
        }
37
38
        $root = $this->createRootElement($rootElement);
39
40
        $this->document->appendChild($root);
41
42
        $this->convertElement($root, $array);
43
    }
44
45
    public function setNumericTagNamePrefix(string $prefix)
46
    {
47
        $this->numericTagNamePrefix = $prefix;
48
    }
49
50
    public static function convert(
51
        array $array,
52
        $rootElement = '',
53
        bool $replaceSpacesByUnderScoresInKeyNames = true,
54
        string $xmlEncoding = null,
55
        string $xmlVersion = '1.0',
56
        array $domProperties = []
57
    ) {
58
        $converter = new static(
59
            $array,
60
            $rootElement,
61
            $replaceSpacesByUnderScoresInKeyNames,
62
            $xmlEncoding,
63
            $xmlVersion,
64
            $domProperties
65
        );
66
67
        return $converter->toXml();
68
    }
69
70
    public function toXml(): string
71
    {
72
        return $this->document->saveXML();
73
    }
74
75
    public function toDom(): DOMDocument
76
    {
77
        return $this->document;
78
    }
79
80
    protected function ensureValidDomProperties(array $domProperties)
81
    {
82
        foreach ($domProperties as $key => $value) {
83
            if (! property_exists($this->document, $key)) {
84
                throw new Exception($key.' is not a valid property of DOMDocument');
85
            }
86
        }
87
    }
88
89
    public function setDomProperties(array $domProperties)
90
    {
91
        $this->ensureValidDomProperties($domProperties);
92
93
        foreach ($domProperties as $key => $value) {
94
            $this->document->{$key} = $value;
95
        }
96
97
        return $this;
98
    }
99
100
    public function prettify()
101
    {
102
        $this->document->preserveWhiteSpace = false;
103
        $this->document->formatOutput = true;
104
105
        return $this;
106
    }
107
108
    private function convertElement(DOMElement $element, $value)
109
    {
110
        $sequential = $this->isArrayAllKeySequential($value);
111
112
        if (! is_array($value)) {
113
            $value = htmlspecialchars($value);
114
115
            $value = $this->removeControlCharacters($value);
116
117
            $element->nodeValue = $value;
118
119
            return;
120
        }
121
122
        foreach ($value as $key => $data) {
123
            if (! $sequential) {
124
                if (($key === '_attributes') || ($key === '@attributes')) {
125
                    $this->addAttributes($element, $data);
126
                } elseif ((($key === '_value') || ($key === '@value')) && is_string($data)) {
127
                    $element->nodeValue = htmlspecialchars($data);
128
                } elseif ((($key === '_cdata') || ($key === '@cdata')) && is_string($data)) {
129
                    $element->appendChild($this->document->createCDATASection($data));
130
                } elseif ((($key === '_mixed') || ($key === '@mixed')) && is_string($data)) {
131
                    $fragment = $this->document->createDocumentFragment();
132
                    $fragment->appendXML($data);
133
                    $element->appendChild($fragment);
134
                } elseif ($key === '__numeric') {
135
                    $this->addNumericNode($element, $data);
136
                } else {
137
                    $this->addNode($element, $key, $data);
138
                }
139
            } elseif (is_array($data)) {
140
                $this->addCollectionNode($element, $data);
141
            } else {
142
                $this->addSequentialNode($element, $data);
143
            }
144
        }
145
    }
146
147
    protected function addNumericNode(DOMElement $element, $value)
148
    {
149
        foreach ($value as $key => $item) {
150
            $this->convertElement($element, [$this->numericTagNamePrefix.$key => $item]);
151
        }
152
    }
153
154
    protected function addNode(DOMElement $element, $key, $value)
155
    {
156
        if ($this->replaceSpacesByUnderScoresInKeyNames) {
157
            $key = str_replace(' ', '_', $key);
158
        }
159
160
        $child = $this->document->createElement($key);
161
        $element->appendChild($child);
162
        $this->convertElement($child, $value);
163
    }
164
165
    protected function addCollectionNode(DOMElement $element, $value)
166
    {
167
        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...
168
            $this->convertElement($element, $value);
169
170
            return;
171
        }
172
173
        $child = $this->document->createElement($element->tagName);
174
        $element->parentNode->appendChild($child);
175
        $this->convertElement($child, $value);
176
    }
177
178
    protected function addSequentialNode(DOMElement $element, $value)
179
    {
180
        if (empty($element->nodeValue) && ! is_numeric($element->nodeValue)) {
181
            $element->nodeValue = htmlspecialchars($value);
182
183
            return;
184
        }
185
186
        $child = new DOMElement($element->tagName);
187
        $child->nodeValue = htmlspecialchars($value);
188
        $element->parentNode->appendChild($child);
189
    }
190
191
    protected function isArrayAllKeySequential($value)
192
    {
193
        if (! is_array($value)) {
194
            return false;
195
        }
196
197
        if (count($value) <= 0) {
198
            return true;
199
        }
200
201
        if (\key($value) === '__numeric') {
202
            return false;
203
        }
204
205
        return array_unique(array_map('is_int', array_keys($value))) === [true];
206
    }
207
208
    protected function addAttributes(DOMElement $element, array $data)
209
    {
210
        foreach ($data as $attrKey => $attrVal) {
211
            $element->setAttribute($attrKey, $attrVal);
212
        }
213
    }
214
215
    protected function createRootElement($rootElement): DOMElement
216
    {
217
        if (is_string($rootElement)) {
218
            $rootElementName = $rootElement ?: 'root';
219
220
            return $this->document->createElement($rootElementName);
221
        }
222
223
        $rootElementName = $rootElement['rootElementName'] ?? 'root';
224
225
        $element = $this->document->createElement($rootElementName);
226
227
        foreach ($rootElement as $key => $value) {
228
            if ($key !== '_attributes' && $key !== '@attributes') {
229
                continue;
230
            }
231
232
            $this->addAttributes($element, $rootElement[$key]);
233
        }
234
235
        return $element;
236
    }
237
238
    protected function removeControlCharacters(string $value): string
239
    {
240
        return preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $value);
241
    }
242
}
243