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 (#73)
by
unknown
02:15 queued 25s
created

ArrayToXml::createDocType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Spatie\ArrayToXml;
4
5
use DOMElement;
6
use DOMDocument;
7
use DOMException;
8
use DOMImplementation;
9
10
class ArrayToXml
11
{
12
    /**
13
     * The root DOM Document.
14
     *
15
     * @var DOMDocument
16
     */
17
    protected $document;
18
19
    /**
20
     * Set to enable replacing space with underscore.
21
     *
22
     * @var bool
23
     */
24
    protected $replaceSpacesByUnderScoresInKeyNames = true;
25
26
    /**
27
     * Construct a new instance.
28
     *
29
     * @param string[] $array
30
     * @param string|array $rootElement
31
     * @param bool $replaceSpacesByUnderScoresInKeyNames
32
     * @param string $xmlEncoding
33
     * @param string $xmlVersion
34
     * @param array $docTypeArray
35
     *
36
     * @throws DOMException
37
     */
38
    public function __construct(array $array, $rootElement = '', $replaceSpacesByUnderScoresInKeyNames = true, $xmlEncoding = null, $xmlVersion = '1.0', $docTypeArray = [])
39
    {
40
        $this->document = new DOMDocument($xmlVersion, $xmlEncoding);
41
        $this->replaceSpacesByUnderScoresInKeyNames = $replaceSpacesByUnderScoresInKeyNames;
42
43
        if ($this->isArrayAllKeySequential($array) && ! empty($array)) {
44
            throw new DOMException('Invalid Character Error');
45
        }
46
47
        if (! empty($docTypeArray)) {
48
            $docType = $this->createDocType($docTypeArray);
49
            $this->document->appendChild($docType);
50
        }
51
52
        $root = $this->createRootElement($rootElement);
53
54
        $this->document->appendChild($root);
55
56
        $this->convertElement($root, $array);
57
    }
58
59
    /**
60
     * Convert the given array to an xml string.
61
     *
62
     * @param string[] $array
63
     * @param string $rootElementName
64
     * @param bool $replaceSpacesByUnderScoresInKeyNames
65
     * @param string $xmlEncoding
66
     * @param string $xmlVersion
67
     * @param array $docTypeArray
68
     *
69
     * @return string
70
     */
71
    public static function convert(array $array, $rootElementName = '', $replaceSpacesByUnderScoresInKeyNames = true, $xmlEncoding = null, $xmlVersion = '1.0', $docTypeArray = [])
72
    {
73
        $converter = new static($array, $rootElementName, $replaceSpacesByUnderScoresInKeyNames, $xmlEncoding, $xmlVersion, $docTypeArray);
74
75
        return $converter->toXml();
76
    }
77
78
    /**
79
     * Return as XML.
80
     *
81
     * @return string
82
     */
83
    public function toXml()
84
    {
85
        return $this->document->saveXML();
86
    }
87
88
    /**
89
     * Return as DOM object.
90
     *
91
     * @return DOMDocument
92
     */
93
    public function toDom()
94
    {
95
        return $this->document;
96
    }
97
98
    /**
99
     * Parse individual element.
100
     *
101
     * @param DOMElement $element
102
     * @param string|string[] $value
103
     */
104
    private function convertElement(DOMElement $element, $value)
105
    {
106
        $sequential = $this->isArrayAllKeySequential($value);
107
108
        if (! is_array($value)) {
109
            $element->nodeValue = htmlspecialchars($value);
110
111
            return;
112
        }
113
114
        foreach ($value as $key => $data) {
115
            if (! $sequential) {
116
                if (($key === '_attributes') || ($key === '@attributes')) {
117
                    $this->addAttributes($element, $data);
118
                } elseif ((($key === '_value') || ($key === '@value')) && is_string($data)) {
119
                    $element->nodeValue = htmlspecialchars($data);
120
                } elseif ((($key === '_cdata') || ($key === '@cdata')) && is_string($data)) {
121
                    $element->appendChild($this->document->createCDATASection($data));
122
                } else {
123
                    $this->addNode($element, $key, $data);
124
                }
125
            } elseif (is_array($data)) {
126
                $this->addCollectionNode($element, $data);
127
            } else {
128
                $this->addSequentialNode($element, $data);
129
            }
130
        }
131
    }
132
133
    /**
134
     * Add node.
135
     *
136
     * @param DOMElement $element
137
     * @param string $key
138
     * @param string|string[] $value
139
     */
140
    protected function addNode(DOMElement $element, $key, $value)
141
    {
142
        if ($this->replaceSpacesByUnderScoresInKeyNames) {
143
            $key = str_replace(' ', '_', $key);
144
        }
145
146
        $child = $this->document->createElement($key);
147
        $element->appendChild($child);
148
        $this->convertElement($child, $value);
149
    }
150
151
    /**
152
     * Add collection node.
153
     *
154
     * @param DOMElement $element
155
     * @param string|string[] $value
156
     *
157
     * @internal param string $key
158
     */
159
    protected function addCollectionNode(DOMElement $element, $value)
160
    {
161
        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...
162
            $this->convertElement($element, $value);
163
164
            return;
165
        }
166
167
        $child = new DOMElement($element->tagName);
168
        $element->parentNode->appendChild($child);
169
        $this->convertElement($child, $value);
170
    }
171
172
    /**
173
     * Add sequential node.
174
     *
175
     * @param DOMElement $element
176
     * @param string|string[] $value
177
     *
178
     * @internal param string $key
179
     */
180
    protected function addSequentialNode(DOMElement $element, $value)
181
    {
182
        if (empty($element->nodeValue)) {
183
            $element->nodeValue = htmlspecialchars($value);
184
185
            return;
186
        }
187
188
        $child = new DOMElement($element->tagName);
189
        $child->nodeValue = htmlspecialchars($value);
190
        $element->parentNode->appendChild($child);
191
    }
192
193
    /**
194
     * Check if array are all sequential.
195
     *
196
     * @param array|string $value
197
     *
198
     * @return bool
199
     */
200
    protected function isArrayAllKeySequential($value)
201
    {
202
        if (! is_array($value)) {
203
            return false;
204
        }
205
206
        if (count($value) <= 0) {
207
            return true;
208
        }
209
210
        return array_unique(array_map('is_int', array_keys($value))) === [true];
211
    }
212
213
    /**
214
     * Add attributes.
215
     *
216
     * @param DOMElement $element
217
     * @param string[] $data
218
     */
219
    protected function addAttributes($element, $data)
220
    {
221
        foreach ($data as $attrKey => $attrVal) {
222
            $element->setAttribute($attrKey, $attrVal);
223
        }
224
    }
225
226
    /**
227
     * Create the root element.
228
     *
229
     * @param  string|array $rootElement
230
     * @return DOMElement
231
     */
232
    protected function createRootElement($rootElement)
233
    {
234
        if (is_string($rootElement)) {
235
            $rootElementName = $rootElement ?: 'root';
236
237
            return $this->document->createElement($rootElementName);
238
        }
239
240
        $rootElementName = $rootElement['rootElementName'] ?? 'root';
241
242
        $element = $this->document->createElement($rootElementName);
243
244
        foreach ($rootElement as $key => $value) {
245
            if ($key !== '_attributes' && $key !== '@attributes') {
246
                continue;
247
            }
248
249
            $this->addAttributes($element, $rootElement[$key]);
250
        }
251
252
        return $element;
253
    }
254
255
    /**
256
     * Pass in an array of elements to set the doctype of the XML.
257
     * @param $docTypeArray
258
     *
259
     * @return \DOMDocumentType
260
     */
261
    protected function createDocType($docTypeArray)
262
    {
263
        $implementation = new DOMImplementation();
264
265
        return $implementation->createDocumentType($docTypeArray[0], $docTypeArray[1], $docTypeArray[2]);
266
    }
267
}
268