Passed
Branch feature/first-release (4f172a)
by Andrea Marco
01:55
created

JsonParser::onDecodingError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Cerbero\JsonParser;
4
5
use Cerbero\JsonParser\Decoders\DecodedValue;
6
use Cerbero\JsonParser\Decoders\Decoder;
7
use Cerbero\JsonParser\Exceptions\SyntaxException;
8
use Cerbero\JsonParser\Pointers\Pointer;
9
use Cerbero\JsonParser\Sources\AnySource;
10
use Cerbero\JsonParser\Tokens\Lexer;
11
use Cerbero\JsonParser\Tokens\Parser;
12
use Cerbero\JsonParser\ValueObjects\Config;
13
use Cerbero\JsonParser\ValueObjects\Progress;
14
use Closure;
15
use IteratorAggregate;
16
use Traversable;
17
18
/**
19
 * The JSON parser entry-point.
20
 *
21
 * @implements IteratorAggregate<string|int, mixed>
22
 */
23
final class JsonParser implements IteratorAggregate
24
{
25
    /**
26
     * The configuration.
27
     *
28
     * @var Config
29
     */
30
    private Config $config;
31
32
    /**
33
     * The lexer.
34
     *
35
     * @var Lexer
36
     */
37
    private Lexer $lexer;
38
39
    /**
40
     * The parser.
41
     *
42
     * @var Parser
43
     */
44
    private Parser $parser;
45
46
    /**
47
     * Instantiate the class.
48
     *
49
     * @param mixed $source
50
     */
51 342
    public function __construct(mixed $source)
52
    {
53 342
        $this->config = new Config();
54 342
        $this->lexer = new Lexer(new AnySource($source, $this->config));
55 342
        $this->parser = new Parser($this->lexer->getIterator(), $this->config);
56
    }
57
58
    /**
59
     * Statically instantiate the class
60
     *
61
     * @param mixed $source
62
     * @return self
63
     */
64 330
    public static function parse(mixed $source): self
65
    {
66 330
        return new self($source);
67
    }
68
69
    /**
70
     * Retrieve the lazily iterable JSON
71
     *
72
     * @return Traversable<string|int, mixed>
73
     */
74 140
    public function getIterator(): Traversable
75
    {
76
        try {
77 140
            yield from $this->parser;
78 15
        } catch (SyntaxException $e) {
0 ignored issues
show
Unused Code introduced by
catch (\Cerbero\JsonPars...ons\SyntaxException $e) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
79 11
            $e->setPosition($this->lexer->position());
80 11
            ($this->config->onSyntaxError)($e);
81
        }
82
    }
83
84
    /**
85
     * Set the JSON pointers
86
     *
87
     * @param string[]|array<string, Closure> $pointers
88
     * @return self
89
     */
90 67
    public function pointers(array $pointers): self
91
    {
92 67
        foreach ($pointers as $pointer => $callback) {
93 67
            $callback instanceof Closure ? $this->pointer($pointer, $callback) : $this->pointer($callback);
94
        }
95
96 59
        return $this;
97
    }
98
99
    /**
100
     * Set a JSON pointer
101
     *
102
     * @param string $pointer
103
     * @param Closure|null $callback
104
     * @return self
105
     */
106 199
    public function pointer(string $pointer, Closure $callback = null): self
107
    {
108 199
        $this->config->pointers->add(new Pointer($pointer, false, $callback));
109
110 195
        return $this;
111
    }
112
113
    /**
114
     * Set the lazy JSON pointers
115
     *
116
     * @param string[]|array<string, Closure> $pointers
117
     * @return self
118
     */
119 32
    public function lazyPointers(array $pointers): self
120
    {
121 32
        foreach ($pointers as $pointer => $callback) {
122 32
            $callback instanceof Closure ? $this->lazyPointer($pointer, $callback) : $this->lazyPointer($callback);
123
        }
124
125 32
        return $this;
126
    }
127
128
    /**
129
     * Set a lazy JSON pointer
130
     *
131
     * @param string $pointer
132
     * @param Closure|null $callback
133
     * @return self
134
     */
135 101
    public function lazyPointer(string $pointer, Closure $callback = null): self
136
    {
137 101
        $this->config->pointers->add(new Pointer($pointer, true, $callback));
138
139 101
        return $this;
140
    }
141
142
    /**
143
     * Traverse the lazily iterable JSON
144
     *
145
     * @param Closure|null $callback
146
     * @return void
147
     */
148 16
    public function traverse(Closure $callback = null): void
149
    {
150 16
        foreach ($this as $key => $value) {
151 9
            $callback && $callback($value, $key, $this);
152
        }
153
    }
154
155
    /**
156
     * Eager load the JSON into an array
157
     *
158
     * @return array<string|int, mixed>
159
     */
160 190
    public function toArray(): array
161
    {
162 190
        return $this->parser->toArray();
163
    }
164
165
    /**
166
     * Set the JSON decoder
167
     *
168
     * @param Decoder $decoder
169
     * @return self
170
     */
171
    public function decoder(Decoder $decoder): self
172
    {
173
        $this->config->decoder = $decoder;
174
175
        return $this;
176
    }
177
178
    /**
179
     * Retrieve the parsing progress
180
     *
181
     * @return Progress
182
     */
183
    public function progress(): Progress
184
    {
185
        return $this->lexer->progress();
186
    }
187
188
    /**
189
     * The number of bytes to read in each chunk
190
     *
191
     * @param int<1, max> $bytes
192
     * @return self
193
     */
194
    public function bytes(int $bytes): self
195
    {
196
        $this->config->bytes = $bytes;
197
198
        return $this;
199
    }
200
201
    /**
202
     * Set the patch to apply during a decoding error
203
     *
204
     * @param mixed $patch
205
     * @return self
206
     */
207 4
    public function patchDecodingError(mixed $patch = null): self
208
    {
209 4
        return $this->onDecodingError(function (DecodedValue $decoded) use ($patch) {
210 4
            $decoded->value = is_callable($patch) ? $patch($decoded) : $patch;
211 4
        });
212
    }
213
214
    /**
215
     * Set the logic to run during a decoding error
216
     *
217
     * @param Closure $callback
218
     * @return self
219
     */
220 5
    public function onDecodingError(Closure $callback): self
221
    {
222 5
        $this->config->onDecodingError = $callback;
223
224 5
        return $this;
225
    }
226
227
    /**
228
     * Set the logic to run during a syntax error
229
     *
230
     * @param Closure $callback
231
     * @return self
232
     */
233 1
    public function onSyntaxError(Closure $callback): self
234
    {
235 1
        $this->config->onSyntaxError = $callback;
236
237 1
        return $this;
238
    }
239
}
240