Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
19 / 19
CRAP
100.00% covered (success)
100.00%
1 / 1
Shape
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
19 / 19
21
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 list
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 asList
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 extra
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 strict
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 coerce
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 rule
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 rules
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 type
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 message
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 messages
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 types
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 ruleParser
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 prepare
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 add
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 review
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 validate
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 parse
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 definition
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Sire;
6
7use Celemas\Sire\Exception\ValidationError;
8use Closure;
9use Override;
10use ValueError;
11
12/** @api */
13final class Shape implements Contract\Shape
14{
15    private Config $config;
16    /** @var array<string, Field> */
17    private array $fields = [];
18    /** @var list<Closure(array<array-key, mixed>): array<array-key, mixed>> */
19    private array $prepareCallbacks = [];
20    /** @var list<Closure(Review): void> */
21    private array $reviewCallbacks = [];
22
23    public function __construct()
24    {
25        $this->config = new Config();
26    }
27
28    public static function list(): self
29    {
30        return new self()->asList();
31    }
32
33    public function asList(bool $list = true): self
34    {
35        $this->config->asList($list);
36
37        return $this;
38    }
39
40    public function extra(Extra|string $extra): self
41    {
42        $this->config->extra($extra);
43
44        return $this;
45    }
46
47    public function strict(): self
48    {
49        $this->config->coercionMode(CoercionMode::Strict);
50
51        return $this;
52    }
53
54    public function coerce(): self
55    {
56        $this->config->coercionMode(CoercionMode::Coerce);
57
58        return $this;
59    }
60
61    public function rule(string $name, Contract\Rule $rule): self
62    {
63        $this->config->rule($name, $rule);
64
65        return $this;
66    }
67
68    public function rules(Contract\RuleRegistry $registry): self
69    {
70        $this->config->rules($registry);
71
72        return $this;
73    }
74
75    public function type(string $name, Contract\Coercer $coercer): self
76    {
77        $this->config->coercer($name, $coercer);
78
79        return $this;
80    }
81
82    public function message(string $key, string $message): self
83    {
84        $this->config->message($key, $message);
85
86        return $this;
87    }
88
89    /** @param array<string, string> $messages */
90    public function messages(array $messages): self
91    {
92        $this->config->messages($messages);
93
94        return $this;
95    }
96
97    public function types(Contract\CoercerRegistry $registry): self
98    {
99        $this->config->coercers($registry);
100
101        return $this;
102    }
103
104    public function ruleParser(Contract\RuleParser $parser): self
105    {
106        $this->config->ruleParser($parser);
107
108        return $this;
109    }
110
111    /** @param Closure(array<array-key, mixed>): array<array-key, mixed> $callback */
112    public function prepare(Closure $callback): self
113    {
114        $this->prepareCallbacks[] = $callback;
115
116        return $this;
117    }
118
119    public function add(
120        string $field,
121        string|Contract\Validator $type,
122    ): Field {
123        if (!$field) {
124            throw new ValueError(
125                'Shape definition error: field must not be empty',
126            );
127        }
128
129        $definition = new Field($field, $type);
130        $this->fields[$field] = $definition;
131
132        return $definition;
133    }
134
135    /** @param Closure(Review): void $callback */
136    public function review(Closure $callback): self
137    {
138        $this->reviewCallbacks[] = $callback;
139
140        return $this;
141    }
142
143    #[Override]
144    public function validate(array $data): Result
145    {
146        return new ValidationRun(
147            $this->definition(),
148            $data,
149        )->validate();
150    }
151
152    /**
153     * @return array<array-key, mixed>
154     * @throws ValidationError
155     */
156    #[Override]
157    public function parse(array $data): array
158    {
159        $result = $this->validate($data);
160
161        if (!$result->valid()) {
162            throw new ValidationError($result);
163        }
164
165        return $result->values();
166    }
167
168    private function definition(): ShapeDefinition
169    {
170        return $this->config->definition(
171            $this->fields,
172            $this->prepareCallbacks,
173            $this->reviewCallbacks,
174        );
175    }
176}

Branches

Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once. Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

Shape->__construct
25        $this->config = new Config();
26    }
Shape->add
120        string $field,
121        string|Contract\Validator $type,
122    ): Field {
123        if (!$field) {
124            throw new ValueError(
125                'Shape definition error: field must not be empty',
129        $definition = new Field($field, $type);
130        $this->fields[$field] = $definition;
131
132        return $definition;
133    }
Shape->asList
33    public function asList(bool $list = true): self
34    {
35        $this->config->asList($list);
36
37        return $this;
38    }
Shape->coerce
56        $this->config->coercionMode(CoercionMode::Coerce);
57
58        return $this;
59    }
Shape->definition
170        return $this->config->definition(
171            $this->fields,
172            $this->prepareCallbacks,
173            $this->reviewCallbacks,
174        );
175    }
Shape->extra
40    public function extra(Extra|string $extra): self
41    {
42        $this->config->extra($extra);
43
44        return $this;
45    }
Shape->list
30        return new self()->asList();
31    }
Shape->message
82    public function message(string $key, string $message): self
83    {
84        $this->config->message($key, $message);
85
86        return $this;
87    }
Shape->messages
90    public function messages(array $messages): self
91    {
92        $this->config->messages($messages);
93
94        return $this;
95    }
Shape->parse
157    public function parse(array $data): array
158    {
159        $result = $this->validate($data);
160
161        if (!$result->valid()) {
162            throw new ValidationError($result);
165        return $result->values();
166    }
Shape->prepare
112    public function prepare(Closure $callback): self
113    {
114        $this->prepareCallbacks[] = $callback;
115
116        return $this;
117    }
Shape->review
136    public function review(Closure $callback): self
137    {
138        $this->reviewCallbacks[] = $callback;
139
140        return $this;
141    }
Shape->rule
61    public function rule(string $name, Contract\Rule $rule): self
62    {
63        $this->config->rule($name, $rule);
64
65        return $this;
66    }
Shape->ruleParser
104    public function ruleParser(Contract\RuleParser $parser): self
105    {
106        $this->config->ruleParser($parser);
107
108        return $this;
109    }
Shape->rules
68    public function rules(Contract\RuleRegistry $registry): self
69    {
70        $this->config->rules($registry);
71
72        return $this;
73    }
Shape->strict
49        $this->config->coercionMode(CoercionMode::Strict);
50
51        return $this;
52    }
Shape->type
75    public function type(string $name, Contract\Coercer $coercer): self
76    {
77        $this->config->coercer($name, $coercer);
78
79        return $this;
80    }
Shape->types
97    public function types(Contract\CoercerRegistry $registry): self
98    {
99        $this->config->coercers($registry);
100
101        return $this;
102    }
Shape->validate
144    public function validate(array $data): Result
145    {
146        return new ValidationRun(
147            $this->definition(),
148            $data,
149        )->validate();
150    }