Test Failed
Pull Request — master (#364)
by
unknown
03:02
created

NestedHandler::validate()   D

Complexity

Conditions 20
Paths 95

Size

Total Lines 96
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 20

Importance

Changes 8
Bugs 1 Features 0
Metric Value
eloc 54
c 8
b 1
f 0
dl 0
loc 96
ccs 43
cts 43
cp 1
rs 4.1666
cc 20
nc 95
nop 3
crap 20

How to fix   Long Method    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 Yiisoft\Arrays\ArrayHelper;
8
use Yiisoft\Strings\StringHelper;
9
use Yiisoft\Validator\DataSet\ObjectDataSet;
10
use Yiisoft\Validator\Exception\UnexpectedRuleException;
11
use Yiisoft\Validator\Result;
12
use Yiisoft\Validator\RuleHandlerInterface;
13
use Yiisoft\Validator\ValidationContext;
14
15
use function is_array;
16
use function is_int;
17
use function is_object;
18
19
/**
20
 * Can be used for validation of nested structures.
21
 *
22
 * For example, we have an inbound request with the following structure:
23
 *
24
 * ```php
25
 * $request = [
26
 *     'author' => [
27
 *         'name' => 'Dmitry',
28
 *         'age' => 18,
29
 *     ],
30
 * ];
31
 * ```
32
 *
33
 * So to make validation we can configure it like this:
34
 *
35
 * ```php
36
 * $rule = new Nested([
37
 *     'author' => new Nested([
38
 *         'name' => [new HasLength(min: 3)],
39
 *         'age' => [new Number(min: 18)],
40
 *     )];
41
 * ]);
42
 * ```
43
 */
44
final class NestedHandler implements RuleHandlerInterface
45
{
46
    public function validate(mixed $value, object $rule, ValidationContext $context): Result
47 39
    {
48
        if (!$rule instanceof Nested) {
49 39
            throw new UnexpectedRuleException(Nested::class, $rule);
50 1
        }
51
52
        $compoundResult = new Result();
53 38
54 8
        if ($rule->getRules() === null) {
55 3
            if (!is_object($value)) {
56 3
                return $compoundResult->addError($rule->getNoRulesWithNoObjectMessage(), [
57
                    'attribute' => $context->getAttribute(),
58 3
                    'type' => get_debug_type($value),
59
                ]);
60
            }
61
62
            $dataSet = new ObjectDataSet($value, $rule->getPropertyVisibility());
63 5
64
            return $context->getValidator()->validate($dataSet);
65 5
        }
66
67
        if (is_array($value)) {
68 30
            $data = $value;
69 27
        } elseif (is_object($value)) {
70 3
            /** @var mixed $data */
71 1
            $data = (new ObjectDataSet($value, $rule->getPropertyVisibility()))->getData();
72
            if (!is_array($data) && !is_object($data)) {
73 2
                return $compoundResult->addError($rule->getIncorrectDataSetTypeMessage(), [
74
                    'attribute' => $context->getAttribute(),
75 2
                    'type' => get_debug_type($data),
76
                ]);
77
            }
78 2
        } else {
79
            return $compoundResult->addError($rule->getIncorrectInputMessage(), [
80
                'attribute' => $context->getAttribute(),
81
                'type' => get_debug_type($value),
82
            ]);
83
        }
84 28
85 28
        $results = [];
86 28
        /** @var int|string $valuePath */
87 27
        foreach ($rule->getRules() as $valuePath => $rules) {
88
            if (is_array($data) && $rule->getRequirePropertyPath() && !ArrayHelper::pathExists($data, $valuePath)) {
89
                if (is_int($valuePath)) {
90
                    $valuePathList = [$valuePath];
91 3
                } else {
92 3
                    /** @var list<string> $valuePathList */
93
                    $valuePathList = StringHelper::parsePath($valuePath);
94 3
                }
95 3
96
                $compoundResult->addError(
97 3
                    $rule->getNoPropertyPathMessage(),
98
                    [
99
                        'path' => $valuePath,
100 3
                        'attribute' => $context->getAttribute(),
101
                    ],
102
                    $valuePathList,
103 24
                );
104 24
105
                continue;
106 24
            }
107
108 24
            /** @var mixed $validatedValue */
109 9
            $validatedValue = ArrayHelper::getValueByPath($data, $valuePath);
110
            $rules = is_iterable($rules) ? $rules : [$rules];
111
112 19
            $itemResult = $context->getValidator()->validate($validatedValue, $rules);
113
            if ($itemResult->isValid()) {
114 19
                continue;
115 19
            }
116 19
117 8
            $result = new Result();
118
            foreach ($itemResult->getErrors() as $error) {
119
                if (is_int($valuePath)) {
120
                    $valuePathList = [$valuePath];
121
                } else {
122 19
                    /** @var list<string> $valuePathList */
123
                    $valuePathList = StringHelper::parsePath($valuePath);
124 19
                }
125
126
                if (!empty($valuePathList)) {
127 28
                    array_push($valuePathList, ...$error->getValuePath());
0 ignored issues
show
Bug introduced by
It seems like $valuePathList can also be of type Yiisoft\Validator\Rule\list; however, parameter $array of array_push() does only seem to accept array, 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

127
                    array_push(/** @scrutinizer ignore-type */ $valuePathList, ...$error->getValuePath());
Loading history...
128 19
                }
129 19
130
                $result->addError($error->getMessage(), $error->getParameters(), $valuePathList);
131
            }
132
            $results[] = $result;
133 28
        }
134
135
        foreach ($results as $result) {
136
            foreach ($result->getErrors() as $error) {
137
                $compoundResult->addError($error->getMessage(), $error->getParameters(), $error->getValuePath());
138
            }
139
        }
140
141
        return $compoundResult;
142
    }
143
}
144