ValidationScope::validateDeeply()   B
last analyzed

Complexity

Conditions 8
Paths 6

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 8

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 30
ccs 20
cts 20
cp 1
rs 8.4444
c 0
b 0
f 0
cc 8
nc 6
nop 3
crap 8
1
<?php
2
3
namespace kalanis\Restful\Validation;
4
5
6
use Nette\Utils\Arrays;
7
use Nette\Utils\Strings;
8
9
10
/**
11
 * ValidationScope
12
 * @package kalanis\Restful\Validation
13
 */
14 1
class ValidationScope implements IValidationScope
15
{
16
17
    /** @var Field[] */
18
    private array $fields = [];
19
20 1
    public function __construct(
21
        private readonly IValidator $validator,
22
    )
23
    {
24 1
    }
25
26
    /**
27
     * Create field or get existing
28
     * @param string $name
29
     * @return IField
30
     */
31
    public function field(string $name): IField
32
    {
33 1
        if (!isset($this->fields[$name])) {
34 1
            $this->fields[$name] = $this->createField($name);
35
        }
36 1
        return $this->fields[$name];
37
    }
38
39
    /**
40
     * Create field
41
     * @param string $name
42
     * @return Field
43
     */
44
    protected function createField(string $name): IField
45
    {
46 1
        return new Field($name, $this->getValidator());
47
    }
48
49
    /**
50
     * Get validator
51
     */
52
    public function getValidator(): IValidator
53
    {
54 1
        return $this->validator;
55
    }
56
57
    /**
58
     * Validate all field in collection
59
     * @param array<string|int, mixed> $data
60
     * @return Error[]
61
     */
62
    public function validate(array $data): array
63
    {
64 1
        $errors = [];
65 1
        foreach ($this->fields as $field) {
66 1
            $fieldErrors = $this->validateDeeply($field, $data, $field->getName());
67 1
            $errors = array_merge($errors, $fieldErrors);
68
        }
69 1
        return $errors;
70
    }
71
72
    /**
73
     * Recursively validate data using dot notation
74
     * @param IField $field
75
     * @param array<string|int, mixed> $data
76
     * @param string $path
77
     * @return array<Error>
78
     */
79
    protected function validateDeeply(IField $field, array $data, string $path): array
80
    {
81 1
        $errors = [];
82
83 1
        if (Arrays::isList($data) && count($data)) {
84 1
            foreach ($data as $item) {
85 1
                $newErrors = $this->validateDeeply($field, $item, $path);
86 1
                $errors = array_merge($errors, $newErrors);
87
            }
88
        } else {
89 1
            $keys = explode(".", $path);
90 1
            $last = count($keys) - 1;
91 1
            foreach ($keys as $index => $key) {
92 1
                $isLast = $index == $last;
93 1
                $value = $data[$key] ?? null;
94
95 1
                if (is_array($value)) {
96 1
                    $newPath = Strings::replace($path, "~^$key\.~");
97 1
                    $newErrors = $this->validateDeeply($field, $value, $newPath);
98 1
                    $errors = array_merge($errors, $newErrors);
99 1
                    break; // because recursion already handled this path validation
100 1
                } elseif ($isLast || is_null($value)) {
101 1
                    $newErrors = $field->validate($value);
102 1
                    $errors = array_merge($errors, $newErrors);
103 1
                    break;
104
                }
105
            }
106
        }
107
108 1
        return $errors;
109
    }
110
111
    /**
112
     * Get schema fields
113
     * @return IField[]
114
     */
115
    public function getFields(): array
116
    {
117
        return $this->fields;
118
    }
119
}
120