Passed
Pull Request — master (#13)
by
unknown
01:35
created

XmlToArray::convertDomElement()   B

Complexity

Conditions 10
Paths 20

Size

Total Lines 54
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 10
eloc 29
c 3
b 0
f 0
nc 20
nop 1
dl 0
loc 54
rs 7.6666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Vyuldashev\XmlToArray;
6
7
use DOMAttr;
8
use DOMCdataSection;
9
use DOMDocument;
10
use DOMElement;
11
use DOMNamedNodeMap;
12
use DOMText;
13
14
class XmlToArray
15
{
16
    protected $document;
17
18
    public function __construct(string $xml)
19
    {
20
        $this->document = new DOMDocument();
21
        $this->document->loadXML($xml);
22
    }
23
24
    public static function convert(string $xml): array
25
    {
26
        $converter = new static($xml);
27
28
        return $converter->toArray();
29
    }
30
31
    protected function convertAttributes(DOMNamedNodeMap $nodeMap): ?array
32
    {
33
        if ($nodeMap->length === 0) {
34
            return null;
35
        }
36
37
        $result = [];
38
39
        /** @var DOMAttr $item */
40
        foreach ($nodeMap as $item) {
41
            $result[$item->name] = $item->value;
42
        }
43
44
        return ['_attributes' => $result];
45
    }
46
47
    protected function convertDomElement(DOMElement $element)
48
    {
49
        $result = $this->convertAttributes($element->attributes);
0 ignored issues
show
Bug introduced by
It seems like $element->attributes can also be of type null; however, parameter $nodeMap of Vyuldashev\XmlToArray\Xm...ay::convertAttributes() does only seem to accept DOMNamedNodeMap, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

49
        $result = $this->convertAttributes(/** @scrutinizer ignore-type */ $element->attributes);
Loading history...
50
51
        $sameNamesOccurrences = [];
52
        $sameNodeNameIndexes = [];
53
54
        if ($element->childNodes->length > 1) {
55
            $childNodeNames = [];
56
57
            foreach ($element->childNodes as $node) {
58
                $childNodeNames[] = $node->nodeName;
59
            }
60
61
            $sameNamesOccurrences = array_count_values($childNodeNames);
62
        }
63
64
        foreach ($element->childNodes as $node) {
65
            if ($node instanceof DOMCdataSection) {
66
                $result['_cdata'] = $node->data;
67
68
                continue;
69
            }
70
            if ($node instanceof DOMText) {
71
                $result = $node->textContent;
72
73
                continue;
74
            }
75
            if ($node instanceof DOMElement) {
76
                $nodeName = $node->nodeName;
77
                $hasSameName = array_key_exists($nodeName, $sameNamesOccurrences) && $sameNamesOccurrences[$nodeName] > 1;
78
79
                if ($hasSameName === false) {
80
                    $result[$nodeName] = $this->convertDomElement($node);
81
                    continue;
82
                }
83
84
                // If we already have a child node with the same name, we need to increment
85
                // and keep track of their index.
86
87
                if (isset($sameNodeNameIndexes[$nodeName])) {
88
                    $key = $sameNodeNameIndexes[$nodeName] + 1;
89
                } else {
90
                    $key = 0;
91
                }
92
93
                $result[$nodeName][$key] = $this->convertDomElement($node);
94
                $sameNodeNameIndexes[$nodeName] = $key;
95
96
                continue;
97
            }
98
        }
99
100
        return $result;
101
    }
102
103
    public function toArray(): array
104
    {
105
        $result = [];
106
107
        if ($this->document->hasChildNodes()) {
108
            $children = $this->document->childNodes;
109
110
            foreach ($children as $child) {
111
                $result[$child->nodeName] = $this->convertDomElement($child);
112
            }
113
        }
114
115
        return $result;
116
    }
117
}
118