Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
77.42% covered (warning)
77.42%
24 / 31
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Parser
77.42% covered (warning)
77.42%
24 / 31
50.00% covered (danger)
50.00%
3 / 6
24.61
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 defineField
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 _get
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
2.02
 parseField
72.73% covered (warning)
72.73%
8 / 11
0.00% covered (danger)
0.00%
0 / 1
10.64
 evalAll
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
3.47
1<?php declare(strict_types=1);
2
3namespace Computator\FrameworkUtils\InputParser;
4
5use Exception;
6use function array_key_exists, is_int, is_string;
7
8class Parser {
9    protected array $valid_fields = [];
10
11    public function __construct(
12        public readonly array $input,
13        array $fields = [],
14        protected ParserConfig $parse_opts = new ParserConfig(),
15        ParserConfig ...$fields2,
16    ) {
17        foreach ([...$fields, ...$fields2] as $field => $opts) {
18            if (is_int($field) && is_string($opts)) {
19                $this->defineField($opts);
20            } else {
21                $this->defineField($field, $opts);
22            }
23        }
24    }
25
26    public function defineField(string $field, ?Field\Base $field_def = null): void {
27        $this->valid_fields[$field] = $field_def ?? new $this->parse_opts->default_field_type;
28    }
29
30    public function get(string $field): mixed {
31        return $this->_get($field);
32    }
33
34    protected function _get(string $field): mixed {
35        if (!array_key_exists($field, $this->valid_fields))
36            throw new \OutOfRangeException("field '{$field}' is not defined");
37        // TODO: cache result
38        // TODO: store original?
39        return $this->parseField(
40            $this->input[$field] ?? null,
41            $this->valid_fields[$field],
42        );
43    }
44
45    protected function parseField(mixed $value, Field\Base $field): mixed {
46        // basic checks
47        if ($value === null)
48            return null;
49        if (is_string($value)) {
50            if ($this->parse_opts->unset_empty && $value === '')
51                return null;
52        }
53
54        // processing
55        foreach ($this->parse_opts->filters as $filt)
56            $value = $filt($value);
57
58        // validation
59        if (is_string($value)) {
60            if ($this->parse_opts->invalid_empty && $value === '')
61                throw new \ValueError("invalid field: empty after filtering");
62        }
63
64        return $field->parse($value);
65    }
66
67    public function evalAll(): array {
68        $out = [];
69        $errs = [];
70        foreach (array_keys($this->valid_fields) as $f) {
71            try {
72                $out[$f] = $this->get($f);
73            }
74            catch (Exception $e) {
75                $out[$f] = null;
76                $errs[$f] = $e;
77            }
78        }
79        return [$out, $errs];
80    }
81}