Completed
Push — master ( 89419d...f547e3 )
by Asmir
28:00 queued 10:26
created

JsonSerializationVisitor::visitArray()   D

Complexity

Conditions 9
Paths 32

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 9

Importance

Changes 0
Metric Value
dl 0
loc 32
ccs 20
cts 20
cp 1
rs 4.909
c 0
b 0
f 0
cc 9
eloc 19
nc 32
nop 3
crap 9
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\Exception\InvalidArgumentException;
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 141
    public function setNavigator(GraphNavigator $navigator)
35
    {
36 141
        $this->navigator = $navigator;
37 141
        $this->root = null;
38 141
        $this->dataStack = new \SplStack;
39 141
    }
40
41
    /**
42
     * @return GraphNavigator
43
     */
44
    public function getNavigator()
45
    {
46
        return $this->navigator;
47
    }
48
49 26
    public function visitNull($data, array $type, Context $context)
50
    {
51 26
        return null;
52
    }
53
54 86
    public function visitString($data, array $type, Context $context)
55
    {
56 86
        if (null === $this->root) {
57 9
            $this->root = $data;
58 9
        }
59
60 86
        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 69
    public function visitArray($data, array $type, Context $context)
97
    {
98 69
        $this->dataStack->push($data);
99
100 69
        $isHash = isset($type['params'][1]);
101
102 69
        if (null === $this->root) {
103 49
            $this->root = $isHash ? new \ArrayObject() : array();
104 49
            $rs = &$this->root;
105 49
        } else {
106 22
            $rs = $isHash ? new \ArrayObject() : array();
107
        }
108
109 69
        $isList = isset($type['params'][0]) && ! isset($type['params'][1]);
110
111 69
        foreach ($data as $k => $v) {
112 64
            $v = $this->navigator->accept($v, $this->getElementType($type), $context);
113
114 64
            if (null === $v && $context->shouldSerializeNull() !== true) {
115 3
                continue;
116
            }
117
118 64
            if ($isList) {
119 17
                $rs[] = $v;
120 17
            } else {
121 51
                $rs[$k] = $v;
122
            }
123 69
        }
124
125 69
        $this->dataStack->pop();
126 69
        return $rs;
127
    }
128
129 78
    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
130
    {
131 78
        if (null === $this->root) {
132 63
            $this->root = new \stdClass;
133 63
        }
134
135 78
        $this->dataStack->push($this->data);
136 78
        $this->data = array();
137 78
    }
138
139 77
    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
140
    {
141 77
        $rs = $this->data;
142 77
        $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 77
        if (empty($rs)) {
146 8
            $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 8
        }
148
149 77
        if ($this->root instanceof \stdClass && 0 === $this->dataStack->count()) {
150 62
            $this->root = $rs;
151 62
        }
152
153 77
        return $rs;
154
    }
155
156 74
    public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
157
    {
158 74
        $v = $this->accessor->getValue($data, $metadata);
159
160 73
        $v = $this->navigator->accept($v, $metadata->type, $context);
161 73
        if (null === $v && $context->shouldSerializeNull() !== true) {
162 13
            return;
163
        }
164
165 71
        $k = $this->namingStrategy->translateName($metadata);
166
167 71
        if ($metadata->inline) {
168 2
            if (is_array($v)) {
169 1
                $this->data = array_merge($this->data, $v);
170 1
            }
171 2
        } else {
172 71
            $this->data[$k] = $v;
173
        }
174 71
    }
175
176
    /**
177
     * Allows you to add additional data to the current object/root element.
178
     * @deprecated use setData instead
179
     * @param string $key
180
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
181
     *                                                       It must not contain any objects anymore.
182
     */
183 1
    public function addData($key, $value)
184
    {
185 1
        if (isset($this->data[$key])) {
186
            throw new InvalidArgumentException(sprintf('There is already data for "%s".', $key));
187
        }
188
189 1
        $this->data[$key] = $value;
190 1
    }
191
192
    /**
193
     * Checks if some data key exists.
194
     *
195
     * @param string $key
196
     * @return boolean
197
     */
198 1
    public function hasData($key)
199
    {
200 1
        return isset($this->data[$key]);
201
    }
202
203
    /**
204
     * Allows you to replace existing data on the current object/root element.
205
     *
206
     * @param string $key
207
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
208
     *                                                       It must not contain any objects anymore.
209
     */
210 1
    public function setData($key, $value)
211
    {
212 1
        $this->data[$key] = $value;
213 1
    }
214
215 141
    public function getRoot()
216
    {
217 141
        return $this->root;
218
    }
219
220
    /**
221
     * @param array|\ArrayObject $data the passed data must be understood by whatever encoding function is applied later.
222
     */
223 7
    public function setRoot($data)
224
    {
225 7
        $this->root = $data;
226 7
    }
227
228
229 130
    public function getResult()
230
    {
231 130
        $result = @json_encode($this->getRoot(), $this->options);
232
233 130
        switch (json_last_error()) {
234 130
            case JSON_ERROR_NONE:
235 128
                return $result;
236
237 2
            case JSON_ERROR_UTF8:
238 2
                throw new \RuntimeException('Your data could not be encoded because it contains invalid UTF8 characters.');
239
240
            default:
241
                throw new \RuntimeException(sprintf('An error occurred while encoding your data (error code %d).', json_last_error()));
242
        }
243
    }
244
245
    public function getOptions()
246
    {
247
        return $this->options;
248
    }
249
250
    public function setOptions($options)
251
    {
252
        $this->options = (integer) $options;
253
    }
254
}
255