Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
99 / 99 |
|
100.00% |
4 / 4 |
CRAP | |
100.00% |
1 / 1 |
InsertSchema | |
100.00% |
99 / 99 |
|
100.00% |
4 / 4 |
20 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
execute | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
addValidateResults | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
main | |
100.00% |
94 / 94 |
|
100.00% |
1 / 1 |
17 |
1 | <?php |
2 | |
3 | /** |
4 | * @license MIT |
5 | * @author hazuki3417<hazuki3417@gmail.com> |
6 | * @copyright 2022 hazuki3417 all rights reserved. |
7 | */ |
8 | |
9 | namespace Selen\MongoDB\Validator; |
10 | |
11 | use ReflectionClass; |
12 | use Selen\Data\ArrayPath; |
13 | use Selen\MongoDB\Attribute\SchemaLoader; |
14 | use Selen\MongoDB\Attributes\Nest; |
15 | use Selen\MongoDB\Validator\Model\ValidateResult; |
16 | use Selen\MongoDB\Validator\Model\ValidatorResult; |
17 | |
18 | class InsertSchema implements SchemaValidatorInterface |
19 | { |
20 | /** @var ArrayPath */ |
21 | public $arrayPath; |
22 | |
23 | /** @var Model\ValidateResult[] */ |
24 | private $validateResults = []; |
25 | |
26 | /** @var SchemaLoader */ |
27 | private $schemaLoader; |
28 | |
29 | public function __construct(SchemaLoader $schemaLoader) |
30 | { |
31 | $this->arrayPath = new ArrayPath(); |
32 | $this->schemaLoader = $schemaLoader; |
33 | } |
34 | |
35 | /** |
36 | * 値の検証を実行します |
37 | * |
38 | * @param array<mixed,mixed> $input 検証する値を渡します |
39 | */ |
40 | public function execute(array $input): ValidatorResult |
41 | { |
42 | $this->main($input); |
43 | return new ValidatorResult(...$this->validateResults); |
44 | } |
45 | |
46 | private function addValidateResults(ValidateResult ...$validateResults): void |
47 | { |
48 | $this->validateResults = \array_merge($this->validateResults, $validateResults); |
49 | } |
50 | |
51 | /** |
52 | * @param array<mixed,mixed> $input 検証する値を渡します |
53 | */ |
54 | private function main(array $input): void |
55 | { |
56 | $this->arrayPath->down(); |
57 | |
58 | /** 検証対象の配列にのみ存在するフィールドを検出する処理 */ |
59 | $inputKeys = array_keys($input); |
60 | $definedKeys = array_keys($this->schemaLoader->fieldLoaders); |
61 | $undefinedKeys = array_diff($inputKeys, $definedKeys); |
62 | |
63 | foreach ($undefinedKeys as $undefinedKey) { |
64 | $this->arrayPath->setCurrentPath($undefinedKey); |
65 | $this->validateResults[] = new ValidateResult( |
66 | false, |
67 | ArrayPath::toString($this->arrayPath->getPaths()), |
68 | 'Undefined key.' |
69 | ); |
70 | } |
71 | |
72 | foreach ($this->schemaLoader->fieldLoaders as $fieldLoader) { |
73 | $attributeValueValidates = $fieldLoader->fetchAttributes(ValueValidateInterface::class); |
74 | $attributeNest = $fieldLoader->attributeNest; |
75 | |
76 | $isValueValidateExecute = $attributeValueValidates !== []; |
77 | $isNestValidExecute = $attributeNest !== null; |
78 | |
79 | $key = $fieldLoader->reflectionProperty->getName(); |
80 | $this->arrayPath->setCurrentPath($key); |
81 | |
82 | $keyValidator = new Key($this->arrayPath); |
83 | $keyValidatorResult = $keyValidator->execute($key, $input); |
84 | |
85 | if ($keyValidatorResult->failure()) { |
86 | $this->addValidateResults(...$keyValidatorResult->getValidateResults()); |
87 | continue; |
88 | } |
89 | |
90 | if ($isValueValidateExecute) { |
91 | // 値のバリデーション処理 |
92 | $valueValidator = new Value($this->arrayPath, $attributeValueValidates); |
93 | $valueValidatorResult = $valueValidator->execute($key, $input); |
94 | |
95 | if ($valueValidatorResult->failure()) { |
96 | $this->addValidateResults(...$valueValidatorResult->getValidateResults()); |
97 | // 値チェックに違反したら控えている処理は実行しない |
98 | continue; |
99 | } |
100 | |
101 | if (!$isNestValidExecute) { |
102 | // 値チェックが成功 + ネストした値のバリデーションをしない |
103 | continue; |
104 | } |
105 | |
106 | // 値チェックが成功 + ネストした値のバリデーションをする |
107 | if (!\is_array($input[$key])) { |
108 | /** |
109 | * ここに到達するとき$input[$key]の値は値チェックで許可されたリテラル値 |
110 | * そのためネストした値のバリデーションは実行しないようにする |
111 | * 例) null | object や null | array object といった属性の指定 |
112 | */ |
113 | $isNestValidExecute = false; |
114 | } |
115 | } |
116 | |
117 | if ($isNestValidExecute) { |
118 | // ネストした値のバリデーション処理 |
119 | /** @var Nest */ |
120 | $nestInstance = $attributeNest->newInstance(); |
121 | $schemaLoader = new SchemaLoader(new ReflectionClass($nestInstance->schemaClassName)); |
122 | $nestValidator = new self($schemaLoader); |
123 | $nestValidator->arrayPath = $this->arrayPath; |
124 | |
125 | // ネストした値 = object or array object = inputは1次元または2次元配列を期待 |
126 | if (!\is_array($input[$key])) { |
127 | // 値がリテラル型だったとき |
128 | $format = 'Invalid value. Expect "%s" schema for array type'; |
129 | $mes = \sprintf($format, $nestInstance->schemaClassName); |
130 | $validateResult = new ValidateResult( |
131 | false, |
132 | ArrayPath::toString($this->arrayPath->getPaths()), |
133 | $mes |
134 | ); |
135 | $this->addValidateResults($validateResult); |
136 | continue; |
137 | } |
138 | |
139 | if ($nestInstance->type === Nest::TYPE_OBJECT) { |
140 | // ネストした値がobject形式 |
141 | $object = $input[$key]; |
142 | |
143 | if ($object === []) { |
144 | // 値が空配列だったとき(ネストしたobject形式の配列を期待しているため、keyは必ず存在する) |
145 | $format = 'Invalid value. Expect "%s" schema for array type'; |
146 | $mes = \sprintf($format, $nestInstance->schemaClassName); |
147 | $validateResult = new ValidateResult( |
148 | false, |
149 | ArrayPath::toString($this->arrayPath->getPaths()), |
150 | $mes |
151 | ); |
152 | $this->addValidateResults($validateResult); |
153 | continue; |
154 | } |
155 | |
156 | $nestValidatorResult = $nestValidator->execute($object); |
157 | |
158 | if ($nestValidatorResult->failure()) { |
159 | $this->addValidateResults(...$nestValidatorResult->getValidateResults()); |
160 | } |
161 | continue; |
162 | } |
163 | |
164 | // ネストした値がarray object形式 |
165 | $objects = $input[$key]; |
166 | |
167 | $nestValidator->arrayPath->down(); |
168 | |
169 | foreach ($objects as $index => $object) { |
170 | $nestValidator->arrayPath->setCurrentPath('[' . $index . ']'); |
171 | |
172 | if (!\is_array($object)) { |
173 | // 値がリテラル型だったとき |
174 | $format = 'Invalid value. Expect "%s" schema for array type'; |
175 | $mes = \sprintf($format, $nestInstance->schemaClassName); |
176 | $validateResult = new ValidateResult( |
177 | false, |
178 | ArrayPath::toString($nestValidator->arrayPath->getPaths()), |
179 | $mes |
180 | ); |
181 | $this->addValidateResults($validateResult); |
182 | continue; |
183 | } |
184 | |
185 | if ($object === []) { |
186 | // 値が空配列だったとき(ネストしたobject形式の配列を期待しているため、keyは必ず存在する) |
187 | $format = 'Invalid value. Expect "%s" schema for array type'; |
188 | $mes = \sprintf($format, $nestInstance->schemaClassName); |
189 | $validateResult = new ValidateResult( |
190 | false, |
191 | ArrayPath::toString($this->arrayPath->getPaths()), |
192 | $mes |
193 | ); |
194 | $this->addValidateResults($validateResult); |
195 | continue; |
196 | } |
197 | |
198 | $nestValidatorResult = $nestValidator->execute($object); |
199 | |
200 | if ($nestValidatorResult->failure()) { |
201 | $this->addValidateResults(...$nestValidatorResult->getValidateResults()); |
202 | } |
203 | } |
204 | $nestValidator->arrayPath->up(); |
205 | continue; |
206 | } |
207 | } |
208 | $this->arrayPath->up(); |
209 | } |
210 | } |