Passed
Push — master ( 17adcb...9acb8c )
by Smoren
12:18
created

Rule::execute()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 33
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 8.0109

Importance

Changes 0
Metric Value
eloc 18
c 0
b 0
f 0
dl 0
loc 33
ccs 17
cts 18
cp 0.9444
rs 8.4444
cc 8
nc 10
nop 1
crap 8.0109
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Smoren\Validator\Rules;
6
7
use Smoren\Validator\Exceptions\CheckError;
8
use Smoren\Validator\Exceptions\ValidationError;
9
use Smoren\Validator\Interfaces\CheckInterface;
10
use Smoren\Validator\Interfaces\RuleInterface;
11
use Smoren\Validator\Interfaces\ExecutionResultInterface;
12
use Smoren\Validator\Structs\Check;
13
use Smoren\Validator\Structs\ExecutionResult;
14
use Smoren\Validator\Structs\RetrospectiveCheck;
15
16
class Rule extends BaseRule implements RuleInterface
17
{
18
    public const ERROR_NULL = 'null';
19
    public const ERROR_NOT_TRUTHY = 'not_truthy';
20
    public const ERROR_NOT_FALSY = 'not_falsy';
21
22
    /**
23
     * @var array<CheckInterface>
24
     */
25
    protected array $checks = [];
26
27
    /**
28
     * @var bool
29
     */
30
    protected bool $isNullable = false;
31
32
    /**
33
     * {@inheritDoc}
34
     *
35
     * @return static
36
     */
37
    public function nullable(): self
38
    {
39
        $this->isNullable = true;
40
        return $this;
41
    }
42
43
    /**
44
     * {@inheritDoc}
45
     *
46
     * @return static
47
     */
48
    public function truthy(): self
49
    {
50
        return $this->addCheck(new Check(
51
            self::ERROR_NOT_TRUTHY,
52
            fn ($value) => boolval($value),
53
        ));
54
    }
55
56
    /**
57
     * {@inheritDoc}
58
     *
59
     * @return static
60
     */
61
    public function falsy(): self
62
    {
63
        return $this->addCheck(new Check(
64
            self::ERROR_NOT_FALSY,
65
            fn ($value) => !boolval($value),
66
        ));
67
    }
68
69
    /**
70
     * {@inheritDoc}
71
     *
72
     * @return static
73
     */
74 2
    public function addCheck(CheckInterface $check): self
75
    {
76 2
        $this->checks[] = $check;
77 2
        return $this;
78
    }
79
80
    /**
81
     * {@inheritDoc}
82
     *
83
     * @return static
84
     */
85
    public function check(string $name, callable $predicate, array $params = [], bool $isInterrupting = false): self
86
    {
87
        return $this->addCheck(new Check($name, $predicate, $params, $isInterrupting));
88
    }
89
90
    /**
91
     * {@inheritDoc}
92
     *
93
     * @return static
94
     */
95
    public function stopOnViolation(): self
96
    {
97
        return $this->addCheck(new RetrospectiveCheck());
98
    }
99
100
    /**
101
     * {@inheritDoc}
102
     *
103
     * @return static
104
     */
105
    public function stopOnAnyPriorViolation(): self
106
    {
107
        foreach ($this->checks as $check) {
108
            $check->setInterrupting();
109
        }
110
        return $this;
111
    }
112
113
    /**
114
     * {@inheritDoc}
115
     */
116 61
    protected function execute($value): ExecutionResultInterface
117
    {
118 61
        $result = parent::execute($value);
119 61
        if ($result->areChecksSufficient()) {
120
            return $result;
121
        }
122
123 61
        if ($value === null) {
124 8
            if ($this->isNullable) {
125 5
                return new ExecutionResult(true);
126
            }
127
128 3
            throw new ValidationError($value, [[self::ERROR_NULL, []]]);
129
        }
130
131 58
        $errors = [];
132
133 58
        foreach ($this->checks as $check) {
134
            try {
135 57
                $check->execute($value, $errors);
136 35
            } catch (CheckError $e) {
137 35
                $errors[] = $e;
138 35
                if ($check->isInterrupting()) {
139 10
                    throw ValidationError::fromCheckErrors($value, $errors);
140
                }
141
            }
142
        }
143
144 51
        if (\count($errors) > 0) {
145 24
            throw ValidationError::fromCheckErrors($value, $errors);
146
        }
147
148 30
        return new ExecutionResult(false);
149
    }
150
}
151