Passed
Push — main ( 2c4672...4947bd )
by Breno
01:51
created

ValidationSet::empty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace BrenoRoosevelt\Validation;
5
6
use BrenoRoosevelt\Validation\Rules\NotEmpty;
7
use BrenoRoosevelt\Validation\Rules\NotRequired;
8
use ReflectionAttribute;
9
use ReflectionClass;
10
use ReflectionException;
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->field = $field;
27
        $this->rules = $rules;
28
    }
29
30
    public static function empty(): self
31
    {
32
        return new self;
33
    }
34
35
    /** @throws ValidationException */
36
    public static function forField(string $field, Validation ...$rules): self
37
    {
38
        (new NotEmpty('Field cannot be left empty'))->validateOrFail($field);
39
        return new self($field, ...$rules);
40
    }
41
42
    public static function withRules(Validation $validation, Validation ...$rules): self
43
    {
44
        return new self(null, $validation, ...$rules);
45
    }
46
47
    public function add(Validation ...$rules): self
48
    {
49
        array_push($this->rules, ...$rules);
50
        return $this;
51
    }
52
53
    public function validate($input, array $context = []): ValidationResult|ValidationResultByField
54
    {
55
        $violations = $this->newEmptyValidationResult();
56
        foreach ($this->rules as $constraint) {
57
            $violations->error(...$constraint->validate($input, $context)->getErrors());
58
        }
59
60
        return $violations;
61
    }
62
63
    public function isRequired(): bool
64
    {
65
        foreach ($this->rules as $rule) {
66
            if ($rule instanceof NotRequired) {
67
                return false;
68
            }
69
        }
70
71
        return true;
72
    }
73
74
    public function notRequired(): self
75
    {
76
        if ($this->isRequired()) {
77
            $this->rules[] = new NotRequired;
78
        }
79
80
        return $this;
81
    }
82
83
    public function isEmpty(): bool
84
    {
85
        return empty($this->rules);
86
    }
87
88
    /**
89
     * @param string|object $objectOrClass
90
     * @param int|null $filter filter properties, ex: ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PRIVATE
91
     * @return array
92
     * @throws ReflectionException if the class does not exist
93
     */
94
    public static function fromProperties(string|object $objectOrClass, ?int $filter = null): array
95
    {
96
        $ruleSets = [];
97
        foreach ((new ReflectionClass($objectOrClass))->getProperties($filter) as $property) {
98
            $ruleSets[$property->getName()] = ValidationSet::fromReflectionProperty($property);
99
        }
100
101
        return array_filter($ruleSets, fn(ValidationSet $c) => !$c->isEmpty());
102
    }
103
104
    /**
105
     * @param string|object $objectOrClass
106
     * @param string $property
107
     * @return static
108
     * @throws ReflectionException if the class or property does not exist.
109
     */
110
    public static function fromProperty(string|object $objectOrClass, string $property): self
111
    {
112
        return self::fromReflectionProperty(new ReflectionProperty($objectOrClass, $property));
113
    }
114
115
    /**
116
     * @param ReflectionProperty $property
117
     * @return static
118
     */
119
    public static function fromReflectionProperty(ReflectionProperty $property): self
120
    {
121
        $ruleSet = new self;
122
        $ruleSet->rules = array_map(
123
            fn(ReflectionAttribute $attribute) => $attribute->newInstance(),
124
            $property->getAttributes(Validation::class, ReflectionAttribute::IS_INSTANCEOF)
125
        );
126
        $ruleSet->setField($property->getName());
127
        return $ruleSet;
128
    }
129
130
    /** @return Validation[] */
131
    public function rules(): array
132
    {
133
        return $this->rules;
134
    }
135
}
136