Completed
Pull Request — master (#859)
by
unknown
05:02
created

JsonSerializationVisitor::setData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 2
crap 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\Exception\InvalidArgumentException;
22
use JMS\Serializer\Metadata\ClassMetadata;
23
use JMS\Serializer\Metadata\PropertyMetadata;
24
25
class JsonSerializationVisitor extends GenericSerializationVisitor
0 ignored issues
show
Deprecated Code introduced by
The class JMS\Serializer\GenericSerializationVisitor has been deprecated.

This class, trait or interface has been deprecated.

Loading history...
26
{
27
    private $options = 0;
28
29
    private $navigator;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
30
    private $root;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
31
    private $dataStack;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
32
    private $data;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
33
34 146
    public function setNavigator(GraphNavigator $navigator)
35
    {
36 146
        $this->navigator = $navigator;
37 146
        $this->root = null;
38 146
        $this->dataStack = new \SplStack;
39 146
    }
40
41
    /**
42
     * @return GraphNavigator
43
     */
44
    public function getNavigator()
45
    {
46
        return $this->navigator;
47
    }
48
49 28
    public function visitNull($data, array $type, Context $context)
50
    {
51 28
        return null;
52
    }
53
54 90
    public function visitString($data, array $type, Context $context)
55
    {
56 90
        if (null === $this->root) {
57 9
            $this->root = $data;
58 9
        }
59
60 90
        return (string)$data;
61
    }
62
63 9
    public function visitBoolean($data, array $type, Context $context)
64
    {
65 9
        if (null === $this->root) {
66 5
            $this->root = $data;
67 5
        }
68
69 9
        return (boolean)$data;
70
    }
71
72 26
    public function visitInteger($data, array $type, Context $context)
73
    {
74 26
        if (null === $this->root) {
75 4
            $this->root = $data;
76 4
        }
77
78 26
        return (int)$data;
79
    }
80
81 13
    public function visitDouble($data, array $type, Context $context)
82
    {
83 13
        if (null === $this->root) {
84 7
            $this->root = $data;
85 7
        }
86
87 13
        return (float)$data;
88
    }
89
90
    /**
91
     * @param array $data
92
     * @param array $type
93
     * @param Context $context
94
     * @return mixed
95
     */
96 71
    public function visitArray($data, array $type, Context $context)
97
    {
98 71
        $this->dataStack->push($data);
99
100 71
        $isHash = isset($type['params'][1]);
101
102 71
        if (null === $this->root) {
103 49
            $this->root = $isHash ? new \ArrayObject() : array();
104 49
            $rs = &$this->root;
105 49
        } else {
106 24
            $rs = $isHash ? new \ArrayObject() : array();
107
        }
108
109 71
        $isList = isset($type['params'][0]) && !isset($type['params'][1]);
110
111 71
        foreach ($data as $k => $v) {
112 65
            $v = $this->navigator->accept($v, $this->getElementType($type), $context);
113
114 65
            if (null === $v && $context->shouldSerializeNull() !== true) {
115 3
                continue;
116
            }
117
118 65
            if ($isList) {
119 17
                $rs[] = $v;
120 17
            } else {
121 52
                $rs[$k] = $v;
122
            }
123 71
        }
124
125 71
        $this->dataStack->pop();
126 71
        return $rs;
127
    }
128
129 83
    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
130
    {
131 83
        if (null === $this->root) {
132 68
            $this->root = new \stdClass;
133 68
        }
134
135 83
        $this->dataStack->push($this->data);
136 83
        $this->data = array();
137 83
    }
138
139 82
    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
140
    {
141 82
        $rs = $this->data;
142 82
        $this->data = $this->dataStack->pop();
143
144
        // Force JSON output to "{}" instead of "[]" if it contains either no properties or all properties are null.
145 82
        if (empty($rs)) {
146 11
            $rs = new \ArrayObject();
0 ignored issues
show
Bug Compatibility introduced by
The expression new \ArrayObject(); of type ArrayObject adds the type ArrayObject to the return on line 153 which is incompatible with the return type of the parent method JMS\Serializer\GenericSe...itor::endVisitingObject of type array.
Loading history...
147 11
        }
148
149 82
        if ($this->root instanceof \stdClass && 0 === $this->dataStack->count()) {
150 67
            $this->root = $rs;
151 67
        }
152
153 82
        return $rs;
154
    }
155
156 79
    public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
157
    {
158 79
        $v = $this->accessor->getValue($data, $metadata);
159
160 78
        $v = $this->navigator->accept($v, $metadata->type, $context);
161 78
        if ((null === $v && $context->shouldSerializeNull() !== true)
162 76
            || (true === $metadata->skipWhenEmpty && ($v instanceof \ArrayObject || is_array($v)) && 0 === count($v))
163 78
        ) {
164 16
            return;
165
        }
166
167 75
        $k = $this->namingStrategy->translateName($metadata);
168 75
        if ($this->hasAdvancedNamingStrategy()) {
169
            $k = $this->advancedNamingStrategy->translateName($metadata, $context);
170
        }
171
172 75
        if ($metadata->inline) {
173 3
            if (is_array($v) || ($v instanceof \ArrayObject)) {
174 3
                $this->data = array_merge($this->data, (array) $v);
175 3
            }
176 3
        } else {
177 74
            $this->data[$k] = $v;
178
        }
179 75
    }
180
181
    /**
182
     * Allows you to add additional data to the current object/root element.
183
     * @deprecated use setData instead
184
     * @param string $key
185
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
186
     *                                                       It must not contain any objects anymore.
187
     */
188 1
    public function addData($key, $value)
189
    {
190 1
        if (isset($this->data[$key])) {
191
            throw new InvalidArgumentException(sprintf('There is already data for "%s".', $key));
192
        }
193
194 1
        $this->data[$key] = $value;
195 1
    }
196
197
    /**
198
     * Checks if some data key exists.
199
     *
200
     * @param string $key
201
     * @return boolean
202
     */
203 1
    public function hasData($key)
204
    {
205 1
        return isset($this->data[$key]);
206
    }
207
208
    /**
209
     * Allows you to replace existing data on the current object/root element.
210
     *
211
     * @param string $key
212
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
213
     *                                                       It must not contain any objects anymore.
214
     */
215 1
    public function setData($key, $value)
216
    {
217 1
        $this->data[$key] = $value;
218 1
    }
219
220 147
    public function getRoot()
221
    {
222 147
        return $this->root;
223
    }
224
225
    /**
226
     * @param array|\ArrayObject $data the passed data must be understood by whatever encoding function is applied later.
227
     */
228 8
    public function setRoot($data)
229
    {
230 8
        $this->root = $data;
231 8
    }
232
233
234 135
    public function getResult()
235
    {
236 135
        $result = @json_encode($this->getRoot(), $this->options);
237
238 135
        switch (json_last_error()) {
239 135
            case JSON_ERROR_NONE:
240 133
                return $result;
241
242 2
            case JSON_ERROR_UTF8:
243 2
                throw new \RuntimeException('Your data could not be encoded because it contains invalid UTF8 characters.');
244
245
            default:
246
                throw new \RuntimeException(sprintf('An error occurred while encoding your data (error code %d).', json_last_error()));
247
        }
248
    }
249
250
    public function getOptions()
251
    {
252
        return $this->options;
253
    }
254
255
    public function setOptions($options)
256
    {
257
        $this->options = (integer)$options;
258
    }
259
}
260