Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
64 / 64
93.41% covered (success)
93.41%
85 / 91
53.25% covered (warning)
53.25%
41 / 77
88.89% covered (warning)
88.89%
24 / 27
CRAP
0.00% covered (danger)
0.00%
0 / 1
Field
100.00% covered (success)
100.00%
64 / 64
93.41% covered (success)
93.41%
85 / 91
53.25% covered (warning)
53.25%
41 / 77
100.00% covered (success)
100.00%
27 / 27
283.46
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
 rules
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
4 / 4
33.33% covered (danger)
33.33%
1 / 3
100.00% covered (success)
100.00%
1 / 1
3.19
 label
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
 finalize
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
 empty
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
7 / 7
25.00% covered (danger)
25.00%
1 / 4
100.00% covered (success)
100.00%
1 / 1
6.80
 default
100.00% covered (success)
100.00%
5 / 5
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
 nullable
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
 optional
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
 hasDefault
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
 defaultValue
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
 isNullable
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
 isOptional
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
 coercionMode
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
 treatsMissingAsEmpty
100.00% covered (success)
100.00%
1 / 1
75.00% covered (warning)
75.00%
3 / 4
50.00% covered (danger)
50.00%
1 / 2
100.00% covered (success)
100.00%
1 / 1
1.12
 isBlank
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
6 / 6
50.00% covered (danger)
50.00%
2 / 4
100.00% covered (success)
100.00%
1 / 1
4.12
 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%
3 / 3
100.00% covered (success)
100.00%
4 / 4
33.33% covered (danger)
33.33%
1 / 3
100.00% covered (success)
100.00%
1 / 1
3.19
 messageOverrides
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
 name
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
 type
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 applyPreparation
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
4 / 4
66.67% covered (warning)
66.67%
2 / 3
100.00% covered (success)
100.00%
1 / 1
2.15
 applyFinalization
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
4 / 4
66.67% covered (warning)
66.67%
2 / 3
100.00% covered (success)
100.00%
1 / 1
2.15
 matchesEmpty
100.00% covered (success)
100.00%
5 / 5
83.33% covered (warning)
83.33%
15 / 18
62.50% covered (warning)
62.50%
5 / 8
100.00% covered (success)
100.00%
1 / 1
9.58
 messageKey
100.00% covered (success)
100.00%
7 / 7
88.24% covered (warning)
88.24%
15 / 17
22.22% covered (danger)
22.22%
6 / 27
100.00% covered (success)
100.00%
1 / 1
22.94
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Sire;
6
7/** @api */
8final class Field
9{
10    private const int FLAG_HAS_DEFAULT = 1;
11    private const int FLAG_NULLABLE = 2;
12    private const int FLAG_OPTIONAL = 4;
13
14    private ?string $label = null;
15    /** @var list<callable> */
16    private array $preparers = [];
17    /** @var list<callable> */
18    private array $finalizers = [];
19    /** @var list<Blank> */
20    private array $empty = [Blank::Missing];
21    private int $flags = 0;
22    private mixed $default = null;
23    private ?CoercionMode $coercionMode = null;
24    /** @var array<string, string> */
25    private array $messages = [];
26    /** @var list<string> */
27    public private(set) array $rules = [];
28
29    public function __construct(
30        public readonly string $field,
31        public readonly string|Contract\Validator $type,
32    ) {}
33
34    public function rules(string ...$rules): static
35    {
36        foreach ($rules as $rule) {
37            $this->rules[] = $rule;
38        }
39
40        return $this;
41    }
42
43    public function label(string $label): static
44    {
45        $this->label = $label;
46
47        return $this;
48    }
49
50    /** @param callable $callback */
51    public function prepare(callable $callback): static
52    {
53        $this->preparers[] = $callback;
54
55        return $this;
56    }
57
58    /** @param callable(mixed, array<string, mixed>): mixed $callback */
59    public function finalize(callable $callback): static
60    {
61        $this->finalizers[] = $callback;
62
63        return $this;
64    }
65
66    public function empty(Blank|string ...$empty): static
67    {
68        $this->empty = [];
69
70        foreach ($empty as $value) {
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
72        }
73
74        return $this;
75    }
76
77    public function default(mixed $value): static
78    {
79        $this->default = $value;
80        $this->flags |= self::FLAG_HAS_DEFAULT;
81
82        if ($value === null) {
83            $this->nullable();
84        }
85
86        return $this;
87    }
88
89    public function nullable(): static
90    {
91        $this->flags |= self::FLAG_NULLABLE;
92
93        return $this;
94    }
95
96    public function optional(): static
97    {
98        $this->flags |= self::FLAG_OPTIONAL;
99
100        return $this;
101    }
102
103    public function strict(): static
104    {
105        $this->coercionMode = CoercionMode::Strict;
106
107        return $this;
108    }
109
110    public function coerce(): static
111    {
112        $this->coercionMode = CoercionMode::Coerce;
113
114        return $this;
115    }
116
117    public function hasDefault(): bool
118    {
119        return ($this->flags & self::FLAG_HAS_DEFAULT) !== 0;
120    }
121
122    public function defaultValue(): mixed
123    {
124        return $this->default;
125    }
126
127    public function isNullable(): bool
128    {
129        return ($this->flags & self::FLAG_NULLABLE) !== 0;
130    }
131
132    public function isOptional(): bool
133    {
134        return ($this->flags & self::FLAG_OPTIONAL) !== 0;
135    }
136
137    /** @internal */
138    public function coercionMode(CoercionMode $default): CoercionMode
139    {
140        return $this->coercionMode ?? $default;
141    }
142
143    public function treatsMissingAsEmpty(): bool
144    {
145        return in_array(Blank::Missing, $this->empty, true);
146    }
147
148    public function isBlank(mixed $value): bool
149    {
150        foreach ($this->empty as $empty) {
151            if ($this->matchesEmpty($empty, $value)) {
152                return true;
153            }
154        }
155
156        return false;
157    }
158
159    public function message(string $key, string $message): static
160    {
161        $this->messages[$this->messageKey($key)] = $message;
162
163        return $this;
164    }
165
166    /** @param array<string, string> $messages */
167    public function messages(array $messages): static
168    {
169        foreach ($messages as $key => $message) {
170            $this->message($key, $message);
171        }
172
173        return $this;
174    }
175
176    /** @return array<string, string> */
177    public function messageOverrides(): array
178    {
179        return $this->messages;
180    }
181
182    public function name(): string
183    {
184        return $this->label ?? $this->field;
185    }
186
187    public function type(): string
188    {
189        return is_string($this->type) ? $this->type : 'shape';
190    }
191
192    /** @param array<string, mixed> $data */
193    public function applyPreparation(mixed $value, array $data): mixed
194    {
195        foreach ($this->preparers as $prepare) {
196            $value = $prepare($value, $data);
197        }
198
199        return $value;
200    }
201
202    /** @param array<string, mixed> $values */
203    public function applyFinalization(mixed $value, array $values): mixed
204    {
205        foreach ($this->finalizers as $finalize) {
206            $values[$this->field] = $value;
207            $value = $finalize($value, $values);
208        }
209
210        return $value;
211    }
212
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
217            Blank::Null => $value === null,
218            Blank::String => $value === '',
219            Blank::Whitespace => is_string($value) && trim($value) === '',
220            Blank::List => $value === [],
221        };
222    }
223
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
227            return 'type.' . $this->type();
228        }
229
230        if ($key === 'missing' || $key === 'null') {
231            return $key;
232        }
233
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
235            return $key;
236        }
237
238        return 'rule.' . $key;
239    }
240}

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.

Field->__construct
30        public readonly string $field,
31        public readonly string|Contract\Validator $type,
32    ) {}
Field->applyFinalization
203    public function applyFinalization(mixed $value, array $values): mixed
204    {
205        foreach ($this->finalizers as $finalize) {
 
205        foreach ($this->finalizers as $finalize) {
 
205        foreach ($this->finalizers as $finalize) {
206            $values[$this->field] = $value;
 
205        foreach ($this->finalizers as $finalize) {
 
205        foreach ($this->finalizers as $finalize) {
206            $values[$this->field] = $value;
207            $value = $finalize($value, $values);
208        }
209
210        return $value;
211    }
203    public function applyFinalization(mixed $value, array $values): mixed
204    {
205        foreach ($this->finalizers as $finalize) {
 
205        foreach ($this->finalizers as $finalize) {
 
205        foreach ($this->finalizers as $finalize) {
206            $values[$this->field] = $value;
207            $value = $finalize($value, $values);
208        }
209
210        return $value;
211    }
203    public function applyFinalization(mixed $value, array $values): mixed
204    {
205        foreach ($this->finalizers as $finalize) {
 
205        foreach ($this->finalizers as $finalize) {
206            $values[$this->field] = $value;
207            $value = $finalize($value, $values);
208        }
209
210        return $value;
211    }
Field->applyPreparation
193    public function applyPreparation(mixed $value, array $data): mixed
194    {
195        foreach ($this->preparers as $prepare) {
 
195        foreach ($this->preparers as $prepare) {
 
195        foreach ($this->preparers as $prepare) {
196            $value = $prepare($value, $data);
 
195        foreach ($this->preparers as $prepare) {
 
195        foreach ($this->preparers as $prepare) {
196            $value = $prepare($value, $data);
197        }
198
199        return $value;
200    }
193    public function applyPreparation(mixed $value, array $data): mixed
194    {
195        foreach ($this->preparers as $prepare) {
 
195        foreach ($this->preparers as $prepare) {
 
195        foreach ($this->preparers as $prepare) {
196            $value = $prepare($value, $data);
197        }
198
199        return $value;
200    }
193    public function applyPreparation(mixed $value, array $data): mixed
194    {
195        foreach ($this->preparers as $prepare) {
 
195        foreach ($this->preparers as $prepare) {
196            $value = $prepare($value, $data);
197        }
198
199        return $value;
200    }
Field->coerce
112        $this->coercionMode = CoercionMode::Coerce;
113
114        return $this;
115    }
Field->coercionMode
138    public function coercionMode(CoercionMode $default): CoercionMode
139    {
140        return $this->coercionMode ?? $default;
141    }
Field->default
77    public function default(mixed $value): static
78    {
79        $this->default = $value;
80        $this->flags |= self::FLAG_HAS_DEFAULT;
81
82        if ($value === null) {
 
83            $this->nullable();
84        }
85
86        return $this;
 
86        return $this;
87    }
77    public function default(mixed $value): static
78    {
79        $this->default = $value;
80        $this->flags |= self::FLAG_HAS_DEFAULT;
81
82        if ($value === null) {
 
86        return $this;
87    }
Field->defaultValue
124        return $this->default;
125    }
Field->empty
66    public function empty(Blank|string ...$empty): static
67    {
68        $this->empty = [];
69
70        foreach ($empty as $value) {
 
70        foreach ($empty as $value) {
 
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
 
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
 
70        foreach ($empty as $value) {
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
 
70        foreach ($empty as $value) {
 
70        foreach ($empty as $value) {
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
72        }
73
74        return $this;
75    }
66    public function empty(Blank|string ...$empty): static
67    {
68        $this->empty = [];
69
70        foreach ($empty as $value) {
 
70        foreach ($empty as $value) {
 
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
 
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
 
70        foreach ($empty as $value) {
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
 
70        foreach ($empty as $value) {
 
70        foreach ($empty as $value) {
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
72        }
73
74        return $this;
75    }
66    public function empty(Blank|string ...$empty): static
67    {
68        $this->empty = [];
69
70        foreach ($empty as $value) {
 
70        foreach ($empty as $value) {
 
70        foreach ($empty as $value) {
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
72        }
73
74        return $this;
75    }
66    public function empty(Blank|string ...$empty): static
67    {
68        $this->empty = [];
69
70        foreach ($empty as $value) {
 
70        foreach ($empty as $value) {
71            $this->empty[] = $value instanceof Blank ? $value : Blank::from($value);
72        }
73
74        return $this;
75    }
Field->finalize
59    public function finalize(callable $callback): static
60    {
61        $this->finalizers[] = $callback;
62
63        return $this;
64    }
Field->hasDefault
119        return ($this->flags & self::FLAG_HAS_DEFAULT) !== 0;
120    }
Field->isBlank
148    public function isBlank(mixed $value): bool
149    {
150        foreach ($this->empty as $empty) {
 
150        foreach ($this->empty as $empty) {
 
151            if ($this->matchesEmpty($empty, $value)) {
 
152                return true;
148    public function isBlank(mixed $value): bool
149    {
150        foreach ($this->empty as $empty) {
 
150        foreach ($this->empty as $empty) {
 
151            if ($this->matchesEmpty($empty, $value)) {
 
150        foreach ($this->empty as $empty) {
 
150        foreach ($this->empty as $empty) {
 
150        foreach ($this->empty as $empty) {
151            if ($this->matchesEmpty($empty, $value)) {
152                return true;
153            }
154        }
155
156        return false;
157    }
148    public function isBlank(mixed $value): bool
149    {
150        foreach ($this->empty as $empty) {
 
150        foreach ($this->empty as $empty) {
 
150        foreach ($this->empty as $empty) {
151            if ($this->matchesEmpty($empty, $value)) {
152                return true;
153            }
154        }
155
156        return false;
157    }
148    public function isBlank(mixed $value): bool
149    {
150        foreach ($this->empty as $empty) {
 
150        foreach ($this->empty as $empty) {
151            if ($this->matchesEmpty($empty, $value)) {
152                return true;
153            }
154        }
155
156        return false;
157    }
Field->isNullable
129        return ($this->flags & self::FLAG_NULLABLE) !== 0;
130    }
Field->isOptional
134        return ($this->flags & self::FLAG_OPTIONAL) !== 0;
135    }
Field->label
43    public function label(string $label): static
44    {
45        $this->label = $label;
46
47        return $this;
48    }
Field->matchesEmpty
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
 
217            Blank::Null => $value === null,
 
218            Blank::String => $value === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
220            Blank::List => $value === [],
 
220            Blank::List => $value === [],
 
220            Blank::List => $value === [],
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
 
217            Blank::Null => $value === null,
 
218            Blank::String => $value === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
220            Blank::List => $value === [],
 
220            Blank::List => $value === [],
 
220            Blank::List => $value === [],
221        };
222    }
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
 
217            Blank::Null => $value === null,
 
218            Blank::String => $value === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
220            Blank::List => $value === [],
221        };
222    }
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
 
217            Blank::Null => $value === null,
 
218            Blank::String => $value === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
220            Blank::List => $value === [],
221        };
222    }
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
 
217            Blank::Null => $value === null,
 
218            Blank::String => $value === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
219            Blank::Whitespace => is_string($value) && trim($value) === '',
 
220            Blank::List => $value === [],
221        };
222    }
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
 
217            Blank::Null => $value === null,
 
218            Blank::String => $value === '',
 
218            Blank::String => $value === '',
 
220            Blank::List => $value === [],
221        };
222    }
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
 
217            Blank::Null => $value === null,
 
217            Blank::Null => $value === null,
 
220            Blank::List => $value === [],
221        };
222    }
213    private function matchesEmpty(Blank $empty, mixed $value): bool
214    {
215        return match ($empty) {
216            Blank::Missing => false,
 
216            Blank::Missing => false,
 
220            Blank::List => $value === [],
221        };
222    }
Field->message
159    public function message(string $key, string $message): static
160    {
161        $this->messages[$this->messageKey($key)] = $message;
162
163        return $this;
164    }
Field->messageKey
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
227            return 'type.' . $this->type();
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
231            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
231            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
235            return $key;
224    private function messageKey(string $key): string
225    {
226        if ($key === 'type') {
 
230        if ($key === 'missing' || $key === 'null') {
 
230        if ($key === 'missing' || $key === 'null') {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
234        if (str_starts_with($key, 'type.') || str_starts_with($key, 'rule.')) {
 
238        return 'rule.' . $key;
239    }
Field->messageOverrides
179        return $this->messages;
180    }
Field->messages
167    public function messages(array $messages): static
168    {
169        foreach ($messages as $key => $message) {
 
169        foreach ($messages as $key => $message) {
 
169        foreach ($messages as $key => $message) {
 
169        foreach ($messages as $key => $message) {
 
169        foreach ($messages as $key => $message) {
170            $this->message($key, $message);
171        }
172
173        return $this;
174    }
167    public function messages(array $messages): static
168    {
169        foreach ($messages as $key => $message) {
 
169        foreach ($messages as $key => $message) {
 
169        foreach ($messages as $key => $message) {
170            $this->message($key, $message);
171        }
172
173        return $this;
174    }
167    public function messages(array $messages): static
168    {
169        foreach ($messages as $key => $message) {
 
169        foreach ($messages as $key => $message) {
170            $this->message($key, $message);
171        }
172
173        return $this;
174    }
Field->name
184        return $this->label ?? $this->field;
185    }
Field->nullable
91        $this->flags |= self::FLAG_NULLABLE;
92
93        return $this;
94    }
Field->optional
98        $this->flags |= self::FLAG_OPTIONAL;
99
100        return $this;
101    }
Field->prepare
51    public function prepare(callable $callback): static
52    {
53        $this->preparers[] = $callback;
54
55        return $this;
56    }
Field->rules
34    public function rules(string ...$rules): static
35    {
36        foreach ($rules as $rule) {
 
36        foreach ($rules as $rule) {
 
36        foreach ($rules as $rule) {
37            $this->rules[] = $rule;
 
36        foreach ($rules as $rule) {
 
36        foreach ($rules as $rule) {
37            $this->rules[] = $rule;
38        }
39
40        return $this;
41    }
34    public function rules(string ...$rules): static
35    {
36        foreach ($rules as $rule) {
 
36        foreach ($rules as $rule) {
 
36        foreach ($rules as $rule) {
37            $this->rules[] = $rule;
38        }
39
40        return $this;
41    }
34    public function rules(string ...$rules): static
35    {
36        foreach ($rules as $rule) {
 
36        foreach ($rules as $rule) {
37            $this->rules[] = $rule;
38        }
39
40        return $this;
41    }
Field->strict
105        $this->coercionMode = CoercionMode::Strict;
106
107        return $this;
108    }
Field->treatsMissingAsEmpty
145        return in_array(Blank::Missing, $this->empty, true);
 
145        return in_array(Blank::Missing, $this->empty, true);
 
145        return in_array(Blank::Missing, $this->empty, true);
146    }
145        return in_array(Blank::Missing, $this->empty, true);
 
145        return in_array(Blank::Missing, $this->empty, true);
 
145        return in_array(Blank::Missing, $this->empty, true);
146    }
Field->type
189        return is_string($this->type) ? $this->type : 'shape';
 
189        return is_string($this->type) ? $this->type : 'shape';
 
189        return is_string($this->type) ? $this->type : 'shape';
190    }
189        return is_string($this->type) ? $this->type : 'shape';
 
189        return is_string($this->type) ? $this->type : 'shape';
 
189        return is_string($this->type) ? $this->type : 'shape';
190    }