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 ( a32e51...2e05e1 )
by Freek
01:12
created

ArrayToXml   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 37
c 1
b 0
f 0
lcom 1
cbo 0
dl 0
loc 238
rs 8.6

11 Methods

Rating   Name   Duplication   Size   Complexity  
A toXml() 0 4 1
A toDom() 0 4 1
A __construct() 0 15 3
A convert() 0 6 1
C convertElement() 0 28 13
A addNode() 0 10 2
A addCollectionNode() 0 12 3
A addSequentialNode() 0 12 2
A isArrayAllKeySequential() 0 12 3
A addAttributes() 0 6 2
B createRootElement() 0 22 6
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
            if (! $sequential) {
108
                if (($key === '_attributes') || ($key === '@attributes')) {
109
                    $this->addAttributes($element, $data);
110
                } elseif ((($key === '_value') || ($key === '@value')) && is_string($data)) {
111
                    $element->nodeValue = htmlspecialchars($data);
112
                } elseif ((($key === '_cdata') || ($key === '@cdata')) && is_string($data)) {
113
                    $element->appendChild($this->document->createCDATASection($data));
114
                } else {
115
                    $this->addNode($element, $key, $data);
116
                }
117
            } elseif (is_array($data)) {
118
                $this->addCollectionNode($element, $data);
119
            } else {
120
                $this->addSequentialNode($element, $data);
121
            }
122
        }
123
    }
124
125
    /**
126
     * Add node.
127
     *
128
     * @param DOMElement $element
129
     * @param string $key
130
     * @param string|string[] $value
131
     */
132
    protected function addNode(DOMElement $element, $key, $value)
133
    {
134
        if ($this->replaceSpacesByUnderScoresInKeyNames) {
135
            $key = str_replace(' ', '_', $key);
136
        }
137
138
        $child = $this->document->createElement($key);
139
        $element->appendChild($child);
140
        $this->convertElement($child, $value);
141
    }
142
143
    /**
144
     * Add collection node.
145
     *
146
     * @param DOMElement $element
147
     * @param string|string[] $value
148
     *
149
     * @internal param string $key
150
     */
151
    protected function addCollectionNode(DOMElement $element, $value)
152
    {
153
        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...
154
            $this->convertElement($element, $value);
155
156
            return;
157
        }
158
159
        $child = $element->cloneNode();
160
        $element->parentNode->appendChild($child);
161
        $this->convertElement($child, $value);
0 ignored issues
show
Compatibility introduced by
$child of type object<DOMNode> is not a sub-type of object<DOMElement>. It seems like you assume a child class of the class DOMNode to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
162
    }
163
164
    /**
165
     * Add sequential node.
166
     *
167
     * @param DOMElement $element
168
     * @param string|string[] $value
169
     *
170
     * @internal param string $key
171
     */
172
    protected function addSequentialNode(DOMElement $element, $value)
173
    {
174
        if (empty($element->nodeValue)) {
175
            $element->nodeValue = htmlspecialchars($value);
176
177
            return;
178
        }
179
180
        $child = $element->cloneNode();
181
        $child->nodeValue = htmlspecialchars($value);
182
        $element->parentNode->appendChild($child);
183
    }
184
185
    /**
186
     * Check if array are all sequential.
187
     *
188
     * @param array|string $value
189
     *
190
     * @return bool
191
     */
192
    protected function isArrayAllKeySequential($value)
193
    {
194
        if (! is_array($value)) {
195
            return false;
196
        }
197
198
        if (count($value) <= 0) {
199
            return true;
200
        }
201
202
        return array_unique(array_map('is_int', array_keys($value))) === [true];
203
    }
204
205
    /**
206
     * Add attributes.
207
     *
208
     * @param DOMElement $element
209
     * @param string[] $data
210
     */
211
    protected function addAttributes($element, $data)
212
    {
213
        foreach ($data as $attrKey => $attrVal) {
214
            $element->setAttribute($attrKey, $attrVal);
215
        }
216
    }
217
218
    /**
219
     * Create the root element.
220
     *
221
     * @param  string|array $rootElement
222
     * @return DOMElement
223
     */
224
    protected function createRootElement($rootElement)
225
    {
226
        if (is_string($rootElement)) {
227
            $rootElementName = $rootElement ?: 'root';
228
229
            return $this->document->createElement($rootElementName);
230
        }
231
232
        $rootElementName = $rootElement['rootElementName'] ?? 'root';
233
234
        $element = $this->document->createElement($rootElementName);
235
236
        foreach ($rootElement as $key => $value) {
237
            if ($key !== '_attributes' && $key !== '@attributes') {
238
                continue;
239
            }
240
241
            $this->addAttributes($element, $rootElement[$key]);
242
        }
243
244
        return $element;
245
    }
246
}
247