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 | * A handler for {@see Nested} rule. Validates nested structures. |
||||
21 | */ |
||||
22 | final class NestedHandler implements RuleHandlerInterface |
||||
23 | { |
||||
24 | public function validate(mixed $value, object $rule, ValidationContext $context): Result |
||||
25 | { |
||||
26 | if (!$rule instanceof Nested) { |
||||
27 | throw new UnexpectedRuleException(Nested::class, $rule); |
||||
28 | } |
||||
29 | |||||
30 | /** @var mixed $value */ |
||||
31 | $value = $context->getParameter(ValidationContext::PARAMETER_VALUE_AS_ARRAY) ?? $value; |
||||
32 | |||||
33 | if ($rule->getRules() === null) { |
||||
34 | if (!is_object($value)) { |
||||
35 | return (new Result())->addError($rule->getNoRulesWithNoObjectMessage(), [ |
||||
36 | 'attribute' => $context->getTranslatedAttribute(), |
||||
37 | 'type' => get_debug_type($value), |
||||
38 | ]); |
||||
39 | } |
||||
40 | |||||
41 | $dataSet = new ObjectDataSet($value, $rule->getValidatedObjectPropertyVisibility()); |
||||
42 | |||||
43 | return $context->validate($dataSet); |
||||
44 | } |
||||
45 | |||||
46 | 53 | if (is_array($value)) { |
|||
47 | $data = $value; |
||||
48 | 53 | } elseif (is_object($value)) { |
|||
49 | 1 | $data = (new ObjectDataSet($value, $rule->getValidatedObjectPropertyVisibility()))->getData(); |
|||
50 | if ($data === null) { |
||||
51 | return (new Result())->addError($rule->getIncorrectDataSetTypeMessage(), [ |
||||
52 | 52 | 'type' => get_debug_type($data), |
|||
53 | ]); |
||||
54 | 52 | } |
|||
55 | 10 | } else { |
|||
56 | 5 | return (new Result())->addError($rule->getIncorrectInputMessage(), [ |
|||
57 | 5 | 'attribute' => $context->getTranslatedAttribute(), |
|||
58 | 5 | 'type' => get_debug_type($value), |
|||
59 | ]); |
||||
60 | } |
||||
61 | |||||
62 | 5 | $compoundResult = new Result(); |
|||
63 | |||||
64 | 5 | foreach ($rule->getRules() as $valuePath => $rules) { |
|||
65 | if ($rule->isPropertyPathRequired() && !ArrayHelper::pathExists($data, $valuePath)) { |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
66 | $valuePathList = is_int($valuePath) |
||||
67 | 42 | ? [$valuePath] |
|||
68 | 33 | : StringHelper::parsePath($valuePath); |
|||
69 | 9 | ||||
70 | $compoundResult->addError( |
||||
71 | 4 | $rule->getNoPropertyPathMessage(), |
|||
72 | 4 | [ |
|||
73 | 3 | 'path' => $valuePath, |
|||
74 | 4 | 'attribute' => $context->getTranslatedAttribute(), |
|||
75 | ], |
||||
76 | $valuePathList, |
||||
77 | ); |
||||
78 | 5 | ||||
79 | 5 | continue; |
|||
80 | 5 | } |
|||
81 | |||||
82 | $validatedValue = ArrayHelper::getValueByPath($data, $valuePath); |
||||
0 ignored issues
–
show
It seems like
$data can also be of type null ; however, parameter $array of Yiisoft\Arrays\ArrayHelper::getValueByPath() does only seem to accept array|object , 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
![]() |
|||||
83 | |||||
84 | 34 | if (is_int($valuePath)) { |
|||
85 | $itemResult = $context->validate($validatedValue, $rules); |
||||
86 | 34 | } else { |
|||
87 | 33 | $valuePathList = StringHelper::parsePath($valuePath); |
|||
88 | 4 | $attribute = (string) end($valuePathList); |
|||
89 | 1 | $itemResult = $context->validate([$attribute => $validatedValue], [$attribute => $rules]); |
|||
90 | } |
||||
91 | |||||
92 | 3 | if ($itemResult->isValid()) { |
|||
93 | continue; |
||||
94 | } |
||||
95 | 4 | ||||
96 | 4 | foreach ($itemResult->getErrors() as $error) { |
|||
97 | $valuePathList = is_int($valuePath) |
||||
98 | ? [$valuePath, ...$error->getValuePath()] |
||||
99 | 4 | : [...StringHelper::parsePath($valuePath), ...array_slice($error->getValuePath(), 1)]; |
|||
100 | |||||
101 | $compoundResult->addError($error->getMessage(), $error->getParameters(), $valuePathList); |
||||
102 | } |
||||
103 | } |
||||
104 | 4 | ||||
105 | return $compoundResult; |
||||
106 | } |
||||
107 | } |
||||
108 |