Passed
Push — main ( ff7ab4...7d3a77 )
by Breno
01:49
created

Validator   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 97
Duplicated Lines 0 %

Importance

Changes 25
Bugs 2 Features 0
Metric Value
eloc 36
c 25
b 2
f 0
dl 0
loc 97
rs 10
wmc 17

7 Methods

Rating   Name   Duplication   Size   Complexity  
A ruleSet() 0 3 1
A field() 0 5 1
A new() 0 3 1
A validateOrFail() 0 5 1
A validateObject() 0 20 5
A fromProperties() 0 5 1
B validate() 0 19 7
1
<?php
2
declare(strict_types=1);
3
4
namespace BrenoRoosevelt\Validation;
5
6
use BrenoRoosevelt\Validation\Exception\GuardTrait;
7
use BrenoRoosevelt\Validation\Exception\ValidationExceptionFactoryInterface;
8
use BrenoRoosevelt\Validation\Exception\ValidationExceptionInterface;
9
use ReflectionClass;
10
use ReflectionException;
11
12
final class Validator
13
{
14
    use GuardTrait;
15
16
    /** @var RuleSet[] */
17
    private array $ruleSets;
18
19
    public static function new(): self
20
    {
21
        return new self;
22
    }
23
24
    /**
25
     * Returns an instance of RuleSet (immutable) or null if not set
26
     * @param string $field
27
     * @return RuleSet|null
28
     */
29
    public function ruleSet(string $field): ?RuleSet
30
    {
31
        return $this->ruleSets[$field] ?? null;
32
    }
33
34
    /**
35
     * Apply new rules to the field
36
     * @param string $field
37
     * @param Rule|RuleSet ...$rules
38
     * @return $this
39
     */
40
    public function field(string $field, Rule|RuleSet ...$rules): self
41
    {
42
        $ruleSet = $this->ruleSets[$field] ?? RuleSet::of($field);
43
        $this->ruleSets[$field] = $ruleSet->add(...$rules);
44
        return $this;
45
    }
46
47
    public function validate(array $data = []): ErrorReporting
48
    {
49
        $errorReporting = new ErrorReporting;
50
        foreach ($this->ruleSets as $field => $fieldRuleSet) {
51
            $fieldIsPresent = array_key_exists($field, $data);
52
            if (!$fieldRuleSet->hasRequired() && !$fieldIsPresent) {
53
                continue;
54
            }
55
56
            $fieldRuleSet = $fieldRuleSet->setField($field);
57
            $result = $fieldRuleSet->validate($data[$field] ?? null, $data);
58
            $errorReporting = $errorReporting->add($result);
59
60
            if ($fieldRuleSet instanceof Stopable && $fieldRuleSet->stopOnFailure() && !$result->isOk()) {
61
                break;
62
            }
63
        }
64
65
        return $errorReporting;
66
    }
67
68
    /** @throws ValidationExceptionInterface */
69
    public function validateOrFail(
70
        array $data = [],
71
        ValidationExceptionFactoryInterface | ValidationExceptionInterface | string | null  $validationException = null
72
    ): void {
73
        $this->validate($data)->guard($validationException);
74
    }
75
76
    public static function validateObject(object $object): ErrorReporting
77
    {
78
        $data = [];
79
        $class = new ReflectionClass($object);
80
        foreach ($class->getProperties() as $property) {
81
            $data[$property->getName()] = $property->getValue($object);
82
        }
83
84
        $result = Validator::fromProperties($object)->validate($data);
85
86
        foreach ($class->getMethods() as $method) {
87
            $ruleSet = RuleSetFactory::fromReflectionMethod($method);
88
            $value = $method->invoke($method->isStatic() ? null : $object);
89
            $methodResult = $ruleSet->validate($value);
90
            if (!$methodResult->isOk()) {
91
                $result = $result->add($methodResult);
92
            }
93
        }
94
95
        return $result;
96
    }
97
98
    /**
99
     * @param string|object $objectOrClass
100
     * @param int|null $filter filter properties, ex: ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PRIVATE
101
     * @return static
102
     * @throws ReflectionException if the class does not exist
103
     */
104
    public static function fromProperties(string|object $objectOrClass, ?int $filter = null): self
105
    {
106
        $instance = new self;
107
        $instance->ruleSets = RuleSetFactory::fromProperties($objectOrClass, $filter);
108
        return $instance;
109
    }
110
}
111