Passed
Pull Request — master (#222)
by Rustam
02:29
created

Nested::validateValue()   B

Complexity

Conditions 11
Paths 7

Size

Total Lines 39
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 11

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 23
nc 7
nop 2
dl 0
loc 39
ccs 24
cts 24
cp 1
crap 11
rs 7.3166
c 1
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Attribute;
8
use Closure;
9
use InvalidArgumentException;
10
use Traversable;
11
use Yiisoft\Validator\Rule\Trait\RuleNameTrait;
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_TRAIT, expecting T_STRING or '{' on line 11 at column 27
Loading history...
12
use Yiisoft\Validator\Rule\Trait\HandlerClassNameTrait;
13
use Yiisoft\Validator\ParametrizedRuleInterface;
14
use Yiisoft\Validator\RuleInterface;
15
use Yiisoft\Validator\RulesDumper;
16
use function is_array;
17
18
/**
19
 * Can be used for validation of nested structures.
20
 *
21
 * For example, we have an inbound request with the following structure:
22
 *
23
 * ```php
24
 * $request = [
25
 *     'author' => [
26
 *         'name' => 'Dmitry',
27
 *         'age' => 18,
28
 *     ],
29
 * ];
30
 * ```
31
 *
32
 * So to make validation we can configure it like this:
33
 *
34
 * ```php
35
 * $rule = new Nested([
36
 *     'author' => new Nested([
37
 *         'name' => [new HasLength(min: 3)],
38
 *         'age' => [new Number(min: 18)],
39
 *     )];
40
 * ]);
41
 * ```
42
 */
43
#[Attribute(Attribute::TARGET_PROPERTY)]
44
final class Nested implements ParametrizedRuleInterface
45
{
46
    use HandlerClassNameTrait;
47
    use RuleNameTrait;
48
49 3
    public function __construct(
50
        /**
51
         * @var RuleInterface[][]
52
         */
53
        private iterable $rules = [],
54
        private bool $errorWhenPropertyPathIsNotFound = false,
55
        private string $propertyPathIsNotFoundMessage = 'Property path "{path}" is not found.',
56
        private bool $skipOnEmpty = false,
57
        private bool $skipOnError = false,
58
        private ?Closure $when = null,
59
    ) {
60 3
        $rules = $rules instanceof Traversable ? iterator_to_array($rules) : $rules;
61 3
        if (empty($rules)) {
62 1
            throw new InvalidArgumentException('Rules must not be empty.');
63
        }
64
65 2
        if ($this->checkRules($rules)) {
66 1
            $message = sprintf('Each rule should be an instance of %s.', RuleInterface::class);
67 1
            throw new InvalidArgumentException($message);
68
        }
69
70 1
        $this->rules = $rules;
71
    }
72
73
    /**
74
     * @return iterable
75
     */
76 10
    public function getRules(): iterable
77
    {
78 10
        return $this->rules;
79
    }
80
81
    /**
82
     * @return bool
83
     */
84 10
    public function isErrorWhenPropertyPathIsNotFound(): bool
85
    {
86 10
        return $this->errorWhenPropertyPathIsNotFound;
87
    }
88
89
    /**
90
     * @return string
91
     */
92 2
    public function getPropertyPathIsNotFoundMessage(): string
93
    {
94 2
        return $this->propertyPathIsNotFoundMessage;
95
    }
96
97
    /**
98
     * @return bool
99
     */
100
    public function isSkipOnEmpty(): bool
101
    {
102
        return $this->skipOnEmpty;
103
    }
104
105
    /**
106
     * @return bool
107
     */
108
    public function isSkipOnError(): bool
109
    {
110
        return $this->skipOnError;
111
    }
112
113
    /**
114
     * @return Closure|null
115
     */
116
    public function getWhen(): ?Closure
117
    {
118
        return $this->when;
119
    }
120
121 2
    private function checkRules(array $rules): bool
122
    {
123 2
        return array_reduce(
124
            $rules,
125 2
            function (bool $carry, $rule) {
126 2
                return $carry || (is_array($rule) ? $this->checkRules($rule) : !$rule instanceof RuleInterface);
127
            },
128
            false
129
        );
130
    }
131
132 4
    public function getOptions(): array
133
    {
134 4
        return (new RulesDumper())->asArray($this->rules);
135
    }
136
}
137