Skip to content

Commit 0dc52a0

Browse files
authored
Merge pull request #3 from KaririCode-Framework/develop
refactor(validator): improve SOLID principles implementation and add …
2 parents e310973 + 5b2bedd commit 0dc52a0

File tree

9 files changed

+246
-69
lines changed

9 files changed

+246
-69
lines changed

composer.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Processor/AbstractValidatorProcessor.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ abstract class AbstractValidatorProcessor implements Processor, ValidatableProce
1212
protected bool $isValid = true;
1313
protected string $errorKey = '';
1414

15+
/**
16+
* Reset the processor's state back to its initial values.
17+
*/
18+
public function reset(): void
19+
{
20+
$this->isValid = true;
21+
$this->errorKey = '';
22+
}
23+
1524
protected function setInvalid(string $errorKey): void
1625
{
1726
$this->isValid = false;

src/Processor/DefaultValidationResultProcessor.php

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,26 @@
55
namespace KaririCode\Validator\Processor;
66

77
use KaririCode\PropertyInspector\AttributeHandler;
8-
use KaririCode\Validator\Contract\ValidationResult as ValidationResultContract;
98
use KaririCode\Validator\Contract\ValidationResultProcessor;
109
use KaririCode\Validator\ValidationResult;
1110

1211
class DefaultValidationResultProcessor implements ValidationResultProcessor
1312
{
14-
public function __construct(
15-
private ValidationResultContract $result = new ValidationResult()
16-
) {
17-
}
18-
1913
public function process(AttributeHandler $handler): ValidationResult
2014
{
15+
$result = new ValidationResult();
2116
$processedValues = $handler->getProcessedPropertyValues();
2217
$errors = $handler->getProcessingResultErrors();
2318

2419
foreach ($processedValues as $property => $data) {
25-
$this->result->setValidatedData($property, $data['value']);
20+
$result->setValidatedData($property, $data['value']);
2621

2722
if (isset($errors[$property])) {
28-
$this->addPropertyErrors($this->result, $property, $errors[$property]);
23+
$this->addPropertyErrors($result, $property, $errors[$property]);
2924
}
3025
}
3126

32-
return $this->result;
27+
return $result;
3328
}
3429

3530
private function addPropertyErrors(

src/Processor/Input/EmailValidator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public function process(mixed $input): mixed
1616
return $input;
1717
}
1818

19+
$input = trim($input);
20+
1921
if (false === filter_var($input, FILTER_VALIDATE_EMAIL)) {
2022
$this->setInvalid('invalidFormat');
2123
}

src/ValidationResult.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,35 @@ class ValidationResult implements ValidationResultContract
1010
{
1111
private array $errors = [];
1212
private array $validatedData = [];
13+
private array $errorHashes = [];
14+
15+
/**
16+
* Reset all validation state.
17+
*
18+
* Clears all errors, validation data, and error hashes,
19+
* returning the ValidationResult to its initial state.
20+
*/
21+
public function reset(): void
22+
{
23+
$this->errors = [];
24+
$this->validatedData = [];
25+
$this->errorHashes = [];
26+
}
1327

1428
public function addError(string $property, string $errorKey, string $message): void
1529
{
1630
if (!isset($this->errors[$property])) {
1731
$this->errors[$property] = [];
32+
$this->errorHashes[$property] = [];
1833
}
1934

2035
// Avoid adding duplicate errors
21-
foreach ($this->errors[$property] as $error) {
22-
if ($error['errorKey'] === $errorKey) {
23-
return;
24-
}
36+
$hash = md5($errorKey . $message);
37+
if (isset($this->errorHashes[$property][$hash])) {
38+
return;
2539
}
2640

41+
$this->errorHashes[$property][$hash] = true;
2742
$this->errors[$property][] = [
2843
'errorKey' => $errorKey,
2944
'message' => $message,
@@ -58,4 +73,9 @@ public function toArray(): array
5873
'validatedData' => $this->validatedData,
5974
];
6075
}
76+
77+
public function __destruct()
78+
{
79+
$this->reset();
80+
}
6181
}

src/Validator.php

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,29 @@
1111
use KaririCode\PropertyInspector\AttributeHandler;
1212
use KaririCode\PropertyInspector\Utility\PropertyInspector;
1313
use KaririCode\Validator\Attribute\Validate;
14-
use KaririCode\Validator\Contract\ValidationResultProcessor;
1514
use KaririCode\Validator\Processor\DefaultValidationResultProcessor;
1615

1716
class Validator implements ValidatorContract
1817
{
1918
private const IDENTIFIER = 'validator';
2019

2120
private ProcessorBuilder $builder;
22-
private PropertyInspector $propertyInspector;
23-
private AttributeHandler $attributeHandler;
2421

2522
public function __construct(
2623
private readonly ProcessorRegistry $registry,
27-
private readonly ValidationResultProcessor $resultProcessor = new DefaultValidationResultProcessor()
2824
) {
2925
$this->builder = new ProcessorBuilder($this->registry);
30-
$this->attributeHandler = new AttributeHandler(self::IDENTIFIER, $this->builder);
31-
$this->propertyInspector = new PropertyInspector(
32-
new AttributeAnalyzer(Validate::class)
33-
);
3426
}
3527

3628
public function validate(mixed $object): ValidationResult
3729
{
38-
$handler = $this->propertyInspector->inspect($object, $this->attributeHandler);
30+
$propertyInspector = new PropertyInspector(
31+
new AttributeAnalyzer(Validate::class)
32+
);
33+
$attributeHandler = new AttributeHandler(self::IDENTIFIER, $this->builder);
34+
$resultProcessor = new DefaultValidationResultProcessor();
35+
$handler = $propertyInspector->inspect($object, $attributeHandler);
3936

40-
return $this->resultProcessor->process($handler);
37+
return $resultProcessor->process($handler);
4138
}
4239
}

tests/Attribute/ValidateTest.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public function testConstructorFiltersInvalidProcessors(): void
4848
$expectedProcessors = ['required', 'email'];
4949
$validate = new Validate($processors);
5050

51-
$this->assertEquals($expectedProcessors, $validate->getProcessors());
51+
$this->assertEquals($expectedProcessors, array_values($validate->getProcessors()));
5252
}
5353

5454
public function testConstructorWithEmptyProcessors(): void
@@ -89,14 +89,19 @@ public static function validProcessorsProvider(): array
8989
[
9090
'length' => ['minLength' => 3, 'maxLength' => 20],
9191
],
92-
['length'],
92+
[
93+
'length' => ['minLength' => 3, 'maxLength' => 20],
94+
],
9395
],
9496
'mixed processors' => [
9597
[
9698
'required',
9799
'email' => ['message' => 'Invalid email'],
98100
],
99-
['required', 'email'],
101+
[
102+
'required',
103+
'email' => ['message' => 'Invalid email'],
104+
],
100105
],
101106
];
102107
}

tests/ValidatorTest.php

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use KaririCode\Contract\Processor\ProcessorRegistry;
88
use KaririCode\Validator\Attribute\Validate;
9-
use KaririCode\Validator\Contract\ValidationResultProcessor;
109
use KaririCode\Validator\Processor\Input\EmailValidator;
1110
use KaririCode\Validator\Processor\Logic\RequiredValidator;
1211
use KaririCode\Validator\ValidationResult;
@@ -17,21 +16,19 @@
1716
class ValidatorTest extends TestCase
1817
{
1918
private ProcessorRegistry|MockObject $registry;
20-
private ValidationResultProcessor|MockObject $resultProcessor;
2119
private Validator $validator;
2220

2321
protected function setUp(): void
2422
{
2523
$this->registry = $this->createMock(ProcessorRegistry::class);
26-
$this->resultProcessor = $this->createMock(ValidationResultProcessor::class);
2724

2825
$this->registry->method('get')
2926
->willReturnMap([
3027
['validator', 'required', new RequiredValidator()],
3128
['validator', 'email', new EmailValidator()],
3229
]);
3330

34-
$this->validator = new Validator($this->registry, $this->resultProcessor);
31+
$this->validator = new Validator($this->registry);
3532
}
3633

3734
public function testValidateWithValidObject(): void
@@ -44,11 +41,6 @@ public function testValidateWithValidObject(): void
4441
$expectedResult = new ValidationResult();
4542
$expectedResult->setValidatedData('email', 'walmir.silva@example.com');
4643

47-
$this->resultProcessor
48-
->expects($this->once())
49-
->method('process')
50-
->willReturn($expectedResult);
51-
5244
$result = $this->validator->validate($testObject);
5345

5446
$this->assertFalse($result->hasErrors());
@@ -65,11 +57,6 @@ public function testValidateWithInvalidObject(): void
6557
$resultWithErrors = new ValidationResult();
6658
$resultWithErrors->addError('email', 'invalidFormat', 'Invalid email format');
6759

68-
$this->resultProcessor
69-
->expects($this->once())
70-
->method('process')
71-
->willReturn($resultWithErrors);
72-
7360
$result = $this->validator->validate($testObject);
7461

7562
$this->assertTrue($result->hasErrors());
@@ -82,13 +69,6 @@ public function testValidateWithNoAttributes(): void
8269
public string $name = 'Test';
8370
};
8471

85-
$emptyResult = new ValidationResult();
86-
87-
$this->resultProcessor
88-
->expects($this->once())
89-
->method('process')
90-
->willReturn($emptyResult);
91-
9272
$result = $this->validator->validate($testObject);
9373

9474
$this->assertFalse($result->hasErrors());
@@ -99,13 +79,6 @@ public function testValidateWithNullObject(): void
9979
{
10080
$testObject = new \stdClass();
10181

102-
$emptyResult = new ValidationResult();
103-
104-
$this->resultProcessor
105-
->expects($this->once())
106-
->method('process')
107-
->willReturn($emptyResult);
108-
10982
$result = $this->validator->validate($testObject);
11083

11184
$this->assertFalse($result->hasErrors());
@@ -128,11 +101,6 @@ public function testValidateWithMultipleProperties(): void
128101
$multiPropertyResult->setValidatedData('name', 'Walmir');
129102
$multiPropertyResult->setValidatedData('email', 'walmir.silva@example.com');
130103

131-
$this->resultProcessor
132-
->expects($this->once())
133-
->method('process')
134-
->willReturn($multiPropertyResult);
135-
136104
$result = $this->validator->validate($testObject);
137105

138106
$this->assertFalse($result->hasErrors());

0 commit comments

Comments
 (0)