Passed
Pull Request — master (#98)
by Alexander
04:56 queued 02:02
created

Nested::propertyPathIsNotFoundMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use InvalidArgumentException;
8
use Traversable;
9
use Yiisoft\Arrays\ArrayHelper;
10
use Yiisoft\Validator\DataSetInterface;
11
use Yiisoft\Validator\HasValidationErrorMessage;
12
use Yiisoft\Validator\Result;
13
use Yiisoft\Validator\Rule;
14
use Yiisoft\Validator\Rules;
15
16
/**
17
 * Each validator validates an array by checking each of its elements against a set of rules
18
 */
19
class Nested extends Rule
20
{
21
    use HasValidationErrorMessage;
22
23
    /**
24
     * @var Rule[][]
25
     */
26
    private iterable $rules;
27
28
    private bool $errorWhenPropertyPathIsNotFound = false;
29
    private string $propertyPathIsNotFoundMessage = 'Property path "{path}" is not found.';
30
31
    private string $message = 'Nested validation error.';
0 ignored issues
show
introduced by
The private property $message is not used, and could be removed.
Loading history...
32
33 12
    public function __construct(iterable $rules)
34
    {
35 12
        $rules = $rules instanceof Traversable ? iterator_to_array($rules) : (array)$rules;
36 12
        if (empty($rules)) {
37 1
            throw new InvalidArgumentException('Rules should not be empty.');
38
        }
39 11
        if ($this->checkRules($rules)) {
40 1
            throw new InvalidArgumentException(sprintf(
41 1
                'Each rule should be instance of %s.',
42 1
                Rule::class
43
            ));
44
        }
45 10
        $this->rules = $rules;
46 10
    }
47
48 9
    protected function validateValue($value, DataSetInterface $dataSet = null): Result
49
    {
50 9
        $result = new Result();
51 9
        if (!is_object($value) && !is_array($value)) {
52 1
            $result->addError(sprintf(
53 1
                'Value should be an array or an object. %s given',
54 1
                gettype($value)
55
            ));
56 1
            return $result;
57
        }
58 8
        $value = (array) $value;
59
60 8
        foreach ($this->rules as $valuePath => $rules) {
61 8
            $rulesSet = is_array($rules) ? $rules : [$rules];
62 8
            if ($this->errorWhenPropertyPathIsNotFound && !ArrayHelper::pathExists($value, $valuePath)) {
63 2
                $result->addError(
64 2
                    $this->translateMessage(
65 2
                        $this->propertyPathIsNotFoundMessage,
66
                        [
67 2
                            'path' => $valuePath,
68
                        ]
69
                    )
70
                );
71 2
                continue;
72
            }
73 6
            $validatedValue = ArrayHelper::getValueByPath($value, $valuePath);
74 6
            $aggregateRule = new Rules($rulesSet);
75 6
            $itemResult = $aggregateRule->validate($validatedValue);
76 6
            if ($itemResult->isValid() === false) {
77 4
                foreach ($itemResult->getErrors() as $error) {
78 4
                    $result->addError($error);
79
                }
80
            }
81
        }
82
83 8
        return $result;
84
    }
85
86 2
    public function errorWhenPropertyPathIsNotFound(bool $value): self
87
    {
88 2
        $new = clone $this;
89 2
        $new->errorWhenPropertyPathIsNotFound = $value;
90 2
        return $new;
91
    }
92
93 1
    public function propertyPathIsNotFoundMessage(string $message): self
94
    {
95 1
        $new = clone $this;
96 1
        $new->propertyPathIsNotFoundMessage = $message;
97 1
        return $new;
98
    }
99
100
    public function getOptions(): array
101
    {
102
        return $this->rules->asArray();
103
    }
104
105 11
    private function checkRules(array $rules): bool
106
    {
107 11
        return array_reduce(
108 11
            $rules,
109 11
            fn (bool $carry, $rule) => $carry || is_array($rule) ? $this->checkRules($rule) : !$rule instanceof Rule,
110 11
            false
111
        );
112
    }
113
}
114