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

JsonEncodeWriter::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 stdClass;
11
use Tebru\Gson\JsonWritable;
12
13
/**
14
 * Class JsonEncodeWriter
15
 *
16
 * @author Nate Brunette <[email protected]>
17
 */
18
final class JsonEncodeWriter implements JsonWritable
19
{
20
    /**
21
     * True if we should serialize nulls
22
     *
23
     * @var bool
24
     */
25
    private $serializeNull = false;
26
27
    /**
28
     * Stack of values to be written
29
     *
30
     * @var array
31
     */
32
    private $stack = [];
33
34
    /**
35
     * Size of the stack array
36
     *
37
     * @var int
38
     */
39
    private $stackSize = 0;
40
41
    /**
42
     * When serializing an object, store the name that should be serialized
43
     *
44
     * @var
45
     */
46
    private $pendingName;
47
48
    /**
49
     * The final result that will be json encoded
50
     *
51
     * @var mixed
52
     */
53
    private $result;
54
55
    /**
56
     * Begin writing array
57
     *
58
     * @return JsonWritable
59
     * @throws \BadMethodCallException
60
     */
61 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...
62
    {
63 6
        if ($this->topIsObjectStart()) {
64 1
            throw new BadMethodCallException('Cannot call beginArray() before name() during object serialization');
65
        }
66
67 5
        $array = [];
68 5
        $this->push($array);
69 5
        $this->stack[] = &$array;
70 5
        $this->stackSize++;
71
72 5
        return $this;
73
    }
74
75
    /**
76
     * End writing array
77
     *
78
     * @return JsonWritable
79
     * @throws \BadMethodCallException
80
     */
81 4
    public function endArray(): JsonWritable
82
    {
83 4
        if (!$this->topIsArray()) {
84 2
            throw new BadMethodCallException('Cannot call endArray() if not serializing array');
85
        }
86
87 2
        $this->pop();
88
89 2
        return $this;
90
    }
91
92
    /**
93
     * Begin writing object
94
     *
95
     * @return JsonWritable
96
     * @throws \BadMethodCallException
97
     */
98 16 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...
99
    {
100 16
        if ($this->topIsObjectStart()) {
101 1
            throw new BadMethodCallException('Cannot call beginObject() before name() during object serialization');
102
        }
103
104 16
        $class = new stdClass();
105 16
        $this->push($class);
106 16
        $this->stack[] = $class;
107 16
        $this->stackSize++;
108
109 16
        return $this;
110
    }
111
112
    /**
113
     * End writing object
114
     *
115
     * @return JsonWritable
116
     * @throws \BadMethodCallException
117
     */
118 6
    public function endObject(): JsonWritable
119
    {
120 6
        if (!$this->topIsObject()) {
121 2
            throw new BadMethodCallException('Cannot call endObject() if not serializing object');
122
        }
123
124 4
        $this->pop();
125
126 4
        return $this;
127
    }
128
129
    /**
130
     * Writes a property name
131
     *
132
     * @param string $name
133
     * @return JsonWritable
134
     * @throws \BadMethodCallException
135
     */
136 5
    public function name(string $name): JsonWritable
137
    {
138 5
        if (!$this->topIsObjectStart()) {
139 1
            throw new BadMethodCallException('Cannot call name() at this point.  Either name() has already been called or object serialization has not been started');
140
        }
141
142 5
        $this->pendingName = $name;
143
144 5
        return $this;
145
    }
146
147
    /**
148
     * Write an integer value
149
     *
150
     * @param int $value
151
     * @return JsonWritable
152
     * @throws \BadMethodCallException
153
     */
154 4
    public function writeInteger(int $value): JsonWritable
155
    {
156 4
        if ($this->topIsObjectStart()) {
157 1
            throw new BadMethodCallException('Cannot call writeInteger() before name() during object serialization');
158
        }
159
160 3
        return $this->push($value);
161
    }
162
163
    /**
164
     * Write a float value
165
     *
166
     * @param float $value
167
     * @return JsonWritable
168
     * @throws \BadMethodCallException
169
     */
170 3
    public function writeFloat(float $value): JsonWritable
171
    {
172 3
        if ($this->topIsObjectStart()) {
173 1
            throw new BadMethodCallException('Cannot call writeFloat() before name() during object serialization');
174
        }
175
176 2
        return $this->push($value);
177
    }
178
179
    /**
180
     * Write a string value
181
     *
182
     * @param string $value
183
     * @return JsonWritable
184
     * @throws \BadMethodCallException
185
     */
186 4
    public function writeString(string $value): JsonWritable
187
    {
188 4
        if ($this->topIsObjectStart()) {
189 1
            throw new BadMethodCallException('Cannot call writeString() before name() during object serialization');
190
        }
191
192 3
        return $this->push($value);
193
    }
194
195
    /**
196
     * Write a boolean value
197
     *
198
     * @param boolean $value
199
     * @return JsonWritable
200
     * @throws \BadMethodCallException
201
     */
202 3
    public function writeBoolean(bool $value): JsonWritable
203
    {
204 3
        if ($this->topIsObjectStart()) {
205 1
            throw new BadMethodCallException('Cannot call writeBoolean() before name() during object serialization');
206
        }
207
208 2
        return $this->push($value);
209
    }
210
211
    /**
212
     * Write a null value if we are serializing nulls, otherwise
213
     * skip the value.  If this is a property value, that property
214
     * should be skippped as well.
215
     *
216
     * @return JsonWritable
217
     * @throws \BadMethodCallException
218
     */
219 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...
220
    {
221 5
        if ($this->topIsObjectStart()) {
222 1
            throw new BadMethodCallException('Cannot call writeNull() before name() during object serialization');
223
        }
224
225 4
        if ($this->serializeNull) {
226 2
            $null = null;
227 2
            return $this->push($null);
228
        }
229
230
        // if we're not serializing nulls
231 2
        if (null !== $this->pendingName) {
232 1
            $this->pendingName = null;
233
        }
234
235 2
        return $this;
236
    }
237
238
    /**
239
     * Sets whether nulls are serialized
240
     *
241
     * @param bool $serializeNull
242
     */
243 2
    public function setSerializeNull(bool $serializeNull): void
244
    {
245 2
        $this->serializeNull = $serializeNull;
246 2
    }
247
248
    /**
249
     * Convert the writer to json
250
     *
251
     * @return string
252
     */
253 17
    public function __toString(): string
254
    {
255 17
        return json_encode($this->result);
256
    }
257
258
    /**
259
     * Get the last index of the stack
260
     *
261
     * @return int
262
     */
263 19
    private function last(): int
264
    {
265 19
        return $this->stackSize - 1;
266
    }
267
268
    /**
269
     * Push a value to the result or current array/object
270
     *
271
     * @param mixed $value
272
     * @return JsonWritable
273
     * @throws \BadMethodCallException
274
     */
275 28
    private function push(&$value): JsonWritable
276
    {
277 28 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...
278 28
            if (null !== $this->result) {
279 2
                throw new BadMethodCallException('Attempting to write two different types');
280
            }
281
282 28
            $this->result = &$value;
283
284 28
            return $this;
285
        }
286
287 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...
288 3
            $this->stack[$this->last()]->{$this->pendingName} = &$value;
289 3
            $this->pendingName = null;
290
        }
291
292 5
        if ($this->topIsArray()) {
293 2
            $this->stack[$this->last()][] = &$value;
294
        }
295
296 5
        return $this;
297
    }
298
299
    /**
300
     * Remove the last element of the stack
301
     */
302 6
    private function pop(): void
303
    {
304 6
        array_splice($this->stack, $this->last(), 1);
305 6
        $this->stackSize--;
306 6
    }
307
308
    /**
309
     * Returns true if an object is the top element of the stack and we haven't called name() yet
310
     *
311
     * @return bool
312
     */
313 29 View Code Duplication
    private function topIsObjectStart(): bool
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...
314
    {
315 29
        if (0 === $this->stackSize) {
316 29
            return false;
317
        }
318
319 14
        return $this->stack[$this->last()] instanceof stdClass && null === $this->pendingName;
320
    }
321
322
    /**
323
     * Returns true if an object is the top element of the stack
324
     *
325
     * @return bool
326
     */
327 6 View Code Duplication
    private function topIsObject()
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...
328
    {
329 6
        if (0 === $this->stackSize) {
330 1
            return false;
331
        }
332
333 5
        return $this->stack[$this->last()] instanceof stdClass;
334
    }
335
336
    /**
337
     * Returns true if an array is the top element of the stack
338
     *
339
     * @return bool
340
     */
341 8
    private function topIsArray()
342
    {
343 8
        if (0 === $this->stackSize) {
344 1
            return false;
345
        }
346
347 7
        return is_array($this->stack[$this->last()]);
348
    }
349
}
350