Passed
Push — master ( 295792...3cace9 )
by Smoren
03:09
created

MixedRule   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 194
Duplicated Lines 0 %

Test Coverage

Coverage 88.24%

Importance

Changes 0
Metric Value
wmc 23
eloc 57
dl 0
loc 194
ccs 60
cts 68
cp 0.8824
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A equal() 0 7 1
A falsy() 0 6 1
A stopOnViolation() 0 3 1
A stopOnAnyPriorViolation() 0 6 2
A __construct() 0 3 1
A getName() 0 3 1
A validate() 0 3 1
A same() 0 7 1
B execute() 0 36 9
A nullable() 0 4 1
A truthy() 0 6 1
A isValid() 0 7 2
A check() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Smoren\Validator\Rules;
6
7
use Smoren\Validator\Checks\RetrospectiveCheck;
8
use Smoren\Validator\Exceptions\CheckError;
9
use Smoren\Validator\Exceptions\ValidationError;
10
use Smoren\Validator\Factories\CheckBuilder;
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\CheckName;
17
use Smoren\Validator\Structs\CheckWrapper;
18
use Smoren\Validator\Structs\Param;
19
use Smoren\Validator\Structs\ValidationSuccessResult;
20
21
class MixedRule 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 221
    public function __construct(string $name)
40
    {
41 221
        $this->name = $name;
42
    }
43
44
    /**
45
     * {@inheritDoc}
46
     *
47
     * @return static
48
     */
49 23
    public function nullable(): self
50
    {
51 23
        $this->isNullable = true;
52 23
        return $this;
53
    }
54
55
    /**
56
     * {@inheritDoc}
57
     *
58
     * @return static
59
     */
60 4
    public function truthy(): self
61
    {
62 4
        return $this->check(
63 4
            CheckBuilder::create(CheckName::TRUTHY)
64 4
                ->withPredicate(fn ($value) => \boolval($value))
65 4
                ->build()
66 4
        );
67
    }
68
69
    /**
70
     * {@inheritDoc}
71
     *
72
     * @return static
73
     */
74 4
    public function falsy(): self
75
    {
76 4
        return $this->check(
77 4
            CheckBuilder::create(CheckName::FALSY)
78 4
                ->withPredicate(fn ($value) => !\boolval($value))
79 4
                ->build()
80 4
        );
81
    }
82
83
    /**
84
     * {@inheritDoc}
85
     *
86
     * @return static
87
     */
88 11
    public function equal($value): self
89
    {
90 11
        return $this->check(
91 11
            CheckBuilder::create(CheckName::EQUAL)
92 11
                ->withPredicate(fn ($actual, $expected) => $actual == $expected)
93 11
                ->withParams([Param::EXPECTED => $value])
94 11
                ->build()
95 11
        );
96
    }
97
98
    /**
99
     * {@inheritDoc}
100
     *
101
     * @return static
102
     */
103 6
    public function same($value): self
104
    {
105 6
        return $this->check(
106 6
            CheckBuilder::create(CheckName::SAME)
107 6
                ->withPredicate(fn ($actual, $expected) => $actual === $expected)
108 6
                ->withParams([Param::EXPECTED => $value])
109 6
                ->build()
110 6
        );
111
    }
112
113
    /**
114
     * {@inheritDoc}
115
     *
116
     * @return static
117
     */
118 217
    public function check(CheckInterface $check, bool $isInterrupting = false): self
119
    {
120 217
        $this->checks[] = new CheckWrapper($check, $isInterrupting);
121 217
        return $this;
122
    }
123
124
    /**
125
     * {@inheritDoc}
126
     *
127
     * @return static
128
     */
129 3
    public function stopOnViolation(): self
130
    {
131 3
        return $this->check(new RetrospectiveCheck(), true);
132
    }
133
134
    /**
135
     * {@inheritDoc}
136
     *
137
     * @return static
138
     */
139 2
    public function stopOnAnyPriorViolation(): self
140
    {
141 2
        foreach ($this->checks as $check) {
142 2
            $check->setInterrupting();
143
        }
144 2
        return $this;
145
    }
146
147
    /**
148
     * {@inheritDoc}
149
     */
150 221
    public function validate($value): void
151
    {
152 221
        $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 221
    protected function execute($value): ValidationResultInterface
180
    {
181 221
        $result = parent::execute($value);
182 221
        if ($result->preventNextChecks()) {
183
            return $result;
184
        }
185
186 221
        if ($value === null) {
187 20
            if ($this->isNullable) {
188 12
                return new ValidationSuccessResult(true);
189
            }
190
191 8
            throw new ValidationError($this->name, $value, [[CheckName::NOT_NULL, []]]);
192
        }
193
194 213
        $errors = [];
195
196 213
        foreach ($this->checks as $check) {
197
            try {
198 211
                $check->getCheck()->execute($value, $errors);
199 115
            } catch (CheckError $e) {
200 115
                if (!($check->getCheck() instanceof UtilityCheckInterface)) {
201 115
                    $errors[] = $e;
202
                }
203
204 115
                if ($check->isInterrupting()) {
205 27
                    throw ValidationError::fromCheckErrors($this->name, $value, $errors);
206
                }
207
            }
208
        }
209
210 197
        if (\count($errors) > 0) {
211 95
            throw ValidationError::fromCheckErrors($this->name, $value, $errors);
212
        }
213
214 112
        return new ValidationSuccessResult(false);
215
    }
216
}
217