Passed
Push — main ( 93c199...f7f95e )
by Breno
01:50
created

Validator::only()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 3
b 0
f 0
nc 3
nop 1
dl 0
loc 10
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace BrenoRoosevelt\Validation;
5
6
use BrenoRoosevelt\Validation\Exception\Guard;
7
use BrenoRoosevelt\Validation\Exception\ValidationExceptionInterface;
8
use BrenoRoosevelt\Validation\Rules\Required;
9
use ReflectionClass;
10
use ReflectionException;
11
12
final class Validator
13
{
14
    use Guard;
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 isRequired(string $field): bool
48
    {
49
        $ruleSet = $this->ruleSets[$field] ?? new RuleSet;
50
        foreach ($ruleSet->rules() as $rule) {
51
            if ($rule instanceof Required) {
52
                return true;
53
            }
54
        }
55
56
        return false;
57
    }
58
59
    public function validate(array $data = []): ValidationResultSet
60
    {
61
        $resultSet = new ValidationResultSet;
62
        foreach ($this->ruleSets as $field => $fieldRuleSet) {
63
            $fieldIsPresent = array_key_exists($field, $data);
64
            if (!$this->isRequired($field) && !$fieldIsPresent) {
65
                return new ValidationResultSet;
66
            }
67
68
            $result = $fieldRuleSet->validate($data[$field] ?? null, $data);
69
            if (!$result->isOk()) {
70
                $resultSet = $resultSet->add($result);
71
            }
72
        }
73
74
        return $resultSet;
75
    }
76
77
    /**
78
     * @throws ValidationExceptionInterface
79
     */
80
    public function validateOrFail(
81
        array $data = [],
82
        ValidationExceptionInterface | string | null  $validationException = null
83
    ): void {
84
        $this->validate($data)->guard($validationException);
85
    }
86
87
    public static function validateObject(object $object): ValidationResultSet
88
    {
89
        $data = [];
90
        $class = new ReflectionClass($object);
91
        foreach ($class->getProperties() as $property) {
92
            $data[$property->getName()] = $property->getValue($object);
93
        }
94
95
        $result = Validator::fromProperties($object)->validate($data);
96
97
        foreach ($class->getMethods() as $method) {
98
            $ruleSet = RuleSetFactory::fromReflectionMethod($method);
99
            $value = $method->invoke($method->isStatic() ? null : $object);
100
            $methodResult = $ruleSet->validate($value);
101
            if (!$methodResult->isOk()) {
102
                $result = $result->add($methodResult);
103
            }
104
        }
105
106
        return $result;
107
    }
108
109
    /**
110
     * @param string|object $objectOrClass
111
     * @param int|null $filter filter properties, ex: ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PRIVATE
112
     * @return static
113
     * @throws ReflectionException if the class does not exist
114
     */
115
    public static function fromProperties(string|object $objectOrClass, ?int $filter = null): self
116
    {
117
        $instance = new self;
118
        $instance->ruleSets = RuleSetFactory::fromProperties($objectOrClass, $filter);
119
        return $instance;
120
    }
121
}
122