SimpleXmlWriter::createXmlNode()   B
last analyzed

Complexity

Conditions 7
Paths 5

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 8.8142

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 12
cts 18
cp 0.6667
rs 8.4906
c 0
b 0
f 0
cc 7
nc 5
nop 2
crap 8.8142
1
<?php
2
3
/*
4
 * soluble-flexstore library
5
 *
6
 * @author    Vanvelthem Sébastien
7
 * @link      https://github.com/belgattitude/soluble-flexstore
8
 * @copyright Copyright (c) 2016-2017 Vanvelthem Sébastien
9
 * @license   MIT License https://github.com/belgattitude/soluble-flexstore/blob/master/LICENSE.md
10
 *
11
 */
12
13
namespace Soluble\FlexStore\Writer;
14
15
use Soluble\FlexStore\Writer\Http\SimpleHeaders;
16
use DateTime;
17
use SimpleXMLElement;
18
use Soluble\FlexStore\Options;
19
use Soluble\FlexStore\Store\StoreInterface;
20
21
class SimpleXmlWriter extends AbstractSendableWriter
22
{
23
    /**
24
     * @var SimpleHeaders
25
     */
26
    protected $headers;
27
    protected $php_54_compatibility = true;
28
29
    /**
30
     * @var array
31
     */
32
    protected $options = [
33
        /*
34
         * XML tag for response
35
         */
36
        'body_tag' => 'response',
37
        /*
38
         * XML tag for rows
39
         */
40
        'row_tag' => 'row',
41
        'encoding' => 'UTF-8',
42
        'debug' => false
43
    ];
44
45
    /**
46
     * @param StoreInterface|null     $store
47
     * @param array|\Traversable|null $options
48
     */
49 3
    public function __construct(StoreInterface $store = null, $options = null)
50
    {
51 3
        if (version_compare(PHP_VERSION, '5.4.0', '<')) {
52
            $this->php_54_compatibility = false;
53
        }
54
55 3
        parent::__construct($store, $options);
56 3
    }
57
58
    /**
59
     * @param string $row_tag
60
     *
61
     * @return SimpleXmlWriter
62
     */
63 1
    public function setRowTag($row_tag)
64
    {
65 1
        $this->options['row_tag'] = $row_tag;
66
67 1
        return $this;
68
    }
69
70
    /**
71
     * @param string $body_tag
72
     *
73
     * @return SimpleXmlWriter
74
     */
75 1
    public function setBodyTag($body_tag)
76
    {
77 1
        $this->options['body_tag'] = $body_tag;
78
79 1
        return $this;
80
    }
81
82
    /**
83
     * @throws Exception\RuntimeException
84
     *
85
     * @param Options $options
86
     *
87
     * @return string xml encoded data
88
     */
89 2
    public function getData(Options $options = null)
90
    {
91 2
        if ($options === null) {
92
            // Take store global/default options
93 2
            $options = $this->store->getOptions();
94
        }
95
96
        // Get unformatted data when using xml writer
97 2
        $options->getHydrationOptions()->disableFormatters();
98
99 2
        $data = $this->store->getData($options);
100 2
        $bt = $this->options['body_tag'];
101 2
        $encoding = $this->options['encoding'];
102 2
        $xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"$encoding\" ?><$bt></$bt>");
103
104 2
        $now = new DateTime();
105
        $d = [
106 2
            'success' => true,
107 2
            'timestamp' => $now->format(DateTime::W3C),
108 2
            'total' => $data->getTotalRows(),
109 2
            'start' => $data->getSource()->getOptions()->getOffset(),
110 2
            'limit' => $data->getSource()->getOptions()->getLimit(),
111 2
            'data' => $data->toArray(),
112
        ];
113
114 2
        if ($this->options['debug']) {
115
            $d['query'] = $data->getSource()->getQueryString();
116
        }
117 2
        $this->createXmlNode($d, $xml);
118
119 2
        $string = $xml->asXML();
120 2
        if ($string === false) {
121
            throw new Exception\RuntimeException(__METHOD__ . ' XML creation failed.');
122
        }
123
124 2
        return (string) $string;
125
    }
126
127
    /**
128
     * @param array            $result
129
     * @param SimpleXMLElement $xml
130
     */
131 1
    protected function createXmlNode($result, SimpleXMLElement $xml)
132
    {
133 1
        foreach ($result as $key => $value) {
134 1
            if (is_array($value)) {
135 1
                if (!is_numeric($key)) {
136 1
                    $subnode = $xml->addChild("$key");
137 1
                    $this->createXmlNode($value, $subnode);
138
                } else {
139 1
                    $v = [$this->options['row_tag'] => $value];
140 1
                    $this->createXmlNode($v, $xml);
141
                }
142
            } else {
143 1
                if ($this->php_54_compatibility) {
144
                    // assuming php 5.4+
145 1
                    $encoded = htmlspecialchars($value, ENT_XML1, $this->options['encoding']);
146
                } else {
147
                    $encoded = '';
148
149
                    foreach (str_split(utf8_decode(htmlspecialchars($value))) as $char) {
150
                        $num = ord($char);
151
                        if ($num > 127) {
152
                            $encoded .= '&#' . $num . ';';
153
                        } else {
154
                            $encoded .= $char;
155
                        }
156
                    }
157
                }
158 1
                $xml->addChild($key, $encoded);
159
            }
160
        }
161 1
    }
162
163
    /**
164
     * Return default headers for sending store data via http.
165
     *
166
     * @return SimpleHeaders
167
     */
168 1
    public function getHttpHeaders()
169
    {
170 1
        if ($this->headers === null) {
171 1
            $this->headers = new SimpleHeaders();
172 1
            $this->headers->setContentType('application/xml', $this->options['encoding']);
173 1
            $this->headers->setContentDispositionType(SimpleHeaders::DIPOSITION_ATTACHEMENT);
174
        }
175
176 1
        return $this->headers;
177
    }
178
}
179