Completed
Push — master ( c82e60...68cb49 )
by Sébastien
05:32
created

SimpleXmlWriter::getHttpHeaders()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

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