XmlTypeEncoder::dataToArrayNode()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 29
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 3
nop 4
dl 0
loc 29
ccs 11
cts 11
cp 1
crap 4
rs 9.7666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Serialization\Encoder;
6
7
use Doctrine\Common\Inflector\Inflector;
8
9
/**
10
 * @deprecated use JsonxTypeEncoder instead
11
 */
12
final class XmlTypeEncoder implements TypeEncoderInterface
13
{
14
    /**
15
     * @var bool
16
     */
17
    private $prettyPrint;
18
19
    public function __construct(bool $prettyPrint = false)
20
    {
21
        $this->prettyPrint = $prettyPrint;
22 4
    }
23
24 4
    public function getContentType(): string
25 4
    {
26
        return 'application/xml';
27
    }
28
29
    public function encode(array $data): string
30 1
    {
31
        $document = new \DOMDocument('1.0', 'UTF-8');
32 1
        $document->formatOutput = $this->prettyPrint;
33
34
        $listNode = $this->createMetadataNode($document, $data['_type'] ?? null);
35
36
        unset($data['_type']);
37
38
        $document->appendChild($listNode);
39
40 3
        $this->dataToNodes($document, $listNode, $data);
41
42 3
        return trim($document->saveXML($document, LIBXML_NOEMPTYTAG));
43 3
    }
44
45 3
    private function createMetadataNode(\DOMDocument $document, string $type = null): \DOMNode
46
    {
47 3
        $node = $document->createElement('object');
48
        if (null !== $type) {
49 3
            $node->setAttribute('type', $type);
50
        }
51 3
52
        return $node;
53 2
    }
54
55
    /**
56
     * @return string
57
     */
58
    private function getMetaPrefix(string $name)
59
    {
60
        return 'meta-'.$name;
61
    }
62 3
63
    private function dataToNodes(\DOMDocument $document, \DOMNode $listNode, array $data): void
64 3
    {
65 3
        foreach ($data as $key => $value) {
66 1
            if (is_string($key) && '_' === $key[0]) {
67
                $key = $this->getMetaPrefix(substr($key, 1));
68
            }
69 3
70
            if (is_array($value)) {
71
                $childNode = $this->dataToArrayNode($document, $listNode, $key, $value);
72
            } else {
73
                $childNode = $this->dataToScalarNode($document, $listNode, $key, $value);
74
            }
75
76
            if (is_int($key)) {
77 1
                $childNode->setAttribute('key', (string) $key);
78
            }
79 1
80
            $listNode->appendChild($childNode);
81
        }
82
    }
83
84
    /**
85
     * @param string|int $key
86
     *
87 3
     * @return \DOMElement|\DOMNode
88
     */
89 3
    private function dataToArrayNode(\DOMDocument $document, \DOMNode $listNode, $key, array $value)
90 3
    {
91 1
        if (!isset($value['_type'])) {
92
            $childNode = $document->createElement(is_int($key) ? Inflector::singularize($listNode->nodeName) : $key);
93
            $this->dataToNodes($document, $childNode, $value);
94 3
95 1
            return $childNode;
96
        }
97 3
98
        if (is_int($key)) {
99
            $childNode = $this->createMetadataNode($document, $value['_type']);
100 2
101 1
            unset($value['_type']);
102
103
            $this->dataToNodes($document, $childNode, $value);
104 2
105
            return $childNode;
106 2
        }
107
108
        $subChildNode = $this->createMetadataNode($document, $value['_type']);
109
110
        unset($value['_type']);
111
112
        $childNode = $document->createElement($key);
113
        $childNode->appendChild($subChildNode);
114
115
        $this->dataToNodes($document, $subChildNode, $value);
116 1
117
        return $childNode;
118 1
    }
119 1
120 1
    /**
121
     * @param string|int                 $key
122 1
     * @param string|bool|float|int|null $value
123
     */
124
    private function dataToScalarNode(\DOMDocument $document, \DOMNode $listNode, $key, $value): \DOMNode
125 1
    {
126 1
        $stringKey = is_int($key) ? Inflector::singularize($listNode->nodeName) : $key;
127
128 1
        if (is_string($value)) {
129
            if (false !== strpos($value, '<') || false !== strpos($value, '&')) {
130 1
                $childNode = $document->createElement($stringKey);
131
                $childNode->appendChild($document->createCDATASection($value));
132 1
            } else {
133
                $childNode = $document->createElement($stringKey, $value);
134
            }
135 1
136
            $childNode->setAttribute('type', 'string');
137 1
138
            return $childNode;
139 1
        }
140 1
141
        if (null === $value) {
142 1
            return $document->createElement($stringKey);
143
        }
144 1
145
        $childNode = $document->createElement($stringKey, $this->getValueAsString($value));
146
        $childNode->setAttribute('type', $this->getType($value));
147
148
        return $childNode;
149
    }
150
151
    /**
152
     * @param bool|float|int $value
153
     *
154
     * @throws \InvalidArgumentException
155 3
     */
156
    private function getValueAsString($value): string
157 3
    {
158
        if (is_bool($value)) {
159 3
            return $value ? 'true' : 'false';
160 2
        }
161 1
162 1
        if (is_float($value)) {
163
            $value = (string) $value;
164 2
            if (false === strpos($value, '.')) {
165
                $value .= '.0';
166
            }
167 2
168
            return $value;
169 2
        }
170
171
        if (is_int($value)) {
0 ignored issues
show
introduced by
The condition is_int($value) is always true.
Loading history...
172 2
            return (string) $value;
173 1
        }
174
175
        throw new \InvalidArgumentException(sprintf('Unsupported data type: %s', gettype($value)));
176 2
    }
177 1
178
    /**
179 1
     * @param bool|float|int|string $value
180
     */
181
    private function getType($value): string
182
    {
183
        if (is_bool($value)) {
184
            return 'boolean';
185
        }
186
187
        if (is_float($value)) {
188
            return 'float';
189 2
        }
190
191 2
        return 'integer';
192 1
    }
193
}
194