Completed
Push — master ( f2fd19...c76b04 )
by Brendan
02:16
created

XmlConverter::addArrayAsChildren()   C

Complexity

Conditions 13
Paths 16

Size

Total Lines 60
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 28
nc 16
nop 3
dl 0
loc 60
rs 6.3453
c 0
b 0
f 0

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
 * This file is part of graze/telnet-client.
4
 *
5
 * Copyright (c) 2018 Nature Delivered Ltd. <https://www.graze.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license https://github.com/graze/xml-utils/blob/master/LICENSE
11
 * @link https://github.com/graze/xml-utils
12
 */
13
14
namespace Graze\XmlUtils;
15
16
use Exception;
17
use SimpleXMLElement;
18
19
class XmlConverter
20
{
21
    /**
22
     * Convert an array into XML and adds the whole structure as a child of the existing SimpleXMLElement given.
23
     * An array of inserted children is returned so you can add further children to them if necessary.
24
     *
25
     * @param array $array
26
     * @param SimpleXMLElement $xmlElement
27
     * @param bool $ignoreEmptyElements
28
     * @return SimpleXMLElement[]
29
     */
30
    public function addArrayAsChildren(array $array, SimpleXMLElement $xmlElement, $ignoreEmptyElements = true)
31
    {
32
        // Keep an array of children that are added to $xmlElement
33
        $children = [];
34
35
        // Add each element of the array as a child to $xmlElement
36
        foreach ($array as $key => $value) {
37
            // Ignore empty array elements
38
            if ($this->isEmpty($value) && $ignoreEmptyElements) {
39
                continue;
40
            }
41
42
            // Specifies attributes as a key/value array
43
            if ($key === '@attributes') {
44
                if (!is_array($value)) {
45
                    throw new Exception('@attributes must be an array');
46
                }
47
48
                foreach ($value as $attributeName => $attributeValue) {
49
                    $xmlElement->addAttribute($attributeName, htmlspecialchars($attributeValue));
50
                }
51
52
                continue;
53
            }
54
55
            // Special case to be able to set the value of an element to a string if the attribute is also being set,
56
            // without this a child element would be created instead.
57
            // The really hacky part is that setting the 0 key element overrides the value (it doesn't normally exist).
58
            if ($key === '@value') {
59
                if (!is_scalar($value)) {
60
                    throw new Exception('@value must be a scalar');
61
                }
62
63
                $xmlElement[0] = htmlspecialchars($value);
64
                continue;
65
            }
66
67
            // Make a recursive call if the element is an array.
68
            // If the array is numeric then there are multiple of the same element.
69
            if (is_array($value)) {
70
                $useSubArray = key($value) === 0;
71
                $subValues = $useSubArray ? $value : [$value];
72
73
                $subChildren = [];
74
                foreach ($subValues as $subValue) {
75
                    $subChild = $xmlElement->addChild($key);
76
                    $this->addArrayAsChildren($subValue, $subChild, $ignoreEmptyElements);
77
                    $subChildren[] = $subChild;
78
                }
79
80
                $children[$key] = $useSubArray ? $subChildren : $subChildren[0];
81
                continue;
82
            }
83
84
            // Encode the value correctly
85
            $value = htmlspecialchars($value);
86
            $children[$key] = $xmlElement->addChild($key, $value);
87
        }
88
89
        return $children;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $children returns an array which contains values of type SimpleXMLElement[]|array which are incompatible with the documented value type SimpleXMLElement.
Loading history...
90
    }
91
92
    /**
93
     * Return whether the value, either an array (flat or multidimensional) or a string is empty. A string is empty if
94
     * its length is zero. An array is empty if all of its elements are empty.
95
     *
96
     * @param array|string $value
97
     * @return bool
98
     */
99
    private function isEmpty($value)
100
    {
101
        // Assume that the value is empty
102
        $empty = true;
103
104
        // If the value is an array
105
        if (is_array($value)) {
106
            foreach ($value as $element) {
107
                // The value is empty if all elements of the array are empty
108
                $empty = $empty && $this->isEmpty($element);
109
            }
110
        } else {
111
            // We can't use the empty function here because it treats "0" as empty
112
            $empty = strlen($value) == 0;
113
        }
114
115
        return $empty;
116
    }
117
118
    /**
119
     * Convert a SimpleXMLElement to an array.
120
     *
121
     * @param SimpleXMLElement $xmlElement
122
     * @return array
123
     */
124
    public function convertToArray(SimpleXMLElement $xmlElement)
125
    {
126
        return json_decode(json_encode($xmlElement), true);
127
    }
128
}
129