Tree::traverseArray()   A
last analyzed

Complexity

Conditions 5
Paths 16

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 9
c 1
b 0
f 0
nc 16
nop 0
dl 0
loc 15
ccs 10
cts 10
cp 1
crap 5
rs 9.6111
1
<?php
2
3
namespace Cerbero\JsonParser\ValueObjects;
4
5
use Cerbero\JsonParser\Pointers\Pointers;
6
use Cerbero\JsonParser\Tokens\Token;
7
8
use function count;
9
10
/**
11
 * The JSON tree.
12
 *
13
 */
14
final class Tree
15
{
16
    /**
17
     * The original JSON tree.
18
     *
19
     * @var array<int, string|int>
20
     */
21
    private array $original = [];
22
23
    /**
24
     * The wildcarded JSON tree.
25
     *
26
     * @var array<int, string|int>
27
     */
28
    private array $wildcarded = [];
29
30
    /**
31
     * Whether a depth is within an object.
32
     *
33
     * @var array<int, bool>
34
     */
35
    private array $inObjectByDepth = [];
36
37
    /**
38
     * The JSON tree depth.
39
     *
40
     * @var int
41
     */
42
    private int $depth = -1;
43
44
    /**
45
     * Instantiate the class.
46
     *
47
     * @param Pointers $pointers
48
     */
49 361
    public function __construct(private readonly Pointers $pointers)
50
    {
51 361
    }
52
53
    /**
54
     * Retrieve the original JSON tree
55
     *
56
     * @return array<int, string|int>
57
     */
58 269
    public function original(): array
59
    {
60 269
        return $this->original;
61
    }
62
63
    /**
64
     * Retrieve the wildcarded JSON tree
65
     *
66
     * @return array<int, string|int>
67
     */
68 248
    public function wildcarded(): array
69
    {
70 248
        return $this->wildcarded;
71
    }
72
73
    /**
74
     * Determine whether the current depth is within an object
75
     *
76
     * @return bool
77
     */
78 357
    public function inObject(): bool
79
    {
80 357
        return $this->inObjectByDepth[$this->depth] ?? false;
81
    }
82
83
    /**
84
     * Retrieve the JSON tree depth
85
     *
86
     * @return int
87
     */
88 34
    public function depth(): int
89
    {
90 34
        return $this->depth;
91
    }
92
93
    /**
94
     * Increase the tree depth by entering an object or an array
95
     *
96
     * @param bool $inObject
97
     * @return void
98
     */
99 357
    public function deepen(bool $inObject): void
100
    {
101 357
        $this->depth++;
102 357
        $this->inObjectByDepth[$this->depth] = $inObject;
103
    }
104
105
    /**
106
     * Decrease the tree depth
107
     *
108
     * @return void
109
     */
110 266
    public function emerge(): void
111
    {
112 266
        $this->depth--;
113
    }
114
115
    /**
116
     * Determine whether the tree is deep
117
     *
118
     * @return bool
119
     */
120 355
    public function isDeep(): bool
121
    {
122 355
        $pointer = $this->pointers->matching();
123
124 355
        return $pointer == '' ? $this->depth > 0 : $this->depth >= $pointer->depth;
0 ignored issues
show
introduced by
The condition $pointer == '' is always false.
Loading history...
125
    }
126
127
    /**
128
     * Traverse the given token
129
     *
130
     * @param Token $token
131
     * @param bool $expectsKey
132
     * @return void
133
     */
134 357
    public function traverseToken(Token $token, bool $expectsKey): void
135
    {
136 357
        $pointer = $this->pointers->matching();
137
138 357
        if ($pointer != '' && $this->depth >= $pointer->depth) {
139 123
            return;
140 357
        } elseif ($expectsKey) {
141 263
            $this->traverseKey($token);
142 357
        } elseif ($token->isValue() && !$this->inObject()) {
143 357
            $this->traverseArray();
144
        }
145
    }
146
147
    /**
148
     * Determine whether the tree is matched by the JSON pointer
149
     *
150
     * @return bool
151
     */
152 357
    public function isMatched(): bool
153
    {
154 357
        return $this->depth >= 0 && $this->pointers->matching()->matchesTree($this);
155
    }
156
157
    /**
158
     * Traverse the given object key
159
     *
160
     * @param string $key
161
     * @return void
162
     */
163 263
    public function traverseKey(string $key): void
164
    {
165 263
        $trimmedKey = substr($key, 1, -1);
166
167 263
        $this->original[$this->depth] = $trimmedKey;
168 263
        $this->wildcarded[$this->depth] = $trimmedKey;
169
170 263
        if (count($this->original) > $offset = $this->depth + 1) {
171 78
            array_splice($this->original, $offset);
172 78
            array_splice($this->wildcarded, $offset);
173 78
            array_splice($this->inObjectByDepth, $offset);
174
        }
175
176 263
        $this->pointers->matchTree($this);
177
    }
178
179
    /**
180
     * Traverse an array
181
     *
182
     * @return void
183
     */
184 357
    public function traverseArray(): void
185
    {
186 357
        $index = $this->original[$this->depth] ?? null;
187 357
        $this->original[$this->depth] = $index = is_int($index) ? $index + 1 : 0;
188
189 357
        if (count($this->original) > $offset = $this->depth + 1) {
190 357
            array_splice($this->original, $offset);
191 357
            array_splice($this->inObjectByDepth, $offset);
192
        }
193
194 357
        $referenceTokens = $this->pointers->matchTree($this)->referenceTokens;
195 357
        $this->wildcarded[$this->depth] = ($referenceTokens[$this->depth] ?? null) == '-' ? '-' : $index;
196
197 357
        if (count($this->wildcarded) > $offset) {
198 357
            array_splice($this->wildcarded, $offset);
199
        }
200
    }
201
202
    /**
203
     * Retrieve the current key
204
     *
205
     * @return string|int
206
     */
207 265
    public function currentKey(): string|int
208
    {
209 265
        $key = $this->original[$this->depth];
210
211 265
        return is_string($key) ? "\"$key\"" : $key;
212
    }
213
}
214