From b75a17e306eb66a136e75c3904fe55d7cb8e26b9 Mon Sep 17 00:00:00 2001 From: Eithel Date: Sat, 16 May 2026 20:00:35 +0200 Subject: [PATCH] fix: improve validateObject and validateValueForProperty methods --- packages/validation/src/Validator.php | 12 ++++++-- packages/validation/tests/ValidatorTest.php | 31 +++++++++++++++++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/validation/src/Validator.php b/packages/validation/src/Validator.php index 3ed45600e..ca95be76d 100644 --- a/packages/validation/src/Validator.php +++ b/packages/validation/src/Validator.php @@ -49,11 +49,15 @@ public function validateObject(object $object): void $value = $property->getValue($object); - $failingRules[$property->getName()] = $this->validateValueForProperty($property, $value); + $failingRulesForProperty = $this->validateValueForProperty($property, $value); + + if ($failingRulesForProperty !== []) { + $failingRules[$property->getName()] = $failingRulesForProperty; + } } if ($failingRules !== []) { - throw $this->createValidationFailureException($failingRules, $object); + throw $this->createValidationFailureException($failingRules, $object, $object::class); } } @@ -153,9 +157,11 @@ public function validateValueForProperty(PropertyReflector $property, mixed $val $key = $property->getAttribute(TranslationKey::class)?->key; + $field = $property->getName(); + return Arr\map( array: $this->validateValue($value, $rules), - map: fn (FailingRule $rule) => $rule->withKey($key), + map: fn (FailingRule $rule) => $rule->withField($field)->withKey($key), ); } diff --git a/packages/validation/tests/ValidatorTest.php b/packages/validation/tests/ValidatorTest.php index e817df893..810c796a7 100644 --- a/packages/validation/tests/ValidatorTest.php +++ b/packages/validation/tests/ValidatorTest.php @@ -8,6 +8,7 @@ use Tempest\Reflection\ClassReflector; use Tempest\Validation\Exceptions\ValidationFailed; use Tempest\Validation\HasErrorMessage; +use Tempest\Validation\Rules\HasLength; use Tempest\Validation\Rules\IsBoolean; use Tempest\Validation\Rules\IsEmail; use Tempest\Validation\Rules\IsEnum; @@ -37,9 +38,35 @@ final class ValidatorTest extends TestCase public function test_validate(): void { - $this->expectException(ValidationFailed::class); + try { + $this->validator->validateObject(new ObjectToBeValidated(name: 'a')); + $this->fail('Expected ValidationFailed to be thrown.'); + } catch (ValidationFailed $e) { + $this->assertArrayHasKey('name', $e->failingRules); + $this->assertCount(1, $e->failingRules['name']); + $this->assertInstanceOf(HasLength::class, $e->failingRules['name'][0]->rule); + $this->assertSame('name', $e->failingRules['name'][0]->field); + $this->assertSame('a', $e->failingRules['name'][0]->value); + $this->assertSame(ObjectToBeValidated::class, $e->targetClass); + } + } + + public function test_validate_passes_with_valid_object(): void + { + $this->validator->validateObject(new ObjectToBeValidated(name: 'ab')); + + $this->expectNotToPerformAssertions(); + } + + public function test_validate_value_for_property_sets_field_and_value(): void + { + $property = (new ClassReflector(ValidateObjectA::class))->getProperty('title'); - $this->validator->validateObject(new ObjectToBeValidated(name: 'a')); + $failingRules = $this->validator->validateValueForProperty($property, 123); + + $this->assertCount(1, $failingRules); + $this->assertSame('title', $failingRules[0]->field); + $this->assertSame(123, $failingRules[0]->value); } public function test_validate_value(): void