Passed
Push — main ( 60c264...37a7fc )
by Breno
02:05
created

Validator::validateObject()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 6
nop 1
dl 0
loc 20
rs 9.8666
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace BrenoRoosevelt\Validation;
5
6
use ReflectionClass;
7
use ReflectionException;
8
use ReflectionMethod;
9
10
final class Validator
11
{
12
    /** @var ValidationSet[] */
13
    private array $ruleSets;
14
15
    public static function new(): self
16
    {
17
        return new self;
18
    }
19
20
    public function ruleSet(string $field): ValidationSet
21
    {
22
        foreach ($this->ruleSets as $ruleSet) {
23
            if ($ruleSet->getField() === $field) {
24
                return $ruleSet;
25
            }
26
        }
27
28
        return $this->ruleSets[] = ValidationSet::forField($field);
29
    }
30
31
    public function field(string $field, Validation|ValidationSet ...$rules): self
32
    {
33
        $ruleset = $this->ruleSet($field);
34
        foreach ($rules as $rule) {
35
            if ($rule instanceof Validation) {
36
                $ruleset->add($rule);
37
            }
38
39
            if ($rule instanceof ValidationSet) {
40
                $ruleset->add(...$rule->rules());
41
            }
42
        }
43
44
        return $this;
45
    }
46
47
    public function validate(array $data = []): ValidationResultSet
48
    {
49
        $validationResultSet = new ValidationResultSet;
50
        foreach ($this->ruleSets as $ruleSet) {
51
            $field = $ruleSet->getField();
52
            if (!$ruleSet->isRequired() && !array_key_exists($field, $data)) {
53
                continue;
54
            }
55
56
            $result = $ruleSet->validate($data[$field] ?? null, $data);
57
            if (!$result->isOk()) {
58
                $validationResultSet = $validationResultSet->add($result);
59
            }
60
        }
61
62
        return $validationResultSet;
63
    }
64
65
    /**
66
     * @throws ReflectionException
67
     */
68
    public function validateObject(object $object): ValidationResultSet
69
    {
70
        $data = [];
71
        $properties = (new ReflectionClass($object))->getProperties();
72
        foreach ($properties as $property) {
73
            $data[$property->getName()] = $property->getValue($object);
74
        }
75
76
        $result = Validator::fromProperties($object)->validate($data);
77
78
        $methodRules = ValidationSet::fromMethods($object);
79
        foreach ($methodRules as $methodName => $ruleSet) {
80
            $value = (new ReflectionMethod($object, $methodName))->invoke($object);
81
            $methodResult = $ruleSet->validate($value);
82
            if (!$methodResult->isOk()) {
83
                $result = $result->add($methodResult);
84
            }
85
        }
86
87
        return $result;
88
    }
89
90
    /**
91
     * @param array $data
92
     * @param ?string $message
93
     * @return void
94
     * @throws ValidationException
95
     */
96
    public function validateOrFail(array $data = [], ?string $message = null)
97
    {
98
        $result = $this->validate($data);
99
        if (!$result->isOk()) {
100
            throw new ValidationException($result, $message);
101
        }
102
    }
103
104
    /**
105
     * @param string|object $objectOrClass
106
     * @param int|null $filter filter properties, ex: ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PRIVATE
107
     * @return static
108
     * @throws ReflectionException if the class does not exist
109
     */
110
    public static function fromProperties(string|object $objectOrClass, ?int $filter = null): self
111
    {
112
        $instance = new self;
113
        $instance->ruleSets = ValidationSet::fromProperties($objectOrClass, $filter);
114
        return $instance;
115
    }
116
}
117