Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
49 / 49
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
20 / 20
CRAP
100.00% covered (success)
100.00%
1 / 1
Shape
100.00% covered (success)
100.00%
49 / 49
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
20 / 20
22
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
 defaultMessages
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
 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 Celema\Sire;
6
7use Celema\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    /**
98     * Every message key the shape's rules and types can produce, with its
99     * default template before any override, sorted by key.
100     *
101     * @return array<string, string>
102     */
103    public function defaultMessages(): array
104    {
105        return $this->config->defaultMessages();
106    }
107
108    public function types(Contract\CoercerRegistry $registry): self
109    {
110        $this->config->coercers($registry);
111
112        return $this;
113    }
114
115    public function ruleParser(Contract\RuleParser $parser): self
116    {
117        $this->config->ruleParser($parser);
118
119        return $this;
120    }
121
122    /** @param Closure(array<array-key, mixed>): array<array-key, mixed> $callback */
123    public function prepare(Closure $callback): self
124    {
125        $this->prepareCallbacks[] = $callback;
126
127        return $this;
128    }
129
130    public function add(
131        string $field,
132        string|Contract\Validator $type,
133    ): Field {
134        if ($field === '') {
135            throw new ValueError(
136                'Shape definition error: field must not be empty',
137            );
138        }
139
140        $definition = new Field($field, $type);
141        $this->fields[$field] = $definition;
142
143        return $definition;
144    }
145
146    /** @param Closure(Review): void $callback */
147    public function review(Closure $callback): self
148    {
149        $this->reviewCallbacks[] = $callback;
150
151        return $this;
152    }
153
154    #[Override]
155    public function validate(array $data): Result
156    {
157        return new ValidationRun(
158            $this->definition(),
159            $data,
160        )->validate();
161    }
162
163    /**
164     * @return array<array-key, mixed>
165     * @throws ValidationError
166     */
167    #[Override]
168    public function parse(array $data): array
169    {
170        $result = $this->validate($data);
171
172        if (!$result->valid()) {
173            throw new ValidationError($result);
174        }
175
176        return $result->values();
177    }
178
179    private function definition(): ShapeDefinition
180    {
181        return $this->config->definition(
182            $this->fields,
183            $this->prepareCallbacks,
184            $this->reviewCallbacks,
185        );
186    }
187}

Paths

Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once. Please also be aware that some paths may include implicit rather than explicit branches, 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
131        string $field,
132        string|Contract\Validator $type,
133    ): Field {
134        if ($field === '') {
 
135            throw new ValueError(
136                'Shape definition error: field must not be empty',
131        string $field,
132        string|Contract\Validator $type,
133    ): Field {
134        if ($field === '') {
 
140        $definition = new Field($field, $type);
141        $this->fields[$field] = $definition;
142
143        return $definition;
144    }
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->defaultMessages
105        return $this->config->defaultMessages();
106    }
Shape->definition
181        return $this->config->definition(
182            $this->fields,
183            $this->prepareCallbacks,
184            $this->reviewCallbacks,
185        );
186    }
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
168    public function parse(array $data): array
169    {
170        $result = $this->validate($data);
171
172        if (!$result->valid()) {
 
173            throw new ValidationError($result);
168    public function parse(array $data): array
169    {
170        $result = $this->validate($data);
171
172        if (!$result->valid()) {
 
176        return $result->values();
177    }
Shape->prepare
123    public function prepare(Closure $callback): self
124    {
125        $this->prepareCallbacks[] = $callback;
126
127        return $this;
128    }
Shape->review
147    public function review(Closure $callback): self
148    {
149        $this->reviewCallbacks[] = $callback;
150
151        return $this;
152    }
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
115    public function ruleParser(Contract\RuleParser $parser): self
116    {
117        $this->config->ruleParser($parser);
118
119        return $this;
120    }
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
108    public function types(Contract\CoercerRegistry $registry): self
109    {
110        $this->config->coercers($registry);
111
112        return $this;
113    }
Shape->validate
155    public function validate(array $data): Result
156    {
157        return new ValidationRun(
158            $this->definition(),
159            $data,
160        )->validate();
161    }