Passed
Pull Request — master (#428)
by Sergei
02:38
created

RulesNormalizer::normalizeList()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Helper;
6
7
use InvalidArgumentException;
8
use ReflectionException;
9
use Yiisoft\Validator\Rule\Callback;
10
use Yiisoft\Validator\RuleInterface;
11
use Yiisoft\Validator\RulesProvider\AttributesRulesProvider;
12
use Yiisoft\Validator\RulesProviderInterface;
13
use Yiisoft\Validator\SkipOnEmptyInterface;
14
use Yiisoft\Validator\ValidatorInterface;
15
16
use function is_callable;
17
use function is_int;
18
use function is_string;
19
20
/**
21
 * @psalm-import-type RulesType from ValidatorInterface
22
 */
23
final class RulesNormalizer
24
{
25
    /**
26
     * @psalm-param RulesType $rules
27
     *
28
     * @throws InvalidArgumentException
29
     * @throws ReflectionException
30 824
     *
31
     * @return iterable<int|string, iterable<int, RuleInterface>>
32
     */
33
    public static function normalize(
34
        callable|iterable|object|string|null $rules,
35 824
        mixed $data = null,
36
        ?callable $defaultSkipOnEmptyCriteria = null,
37 823
    ): iterable {
38
        $rules = self::prepareRulesArray($rules, $data);
39
40
        $normalizedRules = [];
41
42
        /**
43 823
         * @var mixed $attribute
44 811
         * @var mixed $attributeRules
45 1
         */
46 1
        foreach ($rules as $attribute => $attributeRules) {
47
            if (!is_int($attribute) && !is_string($attribute)) {
48 1
                throw new InvalidArgumentException(
49
                    sprintf(
50
                        'An attribute can only have an integer or a string type. %s given.',
51
                        get_debug_type($attribute),
52
                    )
53 810
                );
54 810
            }
55
56
            $normalizedRules[$attribute] = self::normalizeRulesGenerator(
57
                is_iterable($attributeRules) ? $attributeRules : [$attributeRules],
58
                $defaultSkipOnEmptyCriteria
59 822
            );
60
        }
61
62
        return $normalizedRules;
63
    }
64
65
    /**
66
     * @throws InvalidArgumentException
67 824
     *
68
     * @return iterable<int, RuleInterface>
69
     */
70
    public static function normalizeList(iterable|callable|RuleInterface $rules): iterable
71 824
    {
72 34
        return self::normalizeRulesGenerator(
73 30
            is_iterable($rules) ? $rules : [$rules]
0 ignored issues
show
Bug introduced by
It seems like is_iterable($rules) ? $rules : array($rules) can also be of type Yiisoft\Validator\RuleInterface and callable; however, parameter $rules of Yiisoft\Validator\Helper...rmalizeRulesGenerator() does only seem to accept iterable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

73
            /** @scrutinizer ignore-type */ is_iterable($rules) ? $rules : [$rules]
Loading history...
74 34
        );
75
    }
76
77 794
    /**
78 2
     * @psalm-param RulesType $rules
79
     *
80
     * @throws ReflectionException
81 792
     */
82 1
    private static function prepareRulesArray(
83
        callable|iterable|object|string|null $rules,
84
        mixed $data,
85
    ): iterable {
86 791
        if ($rules === null) {
87 790
            return $data instanceof RulesProviderInterface
88
                ? $data->getRules()
89
                : [];
90 1
        }
91
92
        if ($rules instanceof RulesProviderInterface) {
93
            return $rules->getRules();
94
        }
95
96
        if ($rules instanceof RuleInterface || is_callable($rules)) {
97
            return [$rules];
98 810
        }
99
100
        if (is_iterable($rules)) {
101 810
            return $rules;
102 810
        }
103
104
        return (new AttributesRulesProvider($rules))->getRules();
0 ignored issues
show
Bug introduced by
It seems like $rules can also be of type callable and iterable; however, parameter $source of Yiisoft\Validator\RulesP...Provider::__construct() does only seem to accept object|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
        return (new AttributesRulesProvider(/** @scrutinizer ignore-type */ $rules))->getRules();
Loading history...
105
    }
106
107
    /**
108
     * @throws InvalidArgumentException
109 810
     *
110
     * @return iterable<int, RuleInterface>
111 810
     */
112 4
    private static function normalizeRulesGenerator(
113
        iterable $rules,
114
        ?callable $defaultSkipOnEmptyCriteria = null
115 809
    ): iterable {
116 1
        /** @var mixed $rule */
117 1
        foreach ($rules as $rule) {
118
            yield self::normalizeRule($rule, $defaultSkipOnEmptyCriteria);
119
        }
120 1
    }
121
122
    /**
123
     * @throws InvalidArgumentException
124
     */
125 809
    private static function normalizeRule(mixed $rule, ?callable $defaultSkipOnEmptyCriteria): RuleInterface
126 722
    {
127
        if (is_callable($rule)) {
128
            return new Callback($rule);
129 809
        }
130
131
        if (!$rule instanceof RuleInterface) {
132
            throw new InvalidArgumentException(
133
                sprintf(
134
                    'Rule should be either an instance of %s or a callable, %s given.',
135
                    RuleInterface::class,
136
                    get_debug_type($rule)
137
                )
138
            );
139
        }
140
141
        if (
142
            $defaultSkipOnEmptyCriteria !== null
143
            && $rule instanceof SkipOnEmptyInterface
144
            && $rule->getSkipOnEmpty() === null
145
        ) {
146
            $rule = $rule->skipOnEmpty($defaultSkipOnEmptyCriteria);
147
        }
148
149
        return $rule;
150
    }
151
}
152