Passed
Push — main ( b8557d...859bf8 )
by Breno
01:37
created

RuleSet::withRules()   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 1
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\Exception\ValidateOrFail;
7
use BrenoRoosevelt\Validation\Rules\AllowsEmpty;
8
use BrenoRoosevelt\Validation\Rules\AllowsNull;
9
use BrenoRoosevelt\Validation\Rules\IsEmpty;
10
use BrenoRoosevelt\Validation\Rules\NotRequired;
11
12
class RuleSet implements Rule
13
{
14
    use RuleChain,
15
        ValidateOrFail,
16
        BelongsToField;
17
18
    private array $rules;
19
20
    final public function __construct(?string $field = null, Rule | RuleSet ...$rules)
21
    {
22
        $this->rules = $rules;
23
        $this->setField($field);
24
    }
25
26
    public static function new(): self
27
    {
28
        return new self;
29
    }
30
31
    public static function of(string $field, Rule | RuleSet ...$rules): self
32
    {
33
        return new self($field, ...$rules);
34
    }
35
36
    public static function withRules(Rule | RuleSet ...$rules): self
37
    {
38
        return new self(null, ...$rules);
39
    }
40
41
    public function add(Rule | RuleSet ...$rules): static
42
    {
43
        $instance = clone $this;
44
        foreach ($rules as $ruleOrRuleSet) {
45
            array_push(
46
                $instance->rules,
47
                ...($ruleOrRuleSet instanceof Rule ? [$ruleOrRuleSet] : $ruleOrRuleSet->rules())
48
            );
49
        }
50
51
        return $instance;
52
    }
53
54
    public function validate(mixed $input, array $context = []): ValidationResult
55
    {
56
        $result = $empty = $this->newEmptyResult();
57
        if (!$this->shouldValidate($input)) {
58
            return $empty;
59
        }
60
61
        foreach ($this->rules as $rule) {
62
            $result = $result->addError(...$rule->validate($input, $context)->getErrors());
63
        }
64
65
        return $result;
66
    }
67
68
    private function shouldValidate(mixed $input): bool
69
    {
70
        if (null === $input && $this->isAllowsNull()) {
71
            return false;
72
        }
73
74
        $isEmptyInput = (new IsEmpty)->isValid($input);
75
        if ($isEmptyInput && $this->isAllowsEmpty()) {
76
            return false;
77
        }
78
79
        return true;
80
    }
81
82
    public function hasRule(string $ruleClass): bool
83
    {
84
        if (!class_exists($ruleClass)) {
85
            return false;
86
        }
87
88
        foreach ($this->rules as $rule) {
89
            if ($rule instanceof $ruleClass) {
90
                return true;
91
            }
92
        }
93
94
        return false;
95
    }
96
97
    public function isNotRequired(): bool
98
    {
99
        return $this->hasRule(NotRequired::class);
100
    }
101
102
    public function isAllowsEmpty(): bool
103
    {
104
        return $this->isEmpty() || $this->hasRule(AllowsEmpty::class);
105
    }
106
107
    public function isAllowsNull(): bool
108
    {
109
        return $this->isEmpty() || $this->hasRule(AllowsNull::class);
110
    }
111
112
    public function isEmpty(): bool
113
    {
114
        return empty($this->rules);
115
    }
116
117
    /** @return Rule[] */
118
    public function rules(): array
119
    {
120
        return $this->rules;
121
    }
122
}
123