Passed
Push — main ( aa2ba1...352c83 )
by Breno
01:51
created

RuleSet::getIterator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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