Passed
Push — main ( e270df...c1496b )
by Breno
01:40
created

Validator::validate()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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