Passed
Pull Request — master (#151)
by
unknown
12:59
created

Rules::add()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.072

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 5
cp 0.8
crap 3.072
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator;
6
7
use InvalidArgumentException;
8
use Yiisoft\Arrays\ArrayHelper;
9
use Yiisoft\Validator\Rule\Callback;
10
use function is_callable;
11
12
/**
13
 * Rules represents multiple rules for a single value.
14
 */
15
final class Rules
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 34
    public function __construct(iterable $rules = [])
27
    {
28 34
        foreach ($rules as $rule) {
29 33
            $this->add($rule);
30
        }
31 34
    }
32
33
    /**
34
     * @param callable|RuleInterface $rule
35
     */
36 34
    public function add($rule): void
37
    {
38 34
        $rule = $this->normalizeRule($rule);
39 34
        if ($this->formatter !== null && $rule instanceof FormattableRuleInterface) {
40
            $rule = $rule->withFormatter($this->formatter);
41
        }
42 34
        $this->rules[] = $rule;
43 34
    }
44
45 28
    public function validate($value, ValidationContext $context = null): Result
46
    {
47 28
        $context = $context ?? new ValidationContext();
48 28
        $compoundResult = new Result();
49
50 28
        foreach ($this->rules as $rule) {
51 28
            $ruleResult = $rule->validate($value, $context);
52 28
            if ($ruleResult->isValid()) {
53 23
                continue;
54
            }
55
56 17
            $context->setParameter(self::PARAMETER_PREVIOUS_RULES_ERRORED, true);
57
58 17
            foreach ($ruleResult->getErrors() as $key => $message) {
59 17
                $compoundResult->addError($message, $key);
60
            }
61
        }
62
63 28
        return $compoundResult;
64
    }
65
66 34
    private function normalizeRule($rule): RuleInterface
67
    {
68 34
        if (is_callable($rule)) {
69 4
            $rule = Callback::rule($rule);
70
        }
71
72 34
        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 34
        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
            }
103
        }
104 5
        return $arrayOfRules;
105
    }
106
107 1
    private function addFormatterToRules(?FormatterInterface $formatter): void
108
    {
109 1
        foreach ($this->rules as &$rule) {
110 1
            if ($rule instanceof FormattableRuleInterface) {
111 1
                $rule = $rule->withFormatter($formatter);
112
            }
113
        }
114 1
    }
115
}
116