Passed
Pull Request — master (#151)
by
unknown
02:41
created

Rules::asArray()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

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