Skip to content

Commit c4a9237

Browse files
innocenzibrendt
andauthored
feat(validation): add ability to validate an array of values (#1212)
Co-authored-by: Brent Roose <[email protected]>
1 parent f2c9e47 commit c4a9237

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

packages/validation/src/Validator.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
final readonly class Validator
2121
{
22+
/**
23+
* Validates the values of public properties on the specified object using attribute rules.
24+
*/
2225
public function validateObject(object $object): void
2326
{
2427
$class = new ClassReflector($object);
@@ -41,6 +44,8 @@ public function validateObject(object $object): void
4144
}
4245

4346
/**
47+
* Validates the specified `$values` for the corresponding public properties on the specified `$class`, using built-in PHP types and attribute rules.
48+
*
4449
* @param ClassReflector|class-string $class
4550
*/
4651
public function validateValuesForClass(ClassReflector|string $class, ?array $values, string $prefix = ''): array
@@ -89,6 +94,9 @@ class: $property->getType()->asClass(),
8994
return $failingRules;
9095
}
9196

97+
/**
98+
* Validates `$value` against the specified `$property`, using built-in PHP types and attribute rules.
99+
*/
92100
public function validateValueForProperty(PropertyReflector $property, mixed $value): array
93101
{
94102
$rules = $property->getAttributes(Rule::class);
@@ -113,6 +121,9 @@ public function validateValueForProperty(PropertyReflector $property, mixed $val
113121
return $this->validateValue($value, $rules);
114122
}
115123

124+
/**
125+
* Validates the specified `$value` against the specified set `$rules`.
126+
*/
116127
public function validateValue(mixed $value, Closure|Rule|array $rules): array
117128
{
118129
$failingRules = [];
@@ -132,6 +143,31 @@ public function validateValue(mixed $value, Closure|Rule|array $rules): array
132143
return $failingRules;
133144
}
134145

146+
/**
147+
* Validates the specified `$values` against the specified set `$rules`.
148+
* The `$rules` array is expected to have the same keys as `$values`, associated with instance of {@see Tempest\Validation\Rule}.
149+
* If `$rules` doesn't contain a key for a value, it will not be validated.
150+
*
151+
* @param array<string,mixed> $values
152+
* @param array<string,\Tempest\Validation\Rule> $rules
153+
*/
154+
public function validateValues(iterable $values, array $rules): array
155+
{
156+
$failingRules = [];
157+
158+
foreach ($values as $key => $value) {
159+
if (! array_key_exists($key, $rules)) {
160+
continue;
161+
}
162+
163+
if ($failures = $this->validateValue($value, $rules[$key])) {
164+
$failingRules[$key] = $failures;
165+
}
166+
}
167+
168+
return $failingRules;
169+
}
170+
135171
private function convertToRule(Rule|Closure $rule, mixed $value): Rule
136172
{
137173
if ($rule instanceof Rule) {

packages/validation/tests/ValidatorTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,4 +238,41 @@ public function test_skip_validation_attribute(): void
238238

239239
$this->assertEmpty($failingRules);
240240
}
241+
242+
public function test_validate_values_some_invalid(): void
243+
{
244+
$failingRules = new Validator()->validateValues(
245+
[
246+
'name' => '',
247+
'email' => 'invalid-email',
248+
'age' => 0,
249+
],
250+
[
251+
'name' => [new IsString(), new NotNull()],
252+
'email' => [new Email()],
253+
'age' => [new IsInteger(), new NotNull()],
254+
],
255+
);
256+
257+
$this->assertCount(1, $failingRules);
258+
$this->assertInstanceOf(Email::class, $failingRules['email'][0]);
259+
}
260+
261+
public function test_validate_values_all_valid(): void
262+
{
263+
$failingRules = new Validator()->validateValues(
264+
[
265+
'name' => '',
266+
'email' => '[email protected]',
267+
'age' => 0,
268+
],
269+
[
270+
'name' => [new IsString(), new NotNull()],
271+
'email' => [new Email()],
272+
'age' => [new IsInteger(), new NotNull()],
273+
],
274+
);
275+
276+
$this->assertCount(0, $failingRules);
277+
}
241278
}

0 commit comments

Comments
 (0)