Issues (138)

src/Rule/NestedHandler.php (2 issues)

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
It seems like $data can also be of type null; however, parameter $array of Yiisoft\Arrays\ArrayHelper::pathExists() 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

65
            if ($rule->isPropertyPathRequired() && !ArrayHelper::pathExists(/** @scrutinizer ignore-type */ $data, $valuePath)) {
Loading history...
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 ignore-type  annotation

82
            $validatedValue = ArrayHelper::getValueByPath(/** @scrutinizer ignore-type */ $data, $valuePath);
Loading history...
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