Passed
Push — master ( 045fd3...30cbd8 )
by Alexander
02:53
created

RuleSet::addFormatterToRules()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

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