Passed
Push — master ( 93cd6a...e2ddf6 )
by Dominik
53s queued 11s
created

JsonxTypeDecoder::decodeNode()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 36
ccs 18
cts 18
cp 1
rs 8.0995
c 0
b 0
f 0
cc 8
nc 8
nop 1
crap 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Deserialization\Decoder;
6
7
use Chubbyphp\Deserialization\DeserializerRuntimeException;
8
9
/**
10
 * @see https://www.ibm.com/support/knowledgecenter/SS9H2Y_7.6.0/com.ibm.dp.doc/json_jsonx.html
11
 */
12
final class JsonxTypeDecoder implements TypeDecoderInterface
13
{
14
    const DATATYPE_OBJECT = 'object';
15
    const DATATYPE_ARRAY = 'array';
16
    const DATATYPE_BOOLEAN = 'boolean';
17
    const DATATYPE_STRING = 'string';
18
    const DATATYPE_NUMBER = 'number';
19
    const DATATYPE_NULL = 'null';
20
21
    /**
22
     * @return string
23
     */
24 4
    public function getContentType(): string
25
    {
26 4
        return 'application/x-jsonx';
27
    }
28
29
    /**
30
     * @param string $data
31
     *
32
     * @return array
33
     *
34
     * @throws DeserializerRuntimeException
35
     */
36 5
    public function decode(string $data): array
37
    {
38 5
        $document = new \DOMDocument();
39
40 5
        if (!@$document->loadXML($data)) {
41 1
            throw DeserializerRuntimeException::createNotParsable($this->getContentType());
42
        }
43
44 4
        return $this->decodeNode($document->documentElement);
45
    }
46
47
    /**
48
     * @param \DOMNode $node
49
     *
50
     * @return array|bool|string|int|float|null
51
     */
52 4
    private function decodeNode(\DOMNode $node)
53
    {
54 4
        $nodeName = $node->nodeName;
55
56 4
        if (0 !== strpos($nodeName, 'json:')) {
57 1
            throw DeserializerRuntimeException::createNotParsable($this->getContentType());
58
        }
59
60 3
        $nodeType = substr($nodeName, 5);
61
62 3
        if (self::DATATYPE_OBJECT === $nodeType) {
63 2
            return $this->decodeObjectNode($node);
64
        }
65
66 3
        if (self::DATATYPE_ARRAY === $nodeType) {
67 1
            return $this->decodeArrayNode($node);
68
        }
69
70 3
        if (self::DATATYPE_BOOLEAN === $nodeType) {
71 2
            return $this->decodeBooleanNode($node);
72
        }
73
74 3
        if (self::DATATYPE_STRING === $nodeType) {
75 2
            return $this->decodeStringNode($node);
76
        }
77
78 3
        if (self::DATATYPE_NUMBER === $nodeType) {
79 2
            return $this->decodeNumberNode($node);
80
        }
81
82 2
        if (self::DATATYPE_NULL === $nodeType) {
83 1
            return null;
84
        }
85
86 1
        throw DeserializerRuntimeException::createNotParsable($this->getContentType());
87
    }
88
89
    /**
90
     * @param \DOMNode $node
91
     *
92
     * @return array
93
     */
94 2 View Code Duplication
    private function decodeObjectNode(\DOMNode $node): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95
    {
96 2
        $data = [];
97 2
        foreach ($node->childNodes as $childNode) {
98 2
            if ($childNode instanceof \DOMText) {
99 2
                continue;
100
            }
101
102 2
            $data[$childNode->getAttribute('name')] = $this->decodeNode($childNode);
103
        }
104
105 2
        return $data;
106
    }
107
108
    /**
109
     * @param \DOMNode $node
110
     *
111
     * @return array
112
     */
113 1 View Code Duplication
    private function decodeArrayNode(\DOMNode $node): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
114
    {
115 1
        $data = [];
116 1
        foreach ($node->childNodes as $childNode) {
117 1
            if ($childNode instanceof \DOMText) {
118 1
                continue;
119
            }
120
121 1
            $data[] = $this->decodeNode($childNode);
122
        }
123
124 1
        return $data;
125
    }
126
127
    /**
128
     * @param \DOMNode $node
129
     *
130
     * @return bool
131
     */
132 2
    private function decodeBooleanNode(\DOMNode $node): bool
133
    {
134 2
        return 'true' === $node->nodeValue;
135
    }
136
137
    /**
138
     * @param \DOMNode $node
139
     *
140
     * @return string
141
     */
142 2
    private function decodeStringNode(\DOMNode $node): string
143
    {
144 2
        return html_entity_decode($node->nodeValue, ENT_COMPAT | ENT_XML1, 'UTF-8');
145
    }
146
147
    /**
148
     * @param \DOMNoDOMNodedeList $node
149
     *
150
     * @return int|float
151
     */
152 2
    private function decodeNumberNode(\DOMNode $node)
153
    {
154 2
        $value = $node->nodeValue;
155
156 2
        if ($value === (string) (int) $value) {
157 2
            return (int) $value;
158
        }
159
160 2
        return (float) $value;
161
    }
162
}
163