Passed
Push — main ( b1f274...dccb3c )
by Breno
01:48
created

Validator::only()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 6
rs 10
c 1
b 0
f 0
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 (!$this->shouldValidate($ruleSet, $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
    private function shouldValidate(ValidationSet $ruleSet, string $field, array $data): bool
65
    {
66
        if (!$ruleSet->isRequired() && !array_key_exists($field, $data)) {
67
            return false;
68
        }
69
70
        $notNull = $notEmpty = 1;
71
        if ($ruleSet->allowsNull() && null === $data[$field] ?? $notNull) {
72
            return false;
73
        }
74
75
        if ($ruleSet->allowsEmpty() && empty($data[$field] ?? $notEmpty)) {
76
            return false;
77
        }
78
79
        return true;
80
    }
81
82
    public function only(string ...$fields): self
83
    {
84
        $instance = clone $this;
85
        $instance->ruleSets =
86
            array_filter($instance->ruleSets, fn(ValidationSet $ruleSet) => in_array($ruleSet->getField(), $fields));
87
        return $instance;
88
    }
89
90
    public function except(string ...$fields): self
91
    {
92
        $instance = clone $this;
93
        $instance->ruleSets =
94
            array_filter($instance->ruleSets, fn(ValidationSet $ruleSet) => !in_array($ruleSet->getField(), $fields));
95
        return $instance;
96
    }
97
98
    /**
99
     * @throws ReflectionException
100
     */
101
    public function validateObject(object $object): ValidationResultSet
102
    {
103
        $data = [];
104
        $class = new ReflectionClass($object);
105
        foreach ($class->getProperties() as $property) {
106
            $data[$property->getName()] = $property->getValue($object);
107
        }
108
109
        $result = Validator::fromProperties($object)->validate($data);
110
111
        foreach ($class->getMethods() as $method) {
112
            $ruleSet = ValidationSet::fromReflectionMethod($method);
113
            $value = $method->invoke($method->isStatic() ? null : $object);
114
            $methodResult = $ruleSet->validate($value);
115
            if (!$methodResult->isOk()) {
116
                $result = $result->add($methodResult);
117
            }
118
        }
119
120
        return $result;
121
    }
122
123
    /**
124
     * @param array $data
125
     * @param ?string $message
126
     * @return void
127
     * @throws ValidationException
128
     */
129
    public function validateOrFail(array $data = [], ?string $message = null)
130
    {
131
        $result = $this->validate($data);
132
        if (!$result->isOk()) {
133
            throw new ValidationException($result, $message);
134
        }
135
    }
136
137
    /**
138
     * @param string|object $objectOrClass
139
     * @param int|null $filter filter properties, ex: ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PRIVATE
140
     * @return static
141
     * @throws ReflectionException if the class does not exist
142
     */
143
    public static function fromProperties(string|object $objectOrClass, ?int $filter = null): self
144
    {
145
        $instance = new self;
146
        $instance->ruleSets = ValidationSet::fromProperties($objectOrClass, $filter);
147
        return $instance;
148
    }
149
}
150