Completed
Pull Request — master (#743)
by Asmir
07:41
created

JsonSerializationVisitor   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 165
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 91.3%

Importance

Changes 0
Metric Value
wmc 34
lcom 2
cbo 6
dl 0
loc 165
ccs 63
cts 69
cp 0.913
rs 9.2
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A setNavigator() 0 5 1
A visitNull() 0 4 1
A visitString() 0 4 1
A visitBoolean() 0 4 1
A visitInteger() 0 4 1
A visitDouble() 0 4 1
C visitArray() 0 25 7
A startVisitingObject() 0 5 1
A endVisitingObject() 0 12 2
C visitProperty() 0 25 11
A hasData() 0 4 1
A setData() 0 4 1
A getResult() 0 15 3
A getOptions() 0 4 1
A setOptions() 0 4 1
1
<?php
2
3
/*
4
 * Copyright 2016 Johannes M. Schmitt <[email protected]>
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace JMS\Serializer;
20
21
use JMS\Serializer\Metadata\ClassMetadata;
22
use JMS\Serializer\Metadata\PropertyMetadata;
23
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;
24
25
class JsonSerializationVisitor extends AbstractVisitor implements SerializationVisitorInterface
26
{
27
    private $options = 0;
28
29
    private $navigator;
30
    private $dataStack;
31
    private $data;
32
33 241
    public function setNavigator(GraphNavigatorInterface $navigator): void
34
    {
35 241
        $this->navigator = $navigator;
36 241
        $this->dataStack = new \SplStack;
37 241
    }
38
39 44
    public function visitNull($data, array $type, SerializationContext $context)
40
    {
41 44
        return null;
42
    }
43
44 151
    public function visitString(string $data, array $type, SerializationContext $context)
45
    {
46 151
        return $data;
47
    }
48
49 15
    public function visitBoolean(bool $data, array $type, SerializationContext $context)
50
    {
51 15
        return $data;
52
    }
53
54 48
    public function visitInteger(int $data, array $type, SerializationContext $context)
55
    {
56 48
        return $data;
57
    }
58
59 22
    public function visitDouble(float $data, array $type, SerializationContext $context)
60
    {
61 22
        return $data;
62
    }
63
64
    /**
65
     * @param array $data
66
     * @param array $type
67
     * @param SerializationContext $context
68
     * @return mixed
69
     */
70 113
    public function visitArray(array $data, array $type, SerializationContext $context)
71
    {
72 113
        $this->dataStack->push($data);
73
74 113
        $rs = isset($type['params'][1]) ? new \ArrayObject() : array();
75
76 113
        $isList = isset($type['params'][0]) && !isset($type['params'][1]);
77
78 113
        foreach ($data as $k => $v) {
79 102
            $v = $this->navigator->accept($v, $this->getElementType($type), $context);
80
81 102
            if (null === $v && $context->shouldSerializeNull() !== true) {
82 5
                continue;
83
            }
84
85 102
            if ($isList) {
86 28
                $rs[] = $v;
87
            } else {
88 102
                $rs[$k] = $v;
89
            }
90
        }
91
92 113
        $this->dataStack->pop();
93 113
        return $rs;
94
    }
95
96 136
    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, SerializationContext $context): void
97
    {
98 136
        $this->dataStack->push($this->data);
99 136
        $this->data = array();
100 136
    }
101
102 134
    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, SerializationContext $context)
103
    {
104 134
        $rs = $this->data;
105 134
        $this->data = $this->dataStack->pop();
106
107
        // Force JSON output to "{}" instead of "[]" if it contains either no properties or all properties are null.
108 134
        if (empty($rs)) {
109 12
            $rs = new \ArrayObject();
110
        }
111
112 134
        return $rs;
113
    }
114
115 132
    public function visitProperty(PropertyMetadata $metadata, $data, SerializationContext $context): void
116
    {
117 132
        $v = $this->accessor->getValue($data, $metadata);
118
119 130
        $v = $this->navigator->accept($v, $metadata->type, $context);
120 130
        if ((null === $v && $context->shouldSerializeNull() !== true)
121 130
            || (true === $metadata->skipWhenEmpty && ($v instanceof \ArrayObject || \is_array($v)) && 0 === count($v))
122
        ) {
123 26
            return;
124
        }
125
126 127
        if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
127 1
            $k = $this->namingStrategy->getPropertyName($metadata, $context);
128
        } else {
129 126
            $k = $this->namingStrategy->translateName($metadata);
130
        }
131
132 127
        if ($metadata->inline) {
133 5
            if (\is_array($v) || ($v instanceof \ArrayObject)) {
134 5
                $this->data = array_merge($this->data, (array)$v);
135
            }
136
        } else {
137 126
            $this->data[$k] = $v;
138
        }
139 127
    }
140
141
    /**
142
     * Checks if some data key exists.
143
     *
144
     * @param string $key
145
     * @return boolean
146
     */
147 1
    public function hasData($key)
148
    {
149 1
        return isset($this->data[$key]);
150
    }
151
152
    /**
153
     * Allows you to replace existing data on the current object/root element.
154
     *
155
     * @param string $key
156
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
157
     *                                                       It must not contain any objects anymore.
158
     */
159 2
    public function setData($key, $value)
160
    {
161 2
        $this->data[$key] = $value;
162 2
    }
163
164 134
    public function getResult($data)
165
    {
166 134
        $result = @json_encode($data, $this->options);
167
168 134
        switch (json_last_error()) {
169 134
            case JSON_ERROR_NONE:
170 132
                return $result;
171
172 2
            case JSON_ERROR_UTF8:
173 2
                throw new \RuntimeException('Your data could not be encoded because it contains invalid UTF8 characters.');
174
175
            default:
176
                throw new \RuntimeException(sprintf('An error occurred while encoding your data (error code %d).', json_last_error()));
177
        }
178
    }
179
180
    public function getOptions()
181
    {
182
        return $this->options;
183
    }
184
185
    public function setOptions($options)
186
    {
187
        $this->options = (integer)$options;
188
    }
189
}
190