Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ArrayToXML
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 5
462
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 buildXML
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 writeAttr
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
110
 writeEl
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
56
 isAssoc
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Services;
4
5use XmlWriter;
6
7class ArrayToXML
8{
9    private $version;
10
11    private $encoding;
12
13    /**
14     * Construct ArrayToXML object with selected version and encoding
15     *
16     * @param  string  $xmlVersion  XML Version, default 1.0
17     * @param  string  $xmlEncoding  XML Encoding, default UTF-8
18     */
19    public function __construct(string $xmlVersion = '1.0', string $xmlEncoding = 'UTF-8')
20    {
21        $this->version = $xmlVersion;
22        $this->encoding = $xmlEncoding;
23    }
24
25    /**
26     * Build an XML Data Set
27     *
28     * @param  array  $data  Associative Array containing values to be parsed into an XML Data Set(s)
29     * @param  string  $startElement  Root Opening Tag, default data
30     * @return string XML String containing values
31     * @return mixed Boolean false on failure, string XML result on success
32     */
33    public function buildXML(array $data, string $startElement = 'InstancyWrapper'): string
34    {
35        if (! is_array($data)) {
36            $err = 'Invalid variable type supplied, expected array not found on line '.__LINE__.' in Class: '.__CLASS__.' Method: '.__METHOD__;
37            trigger_error($err);
38
39            return false; // return false error occurred
40        }
41        $xml = new XmlWriter;
42        $xml->openMemory();
43        $xml->startDocument($this->version, $this->encoding);
44        $xml->startElement($startElement);
45
46        $data = $this->writeAttr($xml, $data);
47        $this->writeEl($xml, $data);
48
49        $xml->endElement(); // write end element
50
51        // returns the XML results
52        return $xml->outputMemory(true);
53    }
54
55    /**
56     * Write keys in $data prefixed with @ as XML attributes, if $data is an array.
57     * When an @ prefixed key is found, a '%' key is expected to indicate the element itself,
58     * and '#' prefixed key indicates CDATA content
59     *
60     * @param  XMLWriter  $xml  object
61     * @param  array  $data  with attributes filtered out
62     * @return array $data | $nonAttributes
63     */
64    protected function writeAttr(XMLWriter $xml, array $data): array
65    {
66        if (is_array($data)) {
67            $nonAttributes = [];
68            foreach ($data as $key => $val) {
69                // handle an attribute with elements
70                if ($key[0] == '@') {
71                    $xml->writeAttribute(substr($key, 1), $val);
72                } elseif ($key[0] == '%') {
73                    if (is_array($val)) {
74                        $nonAttributes = $val;
75                    } else {
76                        $xml->text($val);
77                    }
78                } elseif ($key[0] == '#') {
79                    if (is_array($val)) {
80                        $nonAttributes = $val;
81                    } else {
82                        $xml->startElement(substr($key, 1));
83                        $xml->writeCData($val);
84                        $xml->endElement();
85                    }
86                } elseif ($key[0] == '!') {
87                    if (is_array($val)) {
88                        $nonAttributes = $val;
89                    } else {
90                        $xml->writeCData($val);
91                    }
92                }
93                // ignore normal elements
94                else {
95                    $nonAttributes[$key] = $val;
96                }
97            }
98
99            return $nonAttributes;
100        } else {
101            return $data;
102        }
103    }
104
105    /**
106     * Write XML as per Associative Array
107     *
108     * @param  XMLWriter  $xml  object
109     * @param  array  $data  Associative Data Array
110     */
111    protected function writeEl(XMLWriter $xml, array $data)
112    {
113        foreach ($data as $key => $value) {
114            if (is_array($value) && ! $this->isAssoc($value)) { // numeric array
115                foreach ($value as $itemValue) {
116                    if (is_array($itemValue)) {
117                        $xml->startElement($key);
118                        $itemValue = $this->writeAttr($xml, $itemValue);
119                        $this->writeEl($xml, $itemValue);
120                        $xml->endElement();
121                    } else {
122                        $itemValue = $this->writeAttr($xml, $itemValue);
123                        $xml->writeElement($key, "$itemValue");
124                    }
125                }
126            } elseif (is_array($value)) { // associative array
127                $xml->startElement($key);
128                $value = $this->writeAttr($xml, $value);
129                $this->writeEl($xml, $value);
130                $xml->endElement();
131            } else { // scalar
132                $value = $this->writeAttr($xml, $value);
133                $xml->writeElement($key, "$value");
134            }
135        }
136    }
137
138    /**
139     * Check if array is associative with string based keys
140     *
141     * @param  array  $array  Array to check
142     */
143    protected function isAssoc(array $array): bool
144    {
145        return (bool) count(array_filter(array_keys($array), 'is_string'));
146    }
147}