Passed
Pull Request — master (#364)
by
unknown
03:15
created

NestedHandler::validate()   D

Complexity

Conditions 20
Paths 95

Size

Total Lines 96
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 51
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 51
cts 51
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 44
    public function validate(mixed $value, object $rule, ValidationContext $context): Result
47
    {
48 44
        if (!$rule instanceof Nested) {
49 1
            throw new UnexpectedRuleException(Nested::class, $rule);
50
        }
51
52 43
        $compoundResult = new Result();
53
54 43
        if ($rule->getRules() === null) {
55 8
            if (!is_object($value)) {
56 3
                return $compoundResult->addError($rule->getNoRulesWithNoObjectMessage(), [
57 3
                    'attribute' => $context->getAttribute(),
58 3
                    'type' => get_debug_type($value),
59
                ]);
60
            }
61
62 5
            $dataSet = new ObjectDataSet($value, $rule->getPropertyVisibility());
63
64 5
            return $context->getValidator()->validate($dataSet);
65
        }
66
67 35
        if (is_array($value)) {
68 31
            $data = $value;
69 4
        } elseif (is_object($value)) {
70
            /** @var mixed $data */
71 2
            $data = (new ObjectDataSet($value, $rule->getPropertyVisibility()))->getData();
72 2
            if (!is_array($data) && !is_object($data)) {
73 1
                return $compoundResult->addError($rule->getIncorrectDataSetTypeMessage(), [
74 1
                    'attribute' => $context->getAttribute(),
75 2
                    'type' => get_debug_type($data),
76
                ]);
77
            }
78
        } else {
79 2
            return $compoundResult->addError($rule->getIncorrectInputMessage(), [
80 2
                'attribute' => $context->getAttribute(),
81 2
                'type' => get_debug_type($value),
82
            ]);
83
        }
84
85 32
        $results = [];
86
        /** @var int|string $valuePath */
87 32
        foreach ($rule->getRules() as $valuePath => $rules) {
88 31
            if (is_array($data) && $rule->getRequirePropertyPath() && !ArrayHelper::pathExists($data, $valuePath)) {
89 4
                if (is_int($valuePath)) {
90 1
                    $valuePathList = [$valuePath];
91
                } else {
92
                    /** @var list<string> $valuePathList */
93 3
                    $valuePathList = StringHelper::parsePath($valuePath);
94
                }
95
96 4
                $compoundResult->addError(
97 4
                    $rule->getNoPropertyPathMessage(),
98
                    [
99 4
                        'path' => $valuePath,
100 4
                        'attribute' => $context->getAttribute(),
101
                    ],
102
                    $valuePathList,
103
                );
104
105 4
                continue;
106
            }
107
108
            /** @var mixed $validatedValue */
109 27
            $validatedValue = ArrayHelper::getValueByPath($data, $valuePath);
110 27
            $rules = is_iterable($rules) ? $rules : [$rules];
111
112 27
            $itemResult = $context->getValidator()->validate($validatedValue, $rules);
113 27
            if ($itemResult->isValid()) {
114 12
                continue;
115
            }
116
117 19
            $result = new Result();
118 19
            foreach ($itemResult->getErrors() as $error) {
119 19
                if (is_int($valuePath)) {
120 2
                    $valuePathList = [$valuePath];
121
                } else {
122
                    /** @var list<string> $valuePathList */
123 17
                    $valuePathList = StringHelper::parsePath($valuePath);
124
                }
125
126 19
                if (!empty($valuePathList)) {
127 19
                    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
                }
129
130 19
                $result->addError($error->getMessage(), $error->getParameters(), $valuePathList);
131
            }
132 19
            $results[] = $result;
133
        }
134
135 32
        foreach ($results as $result) {
136 19
            foreach ($result->getErrors() as $error) {
137 19
                $compoundResult->addError($error->getMessage(), $error->getParameters(), $error->getValuePath());
138
            }
139
        }
140
141 32
        return $compoundResult;
142
    }
143
}
144