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        //returns the XML results
51        return $xml->outputMemory(true);
52    }
53
54    /**
55     * Write keys in $data prefixed with @ as XML attributes, if $data is an array.
56     * When an @ prefixed key is found, a '%' key is expected to indicate the element itself,
57     * and '#' prefixed key indicates CDATA content
58     *
59     * @param  XMLWriter  $xml object
60     * @param  array  $data with attributes filtered out
61     * @return array $data | $nonAttributes
62     */
63    protected function writeAttr(XMLWriter $xml, array $data): array
64    {
65        if (is_array($data)) {
66            $nonAttributes = [];
67            foreach ($data as $key => $val) {
68                //handle an attribute with elements
69                if ($key[0] == '@') {
70                    $xml->writeAttribute(substr($key, 1), $val);
71                } elseif ($key[0] == '%') {
72                    if (is_array($val)) {
73                        $nonAttributes = $val;
74                    } else {
75                        $xml->text($val);
76                    }
77                } elseif ($key[0] == '#') {
78                    if (is_array($val)) {
79                        $nonAttributes = $val;
80                    } else {
81                        $xml->startElement(substr($key, 1));
82                        $xml->writeCData($val);
83                        $xml->endElement();
84                    }
85                } elseif ($key[0] == '!') {
86                    if (is_array($val)) {
87                        $nonAttributes = $val;
88                    } else {
89                        $xml->writeCData($val);
90                    }
91                }
92                //ignore normal elements
93                else {
94                    $nonAttributes[$key] = $val;
95                }
96            }
97
98            return $nonAttributes;
99        } else {
100            return $data;
101        }
102    }
103
104    /**
105     * Write XML as per Associative Array
106     *
107     * @param  XMLWriter  $xml object
108     * @param  array  $data Associative Data Array
109     */
110    protected function writeEl(XMLWriter $xml, array $data)
111    {
112        foreach ($data as $key => $value) {
113            if (is_array($value) && ! $this->isAssoc($value)) { //numeric array
114                foreach ($value as $itemValue) {
115                    if (is_array($itemValue)) {
116                        $xml->startElement($key);
117                        $itemValue = $this->writeAttr($xml, $itemValue);
118                        $this->writeEl($xml, $itemValue);
119                        $xml->endElement();
120                    } else {
121                        $itemValue = $this->writeAttr($xml, $itemValue);
122                        $xml->writeElement($key, "$itemValue");
123                    }
124                }
125            } elseif (is_array($value)) { //associative array
126                $xml->startElement($key);
127                $value = $this->writeAttr($xml, $value);
128                $this->writeEl($xml, $value);
129                $xml->endElement();
130            } else { //scalar
131                $value = $this->writeAttr($xml, $value);
132                $xml->writeElement($key, "$value");
133            }
134        }
135    }
136
137    /**
138     * Check if array is associative with string based keys
139     *
140     * @param  array  $array Array to check
141     */
142    protected function isAssoc(array $array): bool
143    {
144        return (bool) count(array_filter(array_keys($array), 'is_string'));
145    }
146}