Passed
Push — master ( bc036e...f8a9bb )
by Smoren
02:19
created

Rule::getName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Smoren\Validator\Rules;
6
7
use Smoren\Validator\Checks\Check;
8
use Smoren\Validator\Checks\RetrospectiveCheck;
9
use Smoren\Validator\Exceptions\CheckError;
10
use Smoren\Validator\Exceptions\ValidationError;
11
use Smoren\Validator\Interfaces\CheckInterface;
12
use Smoren\Validator\Interfaces\CheckWrapperInterface;
13
use Smoren\Validator\Interfaces\RuleInterface;
14
use Smoren\Validator\Interfaces\UtilityCheckInterface;
15
use Smoren\Validator\Interfaces\ValidationResultInterface;
16
use Smoren\Validator\Structs\CheckErrorName;
17
use Smoren\Validator\Structs\CheckName;
18
use Smoren\Validator\Structs\CheckWrapper;
19
use Smoren\Validator\Structs\ValidationSuccessResult;
20
21
class Rule extends BaseRule implements RuleInterface
22
{
23
    /**
24
     * @var string
25
     */
26
    protected string $name;
27
    /**
28
     * @var array<CheckWrapperInterface>
29
     */
30
    protected array $checks = [];
31
    /**
32
     * @var bool
33
     */
34
    protected bool $isNullable = false;
35
36
    /**
37
     * @param string $name
38
     */
39
    public function __construct(string $name)
40
    {
41
        $this->name = $name;
42
    }
43
44
    /**
45
     * {@inheritDoc}
46
     *
47
     * @return static
48
     */
49
    public function nullable(): self
50
    {
51
        $this->isNullable = true;
52
        return $this;
53
    }
54
55
    /**
56
     * {@inheritDoc}
57
     *
58
     * @return static
59
     */
60
    public function truthy(): self
61
    {
62
        return $this->check(new Check(
63
            CheckName::TRUTHY,
64
            CheckErrorName::NOT_TRUTHY,
65
            fn ($value) => boolval($value),
66
        ));
67
    }
68
69
    /**
70
     * {@inheritDoc}
71
     *
72
     * @return static
73
     */
74
    public function falsy(): self
75
    {
76
        return $this->check(new Check(
77
            CheckName::FALSY,
78
            CheckErrorName::NOT_FALSY,
79
            fn ($value) => !boolval($value),
80
        ));
81
    }
82
83
    /**
84
     * {@inheritDoc}
85
     *
86
     * @return static
87
     */
88
    public function equal($value): self
89
    {
90
        return $this->check(new Check(
91
            CheckName::EQUEAL,
92
            CheckErrorName::NOT_EQUEAL,
93
            fn ($val) => $value == $val,
94
            ['value' => $value]
95
        ));
96
    }
97
98
    /**
99
     * {@inheritDoc}
100
     *
101
     * @return static
102
     */
103
    public function same($value): self
104
    {
105
        return $this->check(new Check(
106
            CheckName::SAME,
107
            CheckErrorName::NOT_SAME,
108
            fn ($val) => $value === $val,
109
            ['value' => $value]
110
        ));
111
    }
112
113
    /**
114
     * {@inheritDoc}
115
     *
116
     * @return static
117
     */
118
    public function check(CheckInterface $check, bool $isInterrupting = false): self
119
    {
120
        $this->checks[] = new CheckWrapper($check, $isInterrupting);
121
        return $this;
122
    }
123
124
    /**
125
     * {@inheritDoc}
126
     *
127
     * @return static
128
     */
129
    public function stopOnViolation(): self
130
    {
131
        return $this->check(new RetrospectiveCheck(), true);
132
    }
133
134
    /**
135
     * {@inheritDoc}
136
     *
137
     * @return static
138
     */
139
    public function stopOnAnyPriorViolation(): self
140
    {
141
        foreach ($this->checks as $check) {
142
            $check->setInterrupting();
143
        }
144
        return $this;
145
    }
146
147
    /**
148
     * {@inheritDoc}
149
     */
150 68
    public function validate($value): void
151
    {
152 68
        $this->execute($value);
153
    }
154
155
    /**
156
     * {@inheritDoc}
157
     */
158
    public function getName(): string
159
    {
160
        return $this->name;
161
    }
162
163
    /**
164
     * {@inheritDoc}
165
     */
166
    public function isValid($value): bool
167
    {
168
        try {
169
            $this->validate($value);
170
            return true;
171
        } catch (ValidationError $e) {
172
            return false;
173
        }
174
    }
175
176
    /**
177
     * {@inheritDoc}
178
     */
179 68
    protected function execute($value): ValidationResultInterface
180
    {
181 68
        $result = parent::execute($value);
182 68
        if ($result->preventNextChecks()) {
183
            return $result;
184
        }
185
186 68
        if ($value === null) {
187 8
            if ($this->isNullable) {
188 5
                return new ValidationSuccessResult(true);
189
            }
190
191 3
            throw new ValidationError($this->name, $value, [[CheckErrorName::NULL, []]]);
192
        }
193
194 65
        $errors = [];
195
196 65
        foreach ($this->checks as $check) {
197
            try {
198 64
                $check->getCheck()->execute($value, $errors);
199 39
            } catch (CheckError $e) {
200 39
                if (!($check->getCheck() instanceof UtilityCheckInterface)) {
201 39
                    $errors[] = $e;
202
                }
203
204 39
                if ($check->isInterrupting()) {
205 15
                    throw ValidationError::fromCheckErrors($this->name, $value, $errors);
206
                }
207
            }
208
        }
209
210 57
        if (\count($errors) > 0) {
211 27
            throw ValidationError::fromCheckErrors($this->name, $value, $errors);
212
        }
213
214 33
        return new ValidationSuccessResult(false);
215
    }
216
}
217