Passed
Push — main ( a1ad3c...963e70 )
by Breno
01:36
created

Validator::field()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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