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 (#74)
by
unknown
09:19
created

ArrayToXml::getRealKey()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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