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

ValidationSet::fromMethods()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace BrenoRoosevelt\Validation;
5
6
use BrenoRoosevelt\Validation\Rules\NotRequired;
7
use ReflectionAttribute;
8
use ReflectionClass;
9
use ReflectionException;
10
use ReflectionMethod;
11
use ReflectionProperty;
12
13
/**
14
 * Composite
15
 */
16
class ValidationSet implements Validation
17
{
18
    use GuardForValidation,
19
        MaybeBelongsToField;
20
21
    /** @var Validation[] */
22
    private array $rules;
23
24
    final public function __construct(?string $field = null, Validation ...$rules)
25
    {
26
        $this->setField($field);
27
        $this->rules = $rules;
28
    }
29
30
    public static function empty(): self
31
    {
32
        return new self;
33
    }
34
35
    public static function forField(string $field, Validation ...$rules): self
36
    {
37
        return new self($field, ...$rules);
38
    }
39
40
    public static function withRules(Validation $validation, Validation ...$rules): self
41
    {
42
        return new self(null, $validation, ...$rules);
43
    }
44
45
    public function add(Validation ...$rules): self
46
    {
47
        array_push($this->rules, ...$rules);
48
        return $this;
49
    }
50
51
    public function validate(mixed $input, array $context = []): ValidationResult|ValidationResultByField
52
    {
53
        $violations = $this->newEmptyValidationResult();
54
        foreach ($this->rules as $constraint) {
55
            $violations = $violations->error(...$constraint->validate($input, $context)->getErrors());
56
        }
57
58
        return $violations;
59
    }
60
61
    public function isRequired(): bool
62
    {
63
        foreach ($this->rules as $rule) {
64
            if ($rule instanceof NotRequired) {
65
                return false;
66
            }
67
        }
68
69
        return true;
70
    }
71
72
    public function notRequired(): self
73
    {
74
        if ($this->isRequired()) {
75
            $this->rules[] = new NotRequired;
76
        }
77
78
        return $this;
79
    }
80
81
    public function isEmpty(): bool
82
    {
83
        return empty($this->rules);
84
    }
85
86
    /**
87
     * @param string|object $objectOrClass
88
     * @param int|null $filter filter properties, ex: ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PRIVATE
89
     * @return ValidationSet[]
90
     * @throws ReflectionException if the class does not exist
91
     */
92
    public static function fromProperties(string|object $objectOrClass, ?int $filter = null): array
93
    {
94
        $ruleSets = [];
95
        foreach ((new ReflectionClass($objectOrClass))->getProperties($filter) as $property) {
96
            $ruleSets[$property->getName()] = ValidationSet::fromReflectionProperty($property);
97
        }
98
99
        return array_filter($ruleSets, fn(ValidationSet $c) => !$c->isEmpty());
100
    }
101
102
    /**
103
     * @param string|object $objectOrClass
104
     * @param int|null $filter
105
     * @return ValidationSet[]
106
     * @throws ReflectionException
107
     */
108
    public static function fromMethods(string|object $objectOrClass, ?int $filter = null): array
109
    {
110
        $ruleSets = [];
111
        foreach ((new ReflectionClass($objectOrClass))->getMethods($filter) as $method) {
112
            $ruleSets[$method->getName()] = ValidationSet::fromReflectionMethod($method);
113
        }
114
115
        return array_filter($ruleSets, fn(ValidationSet $c) => !$c->isEmpty());
116
    }
117
118
    /**
119
     * @param string|object $objectOrClass
120
     * @param string $property
121
     * @return static
122
     * @throws ReflectionException if the class or property does not exist.
123
     */
124
    public static function fromProperty(string|object $objectOrClass, string $property): self
125
    {
126
        return self::fromReflectionProperty(new ReflectionProperty($objectOrClass, $property));
127
    }
128
129
    public static function fromMethod(string|object $objectOrClass, string $method): self
130
    {
131
        return self::fromReflectionMethod(new ReflectionMethod($objectOrClass, $method));
132
    }
133
134
    /**
135
     * @param ReflectionProperty $property
136
     * @return static
137
     */
138
    public static function fromReflectionProperty(ReflectionProperty $property): self
139
    {
140
        return
141
            ValidationSet::forField(
142
                $property->getName(),
143
                ...array_map(
144
                    fn(ReflectionAttribute $attribute) => $attribute->newInstance(),
145
                    $property->getAttributes(Validation::class, ReflectionAttribute::IS_INSTANCEOF)
146
                )
147
            );
148
    }
149
150
    /**
151
     * @param ReflectionMethod $method
152
     * @return static
153
     */
154
    public static function fromReflectionMethod(ReflectionMethod $method): self
155
    {
156
        return
157
            ValidationSet::withRules(
158
                ...array_map(
159
                    fn(ReflectionAttribute $attribute) => $attribute->newInstance(),
160
                    $method->getAttributes(Validation::class, ReflectionAttribute::IS_INSTANCEOF)
161
                )
162
            );
163
    }
164
165
    /** @return Validation[] */
166
    public function rules(): array
167
    {
168
        return $this->rules;
169
    }
170
}
171