Completed
Push — master ( 2ec234...5a4364 )
by Nate
03:39
created

JsonElementWriter::stackSize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/*
3
 * Copyright (c) Nate Brunette.
4
 * Distributed under the MIT License (http://opensource.org/licenses/MIT)
5
 */
6
7
namespace Tebru\Gson\Internal;
8
9
use BadMethodCallException;
10
use JsonSerializable;
11
use Tebru\Gson\Element\JsonArray;
12
use Tebru\Gson\Element\JsonElement;
13
use Tebru\Gson\Element\JsonNull;
14
use Tebru\Gson\Element\JsonObject;
15
use Tebru\Gson\Element\JsonPrimitive;
16
use Tebru\Gson\JsonWritable;
17
18
/**
19
 * Class JsonElementWriter
20
 *
21
 * @author Nate Brunette <[email protected]>
22
 */
23
final class JsonElementWriter implements JsonWritable, JsonSerializable
24
{
25
    /**
26
     * True if we should serialize nulls
27
     *
28
     * @var bool
29
     */
30
    private $serializeNull = false;
31
32
    /**
33
     * Stack of values to be written
34
     *
35
     * @var array
36
     */
37
    private $stack = [];
38
    
39
    /**
40
     * Size of the stack array
41
     *
42
     * @var int
43
     */
44
    private $stackSize = 0;
45
46
    /**
47
     * When serializing an object, store the name that should be serialized
48
     *
49
     * @var
50
     */
51
    private $pendingName;
52
53
    /**
54
     * The final result that will be json encoded
55
     *
56
     * @var JsonElement
57
     */
58
    private $result;
59
60
    /**
61
     * Begin writing array
62
     *
63
     * @return JsonWritable
64
     * @throws \BadMethodCallException
65
     */
66 6 View Code Duplication
    public function beginArray(): JsonWritable
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
67
    {
68 6
        if ($this->topIsObjectStart()) {
69 1
            throw new BadMethodCallException('Cannot call beginArray() before name() during object serialization');
70
        }
71
72 5
        $array = new JsonArray();
73 5
        $this->push($array);
74 5
        $this->stack[] = $array;
75 5
        $this->stackSize++;
76
77 5
        return $this;
78
    }
79
80
    /**
81
     * End writing array
82
     *
83
     * @return JsonWritable
84
     * @throws \BadMethodCallException
85
     */
86 4
    public function endArray(): JsonWritable
87
    {
88 4
        if (!$this->topIsArray()) {
89 2
            throw new BadMethodCallException('Cannot call endArray() if not serializing array');
90
        }
91
92 2
        $this->pop();
93
94 2
        return $this;
95
    }
96
97
    /**
98
     * Begin writing object
99
     *
100
     * @return JsonWritable
101
     * @throws \BadMethodCallException
102
     */
103 17 View Code Duplication
    public function beginObject(): JsonWritable
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
104
    {
105 17
        if ($this->topIsObjectStart()) {
106 1
            throw new BadMethodCallException('Cannot call beginObject() before name() during object serialization');
107
        }
108
109 17
        $class = new JsonObject();
110 17
        $this->push($class);
111 17
        $this->stack[] = $class;
112 17
        $this->stackSize++;
113
114 17
        return $this;
115
    }
116
117
    /**
118
     * End writing object
119
     *
120
     * @return JsonWritable
121
     * @throws \BadMethodCallException
122
     */
123 7
    public function endObject(): JsonWritable
124
    {
125 7
        if (!$this->topIsObject()) {
126 2
            throw new BadMethodCallException('Cannot call endObject() if not serializing object');
127
        }
128
129 5
        $this->pop();
130
131 5
        return $this;
132
    }
133
134
    /**
135
     * Writes a property name
136
     *
137
     * @param string $name
138
     * @return JsonWritable
139
     * @throws \BadMethodCallException
140
     */
141 5
    public function name(string $name): JsonWritable
142
    {
143 5
        if (!$this->topIsObjectStart()) {
144 1
            throw new BadMethodCallException('Cannot call name() at this point.  Either name() has already been called or object serialization has not been started');
145
        }
146
147 5
        $this->pendingName = $name;
148
149 5
        return $this;
150
    }
151
152
    /**
153
     * Write an integer value
154
     *
155
     * @param int $value
156
     * @return JsonWritable
157
     * @throws \BadMethodCallException
158
     */
159 4
    public function writeInteger(int $value): JsonWritable
160
    {
161 4
        if ($this->topIsObjectStart()) {
162 1
            throw new BadMethodCallException('Cannot call writeInteger() before name() during object serialization');
163
        }
164
165 3
        return $this->push(JsonPrimitive::create($value));
166
    }
167
168
    /**
169
     * Write a float value
170
     *
171
     * @param float $value
172
     * @return JsonWritable
173
     * @throws \BadMethodCallException
174
     */
175 3
    public function writeFloat(float $value): JsonWritable
176
    {
177 3
        if ($this->topIsObjectStart()) {
178 1
            throw new BadMethodCallException('Cannot call writeFloat() before name() during object serialization');
179
        }
180
181 2
        return $this->push(JsonPrimitive::create($value));
182
    }
183
184
    /**
185
     * Write a string value
186
     *
187
     * @param string $value
188
     * @return JsonWritable
189
     * @throws \BadMethodCallException
190
     */
191 4
    public function writeString(string $value): JsonWritable
192
    {
193 4
        if ($this->topIsObjectStart()) {
194 1
            throw new BadMethodCallException('Cannot call writeString() before name() during object serialization');
195
        }
196
197 3
        return $this->push(JsonPrimitive::create($value));
198
    }
199
200
    /**
201
     * Write a boolean value
202
     *
203
     * @param boolean $value
204
     * @return JsonWritable
205
     * @throws \BadMethodCallException
206
     */
207 3
    public function writeBoolean(bool $value): JsonWritable
208
    {
209 3
        if ($this->topIsObjectStart()) {
210 1
            throw new BadMethodCallException('Cannot call writeBoolean() before name() during object serialization');
211
        }
212
213 2
        return $this->push(JsonPrimitive::create($value));
214
    }
215
216
    /**
217
     * Write a null value if we are serializing nulls, otherwise
218
     * skip the value.  If this is a property value, that property
219
     * should be skippped as well.
220
     *
221
     * @return JsonWritable
222
     * @throws \BadMethodCallException
223
     */
224 5 View Code Duplication
    public function writeNull(): JsonWritable
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
225
    {
226 5
        if ($this->topIsObjectStart()) {
227 1
            throw new BadMethodCallException('Cannot call writeNull() before name() during object serialization');
228
        }
229
230 4
        if ($this->serializeNull) {
231 2
            return $this->push(new JsonNull());
232
        }
233
234
        // if we're not serializing nulls
235 2
        if (null !== $this->pendingName) {
236 1
            $this->pendingName = null;
237
        }
238
239 2
        return $this;
240
    }
241
242
    /**
243
     * Sets whether nulls are serialized
244
     *
245
     * @param bool $serializeNull
246
     */
247 2
    public function setSerializeNull(bool $serializeNull): void
248
    {
249 2
        $this->serializeNull = $serializeNull;
250 2
    }
251
252
    /**
253
     * Specify data which should be serialized to JSON
254
     *
255
     * @return mixed
256
     */
257 17
    public function jsonSerialize()
258
    {
259 17
        if (null === $this->result) {
260 1
            return null;
261
        }
262
263 16
        return $this->result->jsonSerialize();
264
    }
265
266
    /**
267
     * Get the result as a json element
268
     *
269
     * @return JsonElement
270
     */
271 1
    public function toJsonElement(): JsonElement
272
    {
273 1
        return $this->result;
274
    }
275
276
    /**
277
     * Get the last index of the stack
278
     *
279
     * @return int
280
     */
281 20
    private function last(): int
282
    {
283 20
        return $this->stackSize - 1;
284
    }
285
286
    /**
287
     * Push a value to the result or current array/object
288
     *
289
     * @param JsonElement $value
290
     * @return JsonWritable
291
     * @throws \BadMethodCallException
292
     */
293 29
    private function push(JsonElement $value): JsonWritable
294
    {
295 29 View Code Duplication
        if (0 === $this->stackSize) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
296 29
            if (null !== $this->result) {
297 2
                throw new BadMethodCallException('Attempting to write two different types');
298
            }
299
300 29
            $this->result = $value;
301
302 29
            return $this;
303
        }
304
305 5 View Code Duplication
        if (null !== $this->pendingName) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
306 3
            $this->stack[$this->last()]->add($this->pendingName, $value);
307 3
            $this->pendingName = null;
308
        }
309
310 5
        if ($this->topIsArray()) {
311 2
            $this->stack[$this->last()]->addJsonElement($value);
312
        }
313
314 5
        return $this;
315
    }
316
317
    /**
318
     * Remove the last element of the stack
319
     */
320 7
    private function pop(): void
321
    {
322 7
        array_splice($this->stack, $this->last(), 1);
323 7
        $this->stackSize--;
324 7
    }
325
326
    /**
327
     * Returns true if an object is the top element of the stack and we haven't called name() yet
328
     *
329
     * @return bool
330
     */
331 30
    private function topIsObjectStart(): bool
332
    {
333 30
        if (0 === $this->stackSize) {
334 30
            return false;
335
        }
336
337 14
        return $this->stack[$this->last()] instanceof JsonObject && null === $this->pendingName;
338
    }
339
340
    /**
341
     * Returns true if an object is the top element of the stack
342
     *
343
     * @return bool
344
     */
345 7
    private function topIsObject()
346
    {
347 7
        if (0 === $this->stackSize) {
348 1
            return false;
349
        }
350
351 6
        return $this->stack[$this->last()] instanceof JsonObject;
352
    }
353
354
    /**
355
     * Returns true if an array is the top element of the stack
356
     *
357
     * @return bool
358
     */
359 8
    private function topIsArray()
360
    {
361 8
        if (0 === $this->stackSize) {
362 1
            return false;
363
        }
364
365 7
        return $this->stack[$this->last()] instanceof JsonArray;
366
    }
367
}
368