Passed
Push — master ( 72c1ff...1d076d )
by Alexander
02:24
created

RuleSet::normalizeRule()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.7898

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 1
dl 0
loc 15
ccs 5
cts 9
cp 0.5556
crap 3.7898
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator;
6
7
use InvalidArgumentException;
8
use Yiisoft\Validator\Rule\Callback;
9
use function is_callable;
10
11
/**
12
 * Rule set represents multiple rules for a single value.
13
 */
14
final class RuleSet
15
{
16
    public const PARAMETER_PREVIOUS_RULES_ERRORED = 'previousRulesErrored';
17
18
    private ?FormatterInterface $formatter = null;
19
20
    /**
21
     * @var RuleInterface[]
22
     */
23
    private array $rules = [];
24
25 37
    public function __construct(iterable $rules = [])
26
    {
27 37
        foreach ($rules as $rule) {
28 36
            $this->add($rule);
29
        }
30 37
    }
31
32
    /**
33
     * @param callable|RuleInterface $rule
34
     */
35 37
    public function add($rule): void
36
    {
37 37
        $rule = $this->normalizeRule($rule);
38 37
        if ($this->formatter !== null && $rule instanceof FormattableRuleInterface) {
39
            $rule = $rule->withFormatter($this->formatter);
40
        }
41 37
        $this->rules[] = $rule;
42 37
    }
43
44 31
    public function validate($value, ValidationContext $context = null): Result
45
    {
46 31
        $context = $context ?? new ValidationContext();
47 31
        $compoundResult = new Result();
48
49 31
        foreach ($this->rules as $rule) {
50 31
            $ruleResult = $rule->validate($value, $context);
51 31
            if ($ruleResult->isValid()) {
52 23
                continue;
53
            }
54
55 20
            $context->setParameter(self::PARAMETER_PREVIOUS_RULES_ERRORED, true);
56
57 20
            foreach ($ruleResult->getErrorObjects() as $error) {
58 20
                $compoundResult->addError($error->getMessage(), $error->getValuePath());
59
            }
60
        }
61
62 31
        return $compoundResult;
63
    }
64
65 37
    private function normalizeRule($rule): RuleInterface
66
    {
67 37
        if (is_callable($rule)) {
68 4
            $rule = Callback::rule($rule);
69
        }
70
71 37
        if (!$rule instanceof RuleInterface) {
72
            throw new InvalidArgumentException(sprintf(
73
                'Rule should be either an instance of %s or a callable, %s given.',
74
                RuleInterface::class,
75
                gettype($rule)
76
            ));
77
        }
78
79 37
        return $rule;
80
    }
81
82 1
    public function withFormatter(?FormatterInterface $formatter): self
83
    {
84 1
        $new = clone $this;
85 1
        $new->formatter = $formatter;
86 1
        $new->addFormatterToRules($formatter);
87 1
        return $new;
88
    }
89
90
    /**
91
     * Return rules as array.
92
     *
93
     * @return array
94
     */
95 5
    public function asArray(): array
96
    {
97 5
        $arrayOfRules = [];
98 5
        foreach ($this->rules as $rule) {
99 5
            if ($rule instanceof ParametrizedRuleInterface) {
100 5
                $arrayOfRules[] = array_merge([$rule->getName()], $rule->getOptions());
101
            }
102
        }
103 5
        return $arrayOfRules;
104
    }
105
106 1
    private function addFormatterToRules(?FormatterInterface $formatter): void
107
    {
108 1
        foreach ($this->rules as &$rule) {
109 1
            if ($rule instanceof FormattableRuleInterface) {
110 1
                $rule = $rule->withFormatter($formatter);
111
            }
112
        }
113 1
    }
114
}
115