Passed
Push — master ( 95373b...dd07b4 )
by Nate
43s
created

JsonReader::getPath()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 4
nop 0
dl 0
loc 19
ccs 10
cts 10
cp 1
crap 4
rs 9.9666
c 0
b 0
f 0
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 Tebru\Gson\Exception\JsonSyntaxException;
12
use Tebru\Gson\JsonReadable;
13
use Tebru\Gson\ReaderContext;
14
use Tebru\Gson\JsonToken;
15
16
/**
17
 * Class JsonReader
18
 *
19
 * @author Nate Brunette <[email protected]>
20
 */
21
abstract class JsonReader implements JsonReadable
22
{
23
    use JsonPath;
24
25
    /**
26
     * A stack representing the next element to be consumed
27
     *
28
     * @var array
29
     */
30
    protected $stack = [null];
31
32
    /**
33
     * An array of types that map to the position in the stack
34
     *
35
     * @var array
36
     */
37
    protected $stackTypes = [JsonToken::END_DOCUMENT];
38
39
    /**
40
     * The current size of the stack
41
     *
42
     * @var int
43
     */
44
    protected $stackSize = 1;
45
46
    /**
47
     * The original payload
48
     *
49
     * @var mixed
50
     */
51
    protected $payload;
52
53
    /**
54
     * Runtime context to be used while reading
55
     *
56
     * @var ReaderContext
57
     */
58
    protected $context;
59
60
    /**
61
     * Consumes the next token and asserts it's the end of an array
62
     *
63
     * @return void
64
     */
65 13
    public function endArray(): void
66
    {
67 13
        if ($this->stackTypes[$this->stackSize - 1] !== JsonToken::END_ARRAY) {
68 2
            $this->pathIndices[$this->pathIndex]++;
69 2
            $this->assertionFailed(JsonToken::END_ARRAY);
70
        }
71
72 11
        $this->stackSize--;
73 11
        $this->pathIndex--;
74 11
    }
75
76
    /**
77
     * Consumes the next token and asserts it's the end of an object
78
     *
79
     * @return void
80
     */
81 15
    public function endObject(): void
82
    {
83 15
        if ($this->stackTypes[$this->stackSize - 1] !== JsonToken::END_OBJECT) {
84 2
            $this->assertionFailed(JsonToken::END_OBJECT);
85
        }
86
87 13
        $this->stackSize--;
88 13
        $this->pathNames[$this->pathIndex--] = null;
89 13
    }
90
91
    /**
92
     * Returns true if the array or object has another element
93
     *
94
     * If the current scope is not an array or object, this returns false
95
     *
96
     * @return bool
97
     */
98 14
    public function hasNext(): bool
99
    {
100 14
        $peek = $this->stackTypes[$this->stackSize - 1];
101
102 14
        return $peek !== JsonToken::END_OBJECT && $peek !== JsonToken::END_ARRAY;
103
    }
104
105
    /**
106
     * Consumes the next name and returns it
107
     *
108
     * @return string
109
     */
110 31
    public function nextName(): string
111
    {
112 31
        if ($this->stackTypes[$this->stackSize - 1] !== JsonToken::NAME) {
113 2
            $this->assertionFailed(JsonToken::NAME);
114
        }
115
116 31
        $name = (string)$this->stack[--$this->stackSize];
117
118 31
        $this->pathNames[$this->pathIndex] = $name;
119
120 31
        return $name;
121
    }
122
123
    /**
124
     * Consumes the value of the next token and asserts it's null
125
     *
126
     * @return void
127
     */
128 4
    public function nextNull(): void
129
    {
130 4
        $this->pathIndices[$this->pathIndex]++;
131
132 4
        if ($this->stackTypes[$this->stackSize - 1] !== JsonToken::NULL) {
133 2
            $this->assertionFailed(JsonToken::NULL);
134
        }
135
136 2
        $this->stackSize--;
137 2
    }
138
139
    /**
140
     * Skip the next value.  If the next value is an object or array, all children will
141
     * also be skipped.
142
     *
143
     * @return void
144
     */
145 7
    public function skipValue(): void
146
    {
147 7
        $this->stackSize--;
148
149 7
        switch ($this->stackTypes[$this->stackSize]) {
150 7
            case JsonToken::BEGIN_OBJECT:
151 5
            case JsonToken::BEGIN_ARRAY:
152 3
                $this->stackSize--;
153 3
                break;
154
        }
155
156 7
        $this->pathIndices[$this->pathIndex]--;
157 7
    }
158
159
    /**
160
     * Returns the type of the next token without consuming it
161
     *
162
     * @return string
163
     */
164 64
    public function peek(): string
165
    {
166 64
        return $this->stackTypes[$this->stackSize - 1];
167
    }
168
169
    /**
170
     * Returns the original json after json_decode
171
     *
172
     * @return mixed
173
     */
174 2
    public function getPayload()
175
    {
176 2
        return $this->payload;
177
    }
178
179
    /**
180
     * Get context to be used during deserialization
181
     *
182
     * @return ReaderContext
183
     */
184 5
    public function getContext(): ReaderContext
185
    {
186 5
        return $this->context;
187
    }
188
189
    /**
190
     * Check that the next token equals the expectation
191
     *
192
     * @param string $expectedToken
193
     * @return void
194
     * @throws \Tebru\Gson\Exception\JsonSyntaxException If the next token is not the expectation
195
     */
196 20
    protected function assertionFailed(string $expectedToken): void
197
    {
198 20
        throw new JsonSyntaxException(
199 20
            \sprintf(
200 20
                'Expected "%s", but found "%s" at "%s"',
201 20
                $expectedToken,
202 20
                $this->stackTypes[$this->stackSize - 1],
203 20
                $this->getPath()
204
            )
205
        );
206
    }
207
}
208