Passed
Push — main ( 92895e...7a79c8 )
by Breno
01:59
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\AllowsEmpty;
7
use BrenoRoosevelt\Validation\Rules\AllowsNull;
8
use BrenoRoosevelt\Validation\Rules\NotRequired;
9
use Countable;
10
use IteratorAggregate;
11
use SplObjectStorage;
12
13
class ValidationSet implements Validation, IteratorAggregate, Countable
14
{
15
    use GuardForValidation,
16
        MaybeBelongsToField;
17
18
    private SplObjectStorage $rules;
19
20
    final public function __construct(?string $field = null, Validation|ValidationSet ...$rules)
21
    {
22
        $this->rules = new SplObjectStorage;
23
        $this->withField($field);
24
        $this->attachRules(...$rules);
25
    }
26
27
    public static function empty(): self
28
    {
29
        return new self;
30
    }
31
32
    public static function forField(string $field, Validation|ValidationSet ...$rules): self
33
    {
34
        return new self($field, ...$rules);
35
    }
36
37
    public static function withRules(Validation|ValidationSet ...$rules): self
38
    {
39
        return new self(null, ...$rules);
40
    }
41
42
    public function add(Validation|ValidationSet ...$rules): self
43
    {
44
        $instance = clone $this;
45
        $instance->attachRules(...$rules);
46
        return $instance;
47
    }
48
49
    private function attachRules(Validation|ValidationSet ...$rules): void
50
    {
51
        foreach ($rules as $validationOrSet) {
52
            if ($validationOrSet instanceof Validation) {
53
                $this->rules->attach($validationOrSet);
54
            }
55
56
            if ($validationOrSet instanceof ValidationSet) {
57
                foreach ($validationOrSet as $validation) {
58
                    $this->rules->attach($validation);
59
                }
60
            }
61
        }
62
    }
63
64
    public function validate(mixed $input, array $context = []): ValidationResult|ValidationResultByField
65
    {
66
        $violations = $empty = $this->newEmptyValidationResult();
67
        if (null === $input && $this->allowsNull()) {
68
            return $empty;
69
        }
70
71
        if (empty($input) && $this->allowsEmpty()) {
72
            return $empty;
73
        }
74
75
        foreach ($this->rules as $rule) {
76
            $violations = $violations->error(...$rule->validate($input, $context)->getErrors());
77
        }
78
79
        return $violations;
80
    }
81
82
    public function isRequired(): bool
83
    {
84
        if ($this->isEmpty()) {
85
            return false;
86
        }
87
88
        foreach ($this->rules as $rule) {
89
            if ($rule instanceof NotRequired) {
90
                return false;
91
            }
92
        }
93
94
        return true;
95
    }
96
97
    public function allowsEmpty(): bool
98
    {
99
        if ($this->isEmpty()) {
100
            return true;
101
        }
102
103
        foreach ($this->rules as $rule) {
104
            if ($rule instanceof AllowsEmpty) {
105
                return true;
106
            }
107
        }
108
109
        return false;
110
    }
111
112
    public function allowsNull(): bool
113
    {
114
        if ($this->isEmpty()) {
115
            return true;
116
        }
117
118
        foreach ($this->rules as $rule) {
119
            if ($rule instanceof AllowsNull) {
120
                return true;
121
            }
122
        }
123
124
        return false;
125
    }
126
127
    public function setNotRequired(): self
128
    {
129
        return $this->add(NotRequired::instance());
130
    }
131
132
    public function setAllowsEmpty(): self
133
    {
134
        return $this->add(AllowsEmpty::instance());
135
    }
136
137
    public function setAllowsNull(): self
138
    {
139
        return $this->add(AllowsNull::instance());
140
    }
141
142
    public function isEmpty(): bool
143
    {
144
        return $this->rules->count() === 0;
145
    }
146
147
    /** @return Validation[] */
148
    public function toArray(): array
149
    {
150
        return iterator_to_array($this->rules);
151
    }
152
153
    public function getIterator(): SplObjectStorage
154
    {
155
        return clone $this->rules;
156
    }
157
158
    public function count(): int
159
    {
160
        return $this->rules->count();
161
    }
162
}
163