Completed
Push — master ( 66dded...f21dfb )
by Sébastien
08:51
created

SimpleXmlWriter::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481

Importance

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