XmlConverter   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Test Coverage

Coverage 93.48%

Importance

Changes 0
Metric Value
dl 0
loc 113
ccs 43
cts 46
cp 0.9348
rs 10
c 0
b 0
f 0
wmc 19

3 Methods

Rating   Name   Duplication   Size   Complexity  
A convertToArray() 0 3 1
C addArrayAsChildren() 0 65 14
A isEmpty() 0 17 4
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[]|array
29
     */
30 7
    public function addArrayAsChildren(array $array, SimpleXMLElement $xmlElement, $ignoreEmptyElements = true)
31
    {
32
        // Keep an array of children that are added to $xmlElement
33 7
        $children = [];
34
35
        // Add each element of the array as a child to $xmlElement
36 7
        foreach ($array as $key => $value) {
37
            // Ignore empty array elements
38 7
            if ($this->isEmpty($value) && $ignoreEmptyElements) {
39 1
                continue;
40
            }
41
42
            // Specifies attributes as a key/value array
43 7
            if ($key === '@attributes') {
44 3
                if (!is_array($value)) {
45
                    throw new Exception('@attributes must be an array');
46
                }
47
48 3
                foreach ($value as $attributeName => $attributeValue) {
49 3
                    $xmlElement->addAttribute($attributeName, htmlspecialchars($attributeValue));
50 3
                }
51
52 3
                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 7
            if ($key === '@value') {
59 1
                if (!is_scalar($value)) {
60
                    throw new Exception('@value must be a scalar');
61
                }
62
63 1
                $xmlElement[0] = htmlspecialchars($value);
64 1
                continue;
65
            }
66
67
            // The value contains sub elements.
68
            // If the array is numeric then there are multiple of the same element.
69 7
            if (is_array($value)) {
70 4
                $useSubArray = key($value) === 0;
71 4
                $subValues = $useSubArray ? $value : [$value];
72
73 4
                $subChildren = [];
74 4
                foreach ($subValues as $subValue) {
75
                    // Recursively add child elements.
76 4
                    if (is_array($subValue)) {
77 4
                        $subChild = $xmlElement->addChild($key);
78 4
                        $this->addArrayAsChildren($subValue, $subChild, $ignoreEmptyElements);
79 4
                    } else {
80
                        $subChild = $xmlElement->addChild($key, $subValue);
81
                    }
82 4
                    $subChildren[] = $subChild;
83 4
                }
84
85 4
                $children[$key] = $useSubArray ? $subChildren : $subChildren[0];
86 4
                continue;
87
            }
88
89
            // Encode the value correctly
90 5
            $value = htmlspecialchars($value);
91 5
            $children[$key] = $xmlElement->addChild($key, $value);
92 7
        }
93
94 7
        return $children;
95
    }
96
97
    /**
98
     * Return whether the value, either an array (flat or multidimensional) or a string is empty. A string is empty if
99
     * its length is zero. An array is empty if all of its elements are empty.
100
     *
101
     * @param array|string $value
102
     * @return bool
103
     */
104 7
    private function isEmpty($value)
105
    {
106
        // Assume that the value is empty
107 7
        $empty = true;
108
109
        // If the value is an array
110 7
        if (is_array($value)) {
111 4
            foreach ($value as $element) {
112
                // The value is empty if all elements of the array are empty
113 4
                $empty = $empty && $this->isEmpty($element);
114 4
            }
115 4
        } else {
116
            // We can't use the empty function here because it treats "0" as empty
117 7
            $empty = strlen($value) == 0;
118
        }
119
120 7
        return $empty;
121
    }
122
123
    /**
124
     * Convert a SimpleXMLElement to an array.
125
     *
126
     * @param SimpleXMLElement $xmlElement
127
     * @return array
128
     */
129 1
    public function convertToArray(SimpleXMLElement $xmlElement)
130
    {
131 1
        return json_decode(json_encode($xmlElement), true);
132
    }
133
}
134