Passed
Branch master (bf85d9)
by Johannes
05:40
created

JsonSerializationVisitor::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 4
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
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\Accessor\AccessorStrategyInterface;
22
use JMS\Serializer\Exception\NotAcceptableException;
23
use JMS\Serializer\Exception\RuntimeException;
24
use JMS\Serializer\Metadata\ClassMetadata;
25
use JMS\Serializer\Metadata\PropertyMetadata;
26
27
class JsonSerializationVisitor extends AbstractVisitor implements SerializationVisitorInterface
28
{
29
    private $options = JSON_PRESERVE_ZERO_FRACTION;
30
31
    private $dataStack;
32
    private $data;
33
34
    /**
35
     * @var bool
36
     */
37
    protected $shouldSerializeNull;
38
39 164
    public function __construct(
40
        GraphNavigatorInterface $navigator,
41
        AccessorStrategyInterface $accessorStrategy,
42
        SerializationContext $context,
43
        int $options = JSON_PRESERVE_ZERO_FRACTION)
44
    {
45 164
        parent::__construct($navigator, $accessorStrategy, $context);
46 164
        $this->shouldSerializeNull = $context->shouldSerializeNull();
47 164
        $this->dataStack = new \SplStack;
48 164
        $this->options = $options;
49 164
    }
50
51 14
    public function visitNull($data, array $type)
52
    {
53 14
        return null;
54
    }
55
56 91
    public function visitString(string $data, array $type)
57
    {
58 91
        return $data;
59
    }
60
61 9
    public function visitBoolean(bool $data, array $type)
62
    {
63 9
        return $data;
64
    }
65
66 26
    public function visitInteger(int $data, array $type)
67
    {
68 26
        return $data;
69
    }
70
71 13
    public function visitDouble(float $data, array $type)
72
    {
73 13
        return $data;
74
    }
75
76
    /**
77
     * @param array $data
78
     * @param array $type
79
     * @param SerializationContext $context
80
     * @return mixed
81
     */
82 74
    public function visitArray(array $data, array $type)
83
    {
84 74
        $this->dataStack->push($data);
85
86 74
        $rs = isset($type['params'][1]) ? new \ArrayObject() : array();
87
88 74
        $isList = isset($type['params'][0]) && !isset($type['params'][1]);
89
90 74
        $elType = $this->getElementType($type);
91 74
        foreach ($data as $k => $v) {
92
93 68
            if (null === $v && $this->shouldSerializeNull !== true) {
94 2
                continue;
95
            }
96
97
            try {
98 68
                $v = $this->navigator->accept($v, $elType, $this->context);
99 4
            } catch (NotAcceptableException $e) {
100 4
                continue;
101
            }
102
103 65
            if ($isList) {
104 17
                $rs[] = $v;
105
            } else {
106 65
                $rs[$k] = $v;
107
            }
108
        }
109
110 74
        $this->dataStack->pop();
111 74
        return $rs;
112
    }
113
114 84
    public function startVisitingObject(ClassMetadata $metadata, object $data, array $type): void
115
    {
116 84
        $this->dataStack->push($this->data);
117 84
        $this->data = array();
118 84
    }
119
120 83
    public function endVisitingObject(ClassMetadata $metadata, object $data, array $type)
121
    {
122 83
        $rs = $this->data;
123 83
        $this->data = $this->dataStack->pop();
124
125
        // Force JSON output to "{}" instead of "[]" if it contains either no properties or all properties are null.
126 83
        if (empty($rs)) {
127 11
            $rs = new \ArrayObject();
128
        }
129
130 83
        return $rs;
131
    }
132
133 80
    public function visitProperty(PropertyMetadata $metadata, $data): void
134
    {
135 80
        $v = $this->accessor->getValue($data, $metadata);
136
137 79
        if (null === $v && $this->shouldSerializeNull !== true) {
138 13
            return;
139
        }
140
141
        try {
142 77
            $v = $this->navigator->accept($v, $metadata->type, $this->context);
143 4
        } catch (NotAcceptableException $e) {
144 4
            return;
145
        }
146
147 77
        if (true === $metadata->skipWhenEmpty && ($v instanceof \ArrayObject || \is_array($v)) && 0 === count($v)) {
148 2
            return;
149
        }
150
151 76
        if ($metadata->inline) {
152 3
            if (\is_array($v) || ($v instanceof \ArrayObject)) {
153 3
                $this->data = array_merge($this->data, (array)$v);
154
            }
155
        } else {
156 75
            $this->data[$metadata->serializedName] = $v;
157
        }
158 76
    }
159
160
    /**
161
     * Checks if some data key exists.
162
     *
163
     * @param string $key
164
     * @return boolean
165
     */
166 1
    public function hasData($key)
167
    {
168 1
        return isset($this->data[$key]);
169
    }
170
171
    /**
172
     * Allows you to replace existing data on the current object/root element.
173
     *
174
     * @param string $key
175
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
176
     *                                                       It must not contain any objects anymore.
177
     */
178 2
    public function setData($key, $value)
179
    {
180 2
        $this->data[$key] = $value;
181 2
    }
182
183 136
    public function getResult($data)
184
    {
185 136
        $result = @json_encode($data, $this->options);
186
187 136
        switch (json_last_error()) {
188 136
            case JSON_ERROR_NONE:
189 134
                return $result;
190
191 2
            case JSON_ERROR_UTF8:
192 2
                throw new RuntimeException('Your data could not be encoded because it contains invalid UTF8 characters.');
193
194
            default:
195
                throw new RuntimeException(sprintf('An error occurred while encoding your data (error code %d).', json_last_error()));
196
        }
197
    }
198
}
199