Passed
Pull Request — master (#175)
by Alexander
02:36
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 39
    public function __construct(iterable $rules = [])
27
    {
28 39
        foreach ($rules as $rule) {
29 38
            $this->add($rule);
30
        }
31
    }
32
33
    /**
34
     * @param callable|RuleInterface $rule
35
     */
36 39
    public function add($rule): void
37
    {
38 39
        $rule = $this->normalizeRule($rule);
39 39
        if ($this->formatter !== null && $rule instanceof FormattableRuleInterface) {
40
            $rule = $rule->withFormatter($this->formatter);
41
        }
42 39
        $this->rules[] = $rule;
43
    }
44
45 32
    public function validate($value, ValidationContext $context = null): Result
46
    {
47 32
        $context = $context ?? new ValidationContext();
48
49 32
        $compoundResult = new Result();
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 32
        return $compoundResult;
63
    }
64
65 39
    private function normalizeRule($rule): RuleInterface
66
    {
67 39
        if (is_callable($rule)) {
68 4
            $rule = Callback::rule($rule);
69
        }
70
71 39
        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 39
        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 6
    public function asArray(): array
96
    {
97 6
        $arrayOfRules = [];
98 6
        foreach ($this->rules as $rule) {
99 6
            if ($rule instanceof ParametrizedRuleInterface) {
100 6
                $arrayOfRules[] = array_merge([$rule->getName()], $rule->getOptions());
101
            } else {
102 1
                $arrayOfRules[] = [get_class($rule)];
103
            }
104
        }
105 6
        return $arrayOfRules;
106
    }
107
108 1
    private function addFormatterToRules(?FormatterInterface $formatter): void
109
    {
110 1
        foreach ($this->rules as &$rule) {
111 1
            if ($rule instanceof FormattableRuleInterface) {
112 1
                $rule = $rule->withFormatter($formatter);
113
            }
114
        }
115
    }
116
}
117