Passed
Branch master (f07ed3)
by Nate
02:39
created

JsonElementWriter::topIsObjectStart()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 10
cc 3
nc 3
nop 0
crap 3
1
<?php
2
/*
3
 * Copyright (c) Nate Brunette.
4
 * Distributed under the MIT License (http://opensource.org/licenses/MIT)
5
 */
6
7
declare(strict_types=1);
8
9
namespace Tebru\Gson\Internal;
10
11
use JsonSerializable;
12
use LogicException;
13
use Tebru\Gson\Element\JsonArray;
14
use Tebru\Gson\Element\JsonElement;
15
use Tebru\Gson\Element\JsonNull;
16
use Tebru\Gson\Element\JsonObject;
17
use Tebru\Gson\Element\JsonPrimitive;
18
use Tebru\Gson\JsonWritable;
19
20
/**
21
 * Class JsonElementWriter
22
 *
23
 * @author Nate Brunette <[email protected]>
24
 */
25
final class JsonElementWriter implements JsonWritable, JsonSerializable
26
{
27
    /**
28
     * True if we should serialize nulls
29
     *
30
     * @var bool
31
     */
32
    private $serializeNull = false;
33
34
    /**
35
     * Stack of values to be written
36
     *
37
     * @var array
38
     */
39
    private $stack = [];
40
    
41
    /**
42
     * Size of the stack array
43
     *
44
     * @var int
45
     */
46
    private $stackSize = 0;
47
48
    /**
49
     * A cache of the parsing state corresponding to the stack
50
     *
51
     * @var int[]
52
     */
53
    private $stackStates = [];
54
55
    /**
56
     * When serializing an object, store the name that should be serialized
57
     *
58
     * @var
59
     */
60
    private $pendingName;
61
62
    /**
63
     * The final result that will be json encoded
64
     *
65
     * @var JsonElement
66
     */
67
    private $result;
68
69
    /**
70
     * Begin writing array
71
     *
72
     * @return JsonWritable
73
     * @throws \LogicException
74
     */
75 6
    public function beginArray(): JsonWritable
76
    {
77 6
        if ($this->stackSize > 0 && $this->stackStates[$this->stackSize - 1] === self::STATE_OBJECT_NAME) {
78 1
            throw new LogicException('Cannot call beginArray() before name() during object serialization');
79
        }
80
81 5
        $array = new JsonArray();
82 5
        $this->push($array);
83 5
        $this->stack[] = $array;
84 5
        $this->stackStates[$this->stackSize] = self::STATE_ARRAY;
85 5
        $this->stackSize++;
86
87 5
        return $this;
88
    }
89
90
    /**
91
     * End writing array
92
     *
93
     * @return JsonWritable
94
     * @throws \LogicException
95
     */
96 4
    public function endArray(): JsonWritable
97
    {
98 4
        if ($this->stackSize === 0 || $this->stackStates[$this->stackSize - 1] !== self::STATE_ARRAY) {
99 2
            throw new LogicException('Cannot call endArray() if not serializing array');
100
        }
101
102 2
        \array_pop($this->stack);
103 2
        $this->stackSize--;
104
105 2
        return $this;
106
    }
107
108
    /**
109
     * Begin writing object
110
     *
111
     * @return JsonWritable
112
     * @throws \LogicException
113
     */
114 17
    public function beginObject(): JsonWritable
115
    {
116 17
        if ($this->stackSize > 0 && $this->stackStates[$this->stackSize - 1] === self::STATE_OBJECT_NAME) {
117 1
            throw new LogicException('Cannot call beginObject() before name() during object serialization');
118
        }
119
120 17
        $class = new JsonObject();
121 17
        $this->push($class);
122 17
        $this->stack[$this->stackSize] = $class;
123 17
        $this->stackStates[$this->stackSize] = self::STATE_OBJECT_NAME;
124 17
        $this->stackSize++;
125
126 17
        return $this;
127
    }
128
129
    /**
130
     * End writing object
131
     *
132
     * @return JsonWritable
133
     * @throws \LogicException
134
     */
135 7
    public function endObject(): JsonWritable
136
    {
137 7
        if ($this->stackSize === 0 || $this->stackStates[$this->stackSize - 1] !== self::STATE_OBJECT_NAME) {
138 2
            throw new LogicException('Cannot call endObject() if not serializing object');
139
        }
140
141 5
        \array_pop($this->stack);
142 5
        $this->stackSize--;
143
144 5
        return $this;
145
    }
146
147
    /**
148
     * Writes a property name
149
     *
150
     * @param string $name
151
     * @return JsonWritable
152
     * @throws \LogicException
153
     */
154 5
    public function name(string $name): JsonWritable
155
    {
156 5
        if ($this->stackStates[$this->stackSize - 1] !== self::STATE_OBJECT_NAME) {
157 1
            throw new LogicException('Cannot call name() at this point.  Either name() has already been called or object serialization has not been started');
158
        }
159
160 5
        $this->pendingName = $name;
161 5
        $this->stackStates[$this->stackSize - 1] = self::STATE_OBJECT_VALUE;
162
163 5
        return $this;
164
    }
165
166
    /**
167
     * Write an integer value
168
     *
169
     * @param int $value
170
     * @return JsonWritable
171
     * @throws \LogicException
172
     */
173 4
    public function writeInteger(int $value): JsonWritable
174
    {
175 4
        if ($this->stackSize > 0 && $this->stackStates[$this->stackSize - 1] === self::STATE_OBJECT_NAME) {
176 1
            throw new LogicException('Cannot call writeInteger() before name() during object serialization');
177
        }
178
179 3
        return $this->push(JsonPrimitive::create($value));
180
    }
181
182
    /**
183
     * Write a float value
184
     *
185
     * @param float $value
186
     * @return JsonWritable
187
     * @throws \LogicException
188
     */
189 3
    public function writeFloat(float $value): JsonWritable
190
    {
191 3
        if ($this->stackSize > 0 && $this->stackStates[$this->stackSize - 1] === self::STATE_OBJECT_NAME) {
192 1
            throw new LogicException('Cannot call writeFloat() before name() during object serialization');
193
        }
194
195 2
        return $this->push(JsonPrimitive::create($value));
196
    }
197
198
    /**
199
     * Write a string value
200
     *
201
     * @param string $value
202
     * @return JsonWritable
203
     * @throws \LogicException
204
     */
205 4
    public function writeString(string $value): JsonWritable
206
    {
207 4
        if ($this->stackSize > 0 && $this->stackStates[$this->stackSize - 1] === self::STATE_OBJECT_NAME) {
208 1
            throw new LogicException('Cannot call writeString() before name() during object serialization');
209
        }
210
211 3
        return $this->push(JsonPrimitive::create($value));
212
    }
213
214
    /**
215
     * Write a boolean value
216
     *
217
     * @param boolean $value
218
     * @return JsonWritable
219
     * @throws \LogicException
220
     */
221 3
    public function writeBoolean(bool $value): JsonWritable
222
    {
223 3
        if ($this->stackSize > 0 && $this->stackStates[$this->stackSize - 1] === self::STATE_OBJECT_NAME) {
224 1
            throw new LogicException('Cannot call writeBoolean() before name() during object serialization');
225
        }
226
227 2
        return $this->push(JsonPrimitive::create($value));
228
    }
229
230
    /**
231
     * Write a null value if we are serializing nulls, otherwise
232
     * skip the value.  If this is a property value, that property
233
     * should be skipped as well.
234
     *
235
     * @return JsonWritable
236
     * @throws \LogicException
237
     */
238 5
    public function writeNull(): JsonWritable
239
    {
240 5
        if ($this->stackSize > 0 && $this->stackStates[$this->stackSize - 1] === self::STATE_OBJECT_NAME) {
241 1
            throw new LogicException('Cannot call writeNull() before name() during object serialization');
242
        }
243
244 4
        if ($this->serializeNull) {
245 2
            return $this->push(new JsonNull());
246
        }
247
248
        // if we're not serializing nulls
249 2
        if (null !== $this->pendingName) {
250 1
            $this->stackStates[$this->stackSize - 1] = self::STATE_OBJECT_NAME;
251 1
            $this->pendingName = null;
252
        }
253
254 2
        return $this;
255
    }
256
257
    /**
258
     * Sets whether nulls are serialized
259
     *
260
     * @param bool $serializeNull
261
     * @return void
262
     */
263 2
    public function setSerializeNull(bool $serializeNull): void
264
    {
265 2
        $this->serializeNull = $serializeNull;
266 2
    }
267
268
    /**
269
     * Specify data which should be serialized to JSON
270
     *
271
     * @return mixed
272
     */
273 17
    public function jsonSerialize()
274
    {
275 17
        if (null === $this->result) {
276 1
            return null;
277
        }
278
279 16
        return $this->result->jsonSerialize();
280
    }
281
282
    /**
283
     * Get the result as a json element
284
     *
285
     * @return JsonElement
286
     */
287 1
    public function toJsonElement(): JsonElement
288
    {
289 1
        return $this->result;
290
    }
291
292
    /**
293
     * Push a value to the result or current array/object
294
     *
295
     * @param JsonElement $value
296
     * @return JsonWritable
297
     * @throws \LogicException
298
     */
299 29
    private function push(JsonElement $value): JsonWritable
300
    {
301 29
        if (0 === $this->stackSize) {
302 29
            if (null !== $this->result) {
303 2
                throw new LogicException('Attempting to write two different types');
304
            }
305
306 29
            $this->result = $value;
307
308 29
            return $this;
309
        }
310
311 5
        switch ($this->stackStates[$this->stackSize - 1]) {
312 5
            case self::STATE_OBJECT_VALUE:
313 3
                $this->stack[$this->stackSize - 1]->add($this->pendingName, $value);
314 3
                $this->stackStates[$this->stackSize - 1] = self::STATE_OBJECT_NAME;
315 3
                $this->pendingName = null;
316 3
                break;
317 2
            case self::STATE_ARRAY:
318 2
                $this->stack[$this->stackSize - 1]->addJsonElement($value);
319 2
                $this->stackStates[$this->stackSize - 1] = self::STATE_ARRAY;
320 2
                break;
321
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
322
        }
323
324 5
        return $this;
325
    }
326
}
327