1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace Yiisoft\Validator\Tests; |
||||
6 | |||||
7 | use InvalidArgumentException; |
||||
8 | use PHPUnit\Framework\TestCase; |
||||
9 | use stdClass; |
||||
10 | use Yiisoft\Validator\AttributeTranslator\NullAttributeTranslator; |
||||
11 | use Yiisoft\Validator\DataSet\ArrayDataSet; |
||||
12 | use Yiisoft\Validator\DataSet\ObjectDataSet; |
||||
13 | use Yiisoft\Validator\DataSet\SingleValueDataSet; |
||||
14 | use Yiisoft\Validator\DataSetInterface; |
||||
15 | use Yiisoft\Validator\EmptyCondition\WhenEmpty; |
||||
16 | use Yiisoft\Validator\EmptyCondition\WhenNull; |
||||
17 | use Yiisoft\Validator\Error; |
||||
18 | use Yiisoft\Validator\Exception\RuleHandlerInterfaceNotImplementedException; |
||||
19 | use Yiisoft\Validator\Exception\RuleHandlerNotFoundException; |
||||
20 | use Yiisoft\Validator\Label; |
||||
21 | use Yiisoft\Validator\Result; |
||||
22 | use Yiisoft\Validator\Rule\AtLeast; |
||||
23 | use Yiisoft\Validator\Rule\BooleanValue; |
||||
24 | use Yiisoft\Validator\Rule\Compare; |
||||
25 | use Yiisoft\Validator\Rule\In; |
||||
26 | use Yiisoft\Validator\Rule\Integer; |
||||
27 | use Yiisoft\Validator\Rule\Length; |
||||
28 | use Yiisoft\Validator\Rule\Number; |
||||
29 | use Yiisoft\Validator\Rule\Required; |
||||
30 | use Yiisoft\Validator\Rule\TrueValue; |
||||
31 | use Yiisoft\Validator\RuleInterface; |
||||
32 | use Yiisoft\Validator\RulesProviderInterface; |
||||
33 | use Yiisoft\Validator\Tests\Rule\RuleWithBuiltInHandler; |
||||
34 | use Yiisoft\Validator\Tests\Support\Data\DataSetWithPostValidationHook; |
||||
35 | use Yiisoft\Validator\Tests\Support\Data\EachNestedObjects\Foo; |
||||
36 | use Yiisoft\Validator\Tests\Support\Data\IteratorWithBooleanKey; |
||||
37 | use Yiisoft\Validator\Tests\Support\Data\ObjectWithAttributesOnly; |
||||
38 | use Yiisoft\Validator\Tests\Support\Data\ObjectWithDataSet; |
||||
39 | use Yiisoft\Validator\Tests\Support\Data\ObjectWithDataSetAndRulesProvider; |
||||
40 | use Yiisoft\Validator\Tests\Support\Data\ObjectWithDifferentPropertyVisibility; |
||||
41 | use Yiisoft\Validator\Tests\Support\Data\ObjectWithLabelsProvider; |
||||
42 | use Yiisoft\Validator\Tests\Support\Data\ObjectWithPostValidationHook; |
||||
43 | use Yiisoft\Validator\Tests\Support\Data\ObjectWithRulesProvider; |
||||
44 | use Yiisoft\Validator\Tests\Support\Data\SimpleDto; |
||||
45 | use Yiisoft\Validator\Tests\Support\Data\SimpleForm; |
||||
46 | use Yiisoft\Validator\Tests\Support\Rule\NotNullRule\NotNull; |
||||
47 | use Yiisoft\Validator\Tests\Support\Rule\StubRule\StubDumpedRule; |
||||
48 | use Yiisoft\Validator\ValidationContext; |
||||
49 | use Yiisoft\Validator\Validator; |
||||
50 | use Yiisoft\Validator\ValidatorInterface; |
||||
51 | |||||
52 | class ValidatorTest extends TestCase |
||||
53 | { |
||||
54 | public function testBase(): void |
||||
55 | { |
||||
56 | $validator = new Validator(); |
||||
57 | |||||
58 | $result = $validator->validate(new ObjectWithAttributesOnly()); |
||||
59 | |||||
60 | $this->assertFalse($result->isValid()); |
||||
61 | $this->assertSame( |
||||
62 | ['name' => ['This value must contain at least 5 characters.']], |
||||
63 | $result->getErrorMessagesIndexedByPath() |
||||
64 | ); |
||||
65 | } |
||||
66 | |||||
67 | public function testWithDefaultSkipOnEmptyCondition(): void |
||||
68 | { |
||||
69 | $data = ''; |
||||
70 | $rule = new Length(1); |
||||
71 | $validator = new Validator(); |
||||
72 | |||||
73 | $result = $validator->validate($data, $rule); |
||||
74 | $this->assertFalse($result->isValid()); |
||||
75 | |||||
76 | $newValidator = $validator->withDefaultSkipOnEmptyCondition(true); |
||||
77 | $this->assertNotSame($validator, $newValidator); |
||||
78 | |||||
79 | $result = $newValidator->validate($data, $rule); |
||||
80 | $this->assertTrue($result->isValid()); |
||||
81 | } |
||||
82 | |||||
83 | public function dataDataAndRulesCombinations(): array |
||||
84 | { |
||||
85 | return [ |
||||
86 | 'pure-object-and-array-of-rules' => [ |
||||
87 | [ |
||||
88 | 'number' => ['Value must be no less than 77.'], |
||||
89 | ], |
||||
90 | new ObjectWithDifferentPropertyVisibility(), |
||||
91 | [ |
||||
92 | 'age' => new Number(max: 100), |
||||
93 | 'number' => new Number(min: 77), |
||||
94 | ], |
||||
95 | ], |
||||
96 | 'pure-object-and-no-rules' => [ |
||||
97 | [ |
||||
98 | 'name' => ['Value cannot be blank.'], |
||||
99 | 'age' => ['Value must be no less than 21.'], |
||||
100 | ], |
||||
101 | new ObjectWithDifferentPropertyVisibility(), |
||||
102 | null, |
||||
103 | ], |
||||
104 | 'dataset-object-and-array-of-rules' => [ |
||||
105 | [ |
||||
106 | 'key1' => ['Value must be no less than 21.'], |
||||
107 | ], |
||||
108 | new ObjectWithDataSet(), |
||||
109 | [ |
||||
110 | 'key1' => new Number(min: 21), |
||||
111 | ], |
||||
112 | ], |
||||
113 | 'dataset-object-and-no-rules' => [ |
||||
114 | [], |
||||
115 | new ObjectWithDataSet(), |
||||
116 | null, |
||||
117 | ], |
||||
118 | 'rules-provider-object-and-array-of-rules' => [ |
||||
119 | [ |
||||
120 | 'number' => ['Value must be no greater than 7.'], |
||||
121 | ], |
||||
122 | new ObjectWithRulesProvider(), |
||||
123 | [ |
||||
124 | 'age' => new Number(max: 100), |
||||
125 | 'number' => new Number(max: 7), |
||||
126 | ], |
||||
127 | ], |
||||
128 | 'rules-provider-object-and-no-rules' => [ |
||||
129 | [ |
||||
130 | 'age' => ['Value must be equal to "25".'], |
||||
131 | ], |
||||
132 | new ObjectWithRulesProvider(), |
||||
133 | null, |
||||
134 | ], |
||||
135 | 'rules-provider-and-dataset-object-and-array-of-rules' => [ |
||||
136 | [ |
||||
137 | 'key2' => ['Value must be no greater than 7.'], |
||||
138 | ], |
||||
139 | new ObjectWithDataSetAndRulesProvider(), |
||||
140 | [ |
||||
141 | 'key2' => new Number(max: 7), |
||||
142 | ], |
||||
143 | ], |
||||
144 | 'rules-provider-and-dataset-object-and-no-rules' => [ |
||||
145 | [ |
||||
146 | 'key2' => ['Value must be equal to "99".'], |
||||
147 | ], |
||||
148 | new ObjectWithDataSetAndRulesProvider(), |
||||
149 | null, |
||||
150 | ], |
||||
151 | 'array-and-array-of-rules' => [ |
||||
152 | [ |
||||
153 | 'key2' => ['Value must be no greater than 7.'], |
||||
154 | ], |
||||
155 | ['key1' => 15, 'key2' => 99], |
||||
156 | [ |
||||
157 | 'key1' => new Number(max: 100), |
||||
158 | 'key2' => new Number(max: 7), |
||||
159 | ], |
||||
160 | ], |
||||
161 | 'array-and-no-rules' => [ |
||||
162 | [], |
||||
163 | ['key1' => 15, 'key2' => 99], |
||||
164 | null, |
||||
165 | ], |
||||
166 | 'scalar-and-array-of-rules' => [ |
||||
167 | [ |
||||
168 | '' => ['Value must be no greater than 7.'], |
||||
169 | ], |
||||
170 | 42, |
||||
171 | [ |
||||
172 | new Number(max: 7), |
||||
173 | ], |
||||
174 | ], |
||||
175 | 'scalar-and-no-rules' => [ |
||||
176 | [], |
||||
177 | 42, |
||||
178 | null, |
||||
179 | ], |
||||
180 | 'array-and-rules-provider' => [ |
||||
181 | [ |
||||
182 | 'age' => ['Value must be no less than 18.'], |
||||
183 | ], |
||||
184 | [ |
||||
185 | 'age' => 17, |
||||
186 | ], |
||||
187 | new class () implements RulesProviderInterface { |
||||
188 | public function getRules(): iterable |
||||
189 | { |
||||
190 | return [ |
||||
191 | 'age' => [new Number(min: 18)], |
||||
192 | ]; |
||||
193 | } |
||||
194 | }, |
||||
195 | ], |
||||
196 | 'array-and-object' => [ |
||||
197 | [ |
||||
198 | 'name' => ['Value not passed.'], |
||||
199 | 'bars' => ['Value must be array or iterable.'], |
||||
200 | ], |
||||
201 | [], |
||||
202 | new Foo(), |
||||
203 | ], |
||||
204 | 'array-and-callable' => [ |
||||
205 | ['' => ['test message']], |
||||
206 | [], |
||||
207 | static fn (): Result => (new Result())->addError('test message'), |
||||
208 | ], |
||||
209 | ]; |
||||
210 | } |
||||
211 | |||||
212 | /** |
||||
213 | * @dataProvider dataDataAndRulesCombinations |
||||
214 | */ |
||||
215 | public function testDataAndRulesCombinations( |
||||
216 | array $expectedErrorMessages, |
||||
217 | mixed $data, |
||||
218 | iterable|object|callable|null $rules, |
||||
219 | ): void { |
||||
220 | $validator = new Validator(); |
||||
221 | $result = $validator->validate($data, $rules); |
||||
222 | $this->assertSame($expectedErrorMessages, $result->getErrorMessagesIndexedByAttribute()); |
||||
223 | } |
||||
224 | |||||
225 | public function dataWithEmptyArrayOfRules(): array |
||||
226 | { |
||||
227 | return [ |
||||
228 | 'pure-object-and-no-rules' => [new ObjectWithDifferentPropertyVisibility()], |
||||
229 | 'dataset-object-and-no-rules' => [new ObjectWithDataSet()], |
||||
230 | 'rules-provider-object' => [new ObjectWithRulesProvider()], |
||||
231 | 'rules-provider-and-dataset-object' => [new ObjectWithDataSetAndRulesProvider()], |
||||
232 | 'array' => [['key1' => 15, 'key2' => 99]], |
||||
233 | 'scalar' => [42], |
||||
234 | ]; |
||||
235 | } |
||||
236 | |||||
237 | /** |
||||
238 | * @dataProvider dataWithEmptyArrayOfRules |
||||
239 | */ |
||||
240 | public function testWithEmptyArrayOfRules(mixed $data): void |
||||
241 | { |
||||
242 | $validator = new Validator(); |
||||
243 | $result = $validator->validate($data, []); |
||||
244 | |||||
245 | $this->assertTrue($result->isValid()); |
||||
246 | } |
||||
247 | |||||
248 | public function testAddingRulesViaConstructor(): void |
||||
249 | { |
||||
250 | $dataObject = new ArrayDataSet(['bool' => true, 'int' => 41]); |
||||
251 | $validator = new Validator(); |
||||
252 | $result = $validator->validate($dataObject, [ |
||||
253 | 'bool' => [new BooleanValue()], |
||||
254 | 'int' => [ |
||||
255 | new Integer(), |
||||
256 | new Integer(min: 44), |
||||
257 | static function (mixed $value): Result { |
||||
258 | $result = new Result(); |
||||
259 | if ($value !== 42) { |
||||
260 | $result->addError('Value should be 42!', ['int']); |
||||
261 | } |
||||
262 | |||||
263 | return $result; |
||||
264 | }, |
||||
265 | ], |
||||
266 | ]); |
||||
267 | |||||
268 | $this->assertTrue($result->isAttributeValid('bool')); |
||||
269 | $this->assertFalse($result->isAttributeValid('int')); |
||||
270 | } |
||||
271 | |||||
272 | public function diverseTypesDataProvider(): array |
||||
273 | { |
||||
274 | $class = new stdClass(); |
||||
275 | $class->property = true; |
||||
276 | |||||
277 | return [ |
||||
278 | 'object' => [new ObjectDataSet($class, useCache: false)], |
||||
279 | 'true' => [true], |
||||
280 | 'non-empty-string' => ['true'], |
||||
281 | 'integer' => [12345], |
||||
282 | 'float' => [12.345], |
||||
283 | 'false' => [false], |
||||
284 | ]; |
||||
285 | } |
||||
286 | |||||
287 | /** |
||||
288 | * @dataProvider diverseTypesDataProvider |
||||
289 | */ |
||||
290 | public function testDiverseTypes($dataSet): void |
||||
291 | { |
||||
292 | $validator = new Validator(); |
||||
293 | $result = $validator->validate($dataSet, [new Required()]); |
||||
294 | |||||
295 | $this->assertTrue($result->isValid()); |
||||
296 | } |
||||
297 | |||||
298 | public function testNullAsDataSet(): void |
||||
299 | { |
||||
300 | $validator = new Validator(); |
||||
301 | $result = $validator->validate(null, ['property' => [new Compare()]]); |
||||
302 | |||||
303 | $this->assertTrue($result->isValid()); |
||||
304 | } |
||||
305 | |||||
306 | public function testPreValidation(): void |
||||
307 | { |
||||
308 | $validator = new Validator(); |
||||
309 | $result = $validator->validate( |
||||
310 | new ArrayDataSet(['property' => '']), |
||||
311 | ['property' => [new Required(when: static fn (mixed $value, ?ValidationContext $context): bool => false)]], |
||||
0 ignored issues
–
show
The parameter
$value is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
312 | ); |
||||
313 | |||||
314 | $this->assertTrue($result->isValid()); |
||||
315 | } |
||||
316 | |||||
317 | public function testRuleHandlerWithoutImplement(): void |
||||
318 | { |
||||
319 | $ruleHandler = new class () { |
||||
320 | }; |
||||
321 | $validator = new Validator(); |
||||
322 | |||||
323 | $this->expectException(RuleHandlerInterfaceNotImplementedException::class); |
||||
324 | $validator->validate(new ArrayDataSet(['property' => '']), [ |
||||
325 | 'property' => [ |
||||
326 | new class ($ruleHandler) implements RuleInterface { |
||||
327 | public function __construct(private $ruleHandler) |
||||
328 | { |
||||
329 | } |
||||
330 | |||||
331 | public function getHandler(): string |
||||
332 | { |
||||
333 | return $this->ruleHandler::class; |
||||
334 | } |
||||
335 | }, |
||||
336 | ], |
||||
337 | ]); |
||||
338 | } |
||||
339 | |||||
340 | public function testRuleWithoutHandler(): void |
||||
341 | { |
||||
342 | $this->expectException(RuleHandlerNotFoundException::class); |
||||
343 | |||||
344 | $validator = new Validator(); |
||||
345 | $validator->validate(new ArrayDataSet(['property' => '']), [ |
||||
346 | 'property' => [ |
||||
347 | new class () implements RuleInterface { |
||||
348 | public function getHandler(): string |
||||
349 | { |
||||
350 | return 'NonExistClass'; |
||||
351 | } |
||||
352 | }, |
||||
353 | ], |
||||
354 | ]); |
||||
355 | } |
||||
356 | |||||
357 | public function requiredDataProvider(): array |
||||
358 | { |
||||
359 | $strictRules = [ |
||||
360 | 'orderBy' => [new Required()], |
||||
361 | 'sort' => [ |
||||
362 | new In( |
||||
363 | ['asc', 'desc'], |
||||
364 | skipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $isAttributeMissing |
||||
365 | ), |
||||
366 | ], |
||||
367 | ]; |
||||
368 | $notStrictRules = [ |
||||
369 | 'orderBy' => [new Required()], |
||||
370 | 'sort' => [ |
||||
371 | new In( |
||||
372 | ['asc', 'desc'], |
||||
373 | skipOnEmpty: static fn ( |
||||
374 | mixed $value, |
||||
375 | bool $isAttributeMissing |
||||
376 | ): bool => $isAttributeMissing || $value === '' |
||||
377 | ), |
||||
378 | ], |
||||
379 | ]; |
||||
380 | |||||
381 | return [ |
||||
382 | [ |
||||
383 | ['merchantId' => [new Required(), new Integer()]], |
||||
384 | new ArrayDataSet(['merchantId' => null]), |
||||
385 | [ |
||||
386 | new Error( |
||||
387 | 'Value cannot be blank.', |
||||
388 | ['attribute' => 'merchantId'], |
||||
389 | ['merchantId'] |
||||
390 | ), |
||||
391 | new Error( |
||||
392 | 'The allowed types are integer, float and string.', |
||||
393 | ['attribute' => 'merchantId', 'type' => 'null'], |
||||
394 | ['merchantId'] |
||||
395 | ), |
||||
396 | ], |
||||
397 | ], |
||||
398 | [ |
||||
399 | ['merchantId' => [new Required(), new Integer(skipOnError: true)]], |
||||
400 | new ArrayDataSet(['merchantId' => null]), |
||||
401 | [new Error('Value cannot be blank.', [ 'attribute' => 'merchantId'], ['merchantId'])], |
||||
402 | ], |
||||
403 | [ |
||||
404 | ['merchantId' => [new Required(), new Integer(skipOnError: true)]], |
||||
405 | new ArrayDataSet(['merchantIdd' => 1]), |
||||
406 | [new Error('Value not passed.', ['attribute' => 'merchantId'], ['merchantId'])], |
||||
407 | ], |
||||
408 | |||||
409 | [ |
||||
410 | $strictRules, |
||||
411 | new ArrayDataSet(['orderBy' => 'name', 'sort' => 'asc']), |
||||
412 | [], |
||||
413 | ], |
||||
414 | [ |
||||
415 | $notStrictRules, |
||||
416 | new ArrayDataSet(['orderBy' => 'name', 'sort' => 'asc']), |
||||
417 | [], |
||||
418 | ], |
||||
419 | |||||
420 | [ |
||||
421 | $strictRules, |
||||
422 | new ArrayDataSet(['orderBy' => 'name', 'sort' => 'desc']), |
||||
423 | [], |
||||
424 | ], |
||||
425 | [ |
||||
426 | $notStrictRules, |
||||
427 | new ArrayDataSet(['orderBy' => 'name', 'sort' => 'desc']), |
||||
428 | [], |
||||
429 | ], |
||||
430 | |||||
431 | [ |
||||
432 | $strictRules, |
||||
433 | new ArrayDataSet(['orderBy' => 'name', 'sort' => 'up']), |
||||
434 | [new Error('This value is not in the list of acceptable values.', ['attribute' => 'sort'], ['sort'])], |
||||
435 | ], |
||||
436 | [ |
||||
437 | $notStrictRules, |
||||
438 | new ArrayDataSet(['orderBy' => 'name', 'sort' => 'up']), |
||||
439 | [new Error('This value is not in the list of acceptable values.', ['attribute' => 'sort'], ['sort'])], |
||||
440 | ], |
||||
441 | |||||
442 | [ |
||||
443 | $strictRules, |
||||
444 | new ArrayDataSet(['orderBy' => 'name', 'sort' => '']), |
||||
445 | [new Error('This value is not in the list of acceptable values.', ['attribute' => 'sort'], ['sort'])], |
||||
446 | ], |
||||
447 | [ |
||||
448 | $notStrictRules, |
||||
449 | new ArrayDataSet(['orderBy' => 'name', 'sort' => '']), |
||||
450 | [], |
||||
451 | ], |
||||
452 | |||||
453 | [ |
||||
454 | $strictRules, |
||||
455 | new ArrayDataSet(['orderBy' => 'name']), |
||||
456 | [], |
||||
457 | ], |
||||
458 | [ |
||||
459 | $notStrictRules, |
||||
460 | new ArrayDataSet(['orderBy' => 'name']), |
||||
461 | [], |
||||
462 | ], |
||||
463 | |||||
464 | [ |
||||
465 | $strictRules, |
||||
466 | new ArrayDataSet(['orderBy' => '']), |
||||
467 | [new Error('Value cannot be blank.', ['attribute' => 'orderBy'], ['orderBy'])], |
||||
468 | ], |
||||
469 | [ |
||||
470 | $notStrictRules, |
||||
471 | new ArrayDataSet(['orderBy' => '']), |
||||
472 | [new Error('Value cannot be blank.', ['attribute' => 'orderBy'], ['orderBy'])], |
||||
473 | ], |
||||
474 | |||||
475 | [ |
||||
476 | $strictRules, |
||||
477 | new ArrayDataSet([]), |
||||
478 | [new Error('Value not passed.', ['attribute' => 'orderBy'], ['orderBy'])], |
||||
479 | ], |
||||
480 | [ |
||||
481 | $notStrictRules, |
||||
482 | new ArrayDataSet([]), |
||||
483 | [new Error('Value not passed.', ['attribute' => 'orderBy'], ['orderBy'])], |
||||
484 | ], |
||||
485 | [ |
||||
486 | [ |
||||
487 | 'name' => [new Required(), new Length(min: 3, skipOnError: true)], |
||||
488 | 'description' => [new Required(), new Length(min: 5, skipOnError: true)], |
||||
489 | ], |
||||
490 | new ObjectDataSet( |
||||
491 | new class () { |
||||
492 | private string $title = ''; |
||||
0 ignored issues
–
show
|
|||||
493 | private string $description = 'abc123'; |
||||
0 ignored issues
–
show
|
|||||
494 | } |
||||
495 | ), |
||||
496 | [new Error('Value not passed.', ['attribute' => 'name'], ['name'])], |
||||
497 | ], |
||||
498 | [ |
||||
499 | null, |
||||
500 | new ObjectDataSet(new ObjectWithDataSet()), |
||||
501 | [], |
||||
502 | ], |
||||
503 | ]; |
||||
504 | } |
||||
505 | |||||
506 | /** |
||||
507 | * @link https://github.com/yiisoft/validator/issues/173 |
||||
508 | * @link https://github.com/yiisoft/validator/issues/289 |
||||
509 | * |
||||
510 | * @dataProvider requiredDataProvider |
||||
511 | */ |
||||
512 | public function testRequired(array|null $rules, DataSetInterface $dataSet, array $expectedErrors): void |
||||
513 | { |
||||
514 | $validator = new Validator(); |
||||
515 | $result = $validator->validate($dataSet, $rules); |
||||
516 | $this->assertEquals($expectedErrors, $result->getErrors()); |
||||
517 | } |
||||
518 | |||||
519 | public function skipOnEmptyDataProvider(): array |
||||
520 | { |
||||
521 | $validator = new Validator(); |
||||
522 | $rules = [ |
||||
523 | 'name' => [new Length(min: 8)], |
||||
524 | 'age' => [new Integer(min: 18)], |
||||
525 | ]; |
||||
526 | $stringLessThanMinMessage = 'This value must contain at least 8 characters.'; |
||||
527 | $incorrectNumberMessage = 'The allowed types are integer, float and string.'; |
||||
528 | $intMessage = 'Value must be an integer.'; |
||||
529 | $intLessThanMinMessage = 'Value must be no less than 18.'; |
||||
530 | |||||
531 | return [ |
||||
532 | 'rule / validator, skipOnEmpty: false, value not passed' => [ |
||||
533 | $validator, |
||||
534 | new ArrayDataSet([ |
||||
535 | 'name' => 'Dmitriy', |
||||
536 | ]), |
||||
537 | $rules, |
||||
538 | [ |
||||
539 | new Error($stringLessThanMinMessage, [ |
||||
540 | 'min' => 8, |
||||
541 | 'attribute' => 'name', |
||||
542 | 'number' => 7, |
||||
543 | ], ['name']), |
||||
544 | new Error($incorrectNumberMessage, [ |
||||
545 | 'attribute' => 'age', |
||||
546 | 'type' => 'null', |
||||
547 | ], ['age']), |
||||
548 | ], |
||||
549 | ], |
||||
550 | 'rule / validator, skipOnEmpty: false, value is empty' => [ |
||||
551 | $validator, |
||||
552 | new ArrayDataSet([ |
||||
553 | 'name' => 'Dmitriy', |
||||
554 | 'age' => null, |
||||
555 | ]), |
||||
556 | $rules, |
||||
557 | [ |
||||
558 | new Error($stringLessThanMinMessage, [ |
||||
559 | 'min' => 8, |
||||
560 | 'attribute' => 'name', |
||||
561 | 'number' => 7, |
||||
562 | ], ['name']), |
||||
563 | new Error($incorrectNumberMessage, [ |
||||
564 | 'attribute' => 'age', |
||||
565 | 'type' => 'null', |
||||
566 | ], ['age']), |
||||
567 | ], |
||||
568 | ], |
||||
569 | 'rule / validator, skipOnEmpty: false, value is not empty' => [ |
||||
570 | $validator, |
||||
571 | new ArrayDataSet([ |
||||
572 | 'name' => 'Dmitriy', |
||||
573 | 'age' => 17, |
||||
574 | ]), |
||||
575 | $rules, |
||||
576 | [ |
||||
577 | new Error($stringLessThanMinMessage, [ |
||||
578 | 'min' => 8, |
||||
579 | 'attribute' => 'name', |
||||
580 | 'number' => 7, |
||||
581 | ], ['name']), |
||||
582 | new Error($intLessThanMinMessage, [ |
||||
583 | 'min' => 18, |
||||
584 | 'attribute' => 'age', |
||||
585 | 'value' => 17, |
||||
586 | ], ['age']), |
||||
587 | ], |
||||
588 | ], |
||||
589 | |||||
590 | 'rule, skipOnEmpty: true, value not passed' => [ |
||||
591 | $validator, |
||||
592 | new ArrayDataSet([ |
||||
593 | 'name' => 'Dmitriy', |
||||
594 | ]), |
||||
595 | [ |
||||
596 | 'name' => [new Length(min: 8)], |
||||
597 | 'age' => [new Integer(min: 18, skipOnEmpty: true)], |
||||
598 | ], |
||||
599 | [ |
||||
600 | new Error($stringLessThanMinMessage, [ |
||||
601 | 'min' => 8, |
||||
602 | 'attribute' => 'name', |
||||
603 | 'number' => 7, |
||||
604 | ], ['name']), |
||||
605 | ], |
||||
606 | ], |
||||
607 | 'rule, skipOnEmpty: true, value is empty (null)' => [ |
||||
608 | $validator, |
||||
609 | new ArrayDataSet([ |
||||
610 | 'name' => 'Dmitriy', |
||||
611 | 'age' => null, |
||||
612 | ]), |
||||
613 | [ |
||||
614 | 'name' => [new Length(min: 8)], |
||||
615 | 'age' => [new Integer(min: 18, skipOnEmpty: true)], |
||||
616 | ], |
||||
617 | [ |
||||
618 | new Error($stringLessThanMinMessage, [ |
||||
619 | 'min' => 8, |
||||
620 | 'attribute' => 'name', |
||||
621 | 'number' => 7, |
||||
622 | ], ['name']), |
||||
623 | ], |
||||
624 | ], |
||||
625 | 'rule, skipOnEmpty: true, value is empty (empty string after trimming), trimString is false' => [ |
||||
626 | $validator, |
||||
627 | new ArrayDataSet([ |
||||
628 | 'name' => ' ', |
||||
629 | 'age' => 17, |
||||
630 | ]), |
||||
631 | [ |
||||
632 | 'name' => [new Length(min: 8, skipOnEmpty: true)], |
||||
633 | 'age' => [new Integer(min: 18)], |
||||
634 | ], |
||||
635 | [ |
||||
636 | new Error($stringLessThanMinMessage, [ |
||||
637 | 'min' => 8, |
||||
638 | 'attribute' => 'name', |
||||
639 | 'number' => 1, |
||||
640 | ], ['name']), |
||||
641 | new Error($intLessThanMinMessage, [ |
||||
642 | 'min' => 18, |
||||
643 | 'attribute' => 'age', |
||||
644 | 'value' => 17, |
||||
645 | ], ['age']), |
||||
646 | ], |
||||
647 | ], |
||||
648 | 'rule, skipOnEmpty: SkipOnEmpty, value is empty (empty string after trimming), trimString is true' => [ |
||||
649 | $validator, |
||||
650 | new ArrayDataSet([ |
||||
651 | 'name' => ' ', |
||||
652 | 'age' => 17, |
||||
653 | ]), |
||||
654 | [ |
||||
655 | 'name' => [new Length(min: 8, skipOnEmpty: new WhenEmpty(trimString: true))], |
||||
656 | 'age' => [new Integer(min: 18)], |
||||
657 | ], |
||||
658 | [ |
||||
659 | new Error($intLessThanMinMessage, [ |
||||
660 | 'min' => 18, |
||||
661 | 'attribute' => 'age', |
||||
662 | 'value' => 17, |
||||
663 | ], ['age']), |
||||
664 | ], |
||||
665 | ], |
||||
666 | 'rule, skipOnEmpty: true, value is not empty' => [ |
||||
667 | $validator, |
||||
668 | new ArrayDataSet([ |
||||
669 | 'name' => 'Dmitriy', |
||||
670 | 'age' => 17, |
||||
671 | ]), |
||||
672 | [ |
||||
673 | 'name' => [new Length(min: 8)], |
||||
674 | 'age' => [new Integer(min: 18, skipOnEmpty: true)], |
||||
675 | ], |
||||
676 | [ |
||||
677 | new Error($stringLessThanMinMessage, [ |
||||
678 | 'min' => 8, |
||||
679 | 'attribute' => 'name', |
||||
680 | 'number' => 7, |
||||
681 | ], ['name']), |
||||
682 | new Error($intLessThanMinMessage, [ |
||||
683 | 'min' => 18, |
||||
684 | 'attribute' => 'age', |
||||
685 | 'value' => 17, |
||||
686 | ], ['age']), |
||||
687 | ], |
||||
688 | ], |
||||
689 | |||||
690 | 'rule, skipOnEmpty: SkipOnNull, value not passed' => [ |
||||
691 | $validator, |
||||
692 | new ArrayDataSet([ |
||||
693 | 'name' => 'Dmitriy', |
||||
694 | ]), |
||||
695 | [ |
||||
696 | 'name' => [new Length(min: 8)], |
||||
697 | 'age' => [new Integer(min: 18, skipOnEmpty: new WhenNull())], |
||||
698 | ], |
||||
699 | [ |
||||
700 | new Error($stringLessThanMinMessage, [ |
||||
701 | 'min' => 8, |
||||
702 | 'attribute' => 'name', |
||||
703 | 'number' => 7, |
||||
704 | ], ['name']), |
||||
705 | ], |
||||
706 | ], |
||||
707 | 'rule, skipOnEmpty: SkipOnNull, value is empty' => [ |
||||
708 | $validator, |
||||
709 | new ArrayDataSet([ |
||||
710 | 'name' => 'Dmitriy', |
||||
711 | 'age' => null, |
||||
712 | ]), |
||||
713 | [ |
||||
714 | 'name' => [new Length(min: 8)], |
||||
715 | 'age' => [new Integer(min: 18, skipOnEmpty: new WhenNull())], |
||||
716 | ], |
||||
717 | [ |
||||
718 | new Error($stringLessThanMinMessage, [ |
||||
719 | 'min' => 8, |
||||
720 | 'attribute' => 'name', |
||||
721 | 'number' => 7, |
||||
722 | ], ['name']), |
||||
723 | ], |
||||
724 | ], |
||||
725 | 'rule, skipOnEmpty: SkipOnNull, value is not empty' => [ |
||||
726 | $validator, |
||||
727 | new ArrayDataSet([ |
||||
728 | 'name' => 'Dmitriy', |
||||
729 | 'age' => 17, |
||||
730 | ]), |
||||
731 | [ |
||||
732 | 'name' => [new Length(min: 8)], |
||||
733 | 'age' => [new Integer(min: 18, skipOnEmpty: new WhenNull())], |
||||
734 | ], |
||||
735 | [ |
||||
736 | new Error($stringLessThanMinMessage, [ |
||||
737 | 'min' => 8, |
||||
738 | 'attribute' => 'name', |
||||
739 | 'number' => 7, |
||||
740 | ], ['name']), |
||||
741 | new Error($intLessThanMinMessage, [ |
||||
742 | 'min' => 18, |
||||
743 | 'attribute' => 'age', |
||||
744 | 'value' => 17, |
||||
745 | ], ['age']), |
||||
746 | ], |
||||
747 | ], |
||||
748 | 'rule, skipOnEmpty: SkipOnNull, value is not empty (empty string)' => [ |
||||
749 | $validator, |
||||
750 | new ArrayDataSet([ |
||||
751 | 'name' => 'Dmitriy', |
||||
752 | 'age' => '', |
||||
753 | ]), |
||||
754 | [ |
||||
755 | 'name' => [new Length(min: 8)], |
||||
756 | 'age' => [new Integer(min: 18, skipOnEmpty: new WhenNull())], |
||||
757 | ], |
||||
758 | [ |
||||
759 | new Error($stringLessThanMinMessage, [ |
||||
760 | 'min' => 8, |
||||
761 | 'attribute' => 'name', |
||||
762 | 'number' => 7, |
||||
763 | ], ['name']), |
||||
764 | new Error($intMessage, [ |
||||
765 | 'attribute' => 'age', |
||||
766 | 'value' => '', |
||||
767 | ], ['age']), |
||||
768 | ], |
||||
769 | ], |
||||
770 | |||||
771 | 'rule, skipOnEmpty: custom callback, value not passed' => [ |
||||
772 | $validator, |
||||
773 | new ArrayDataSet([ |
||||
774 | 'name' => 'Dmitriy', |
||||
775 | ]), |
||||
776 | [ |
||||
777 | 'name' => [new Length(min: 8)], |
||||
778 | 'age' => [ |
||||
779 | new Integer( |
||||
780 | min: 18, |
||||
781 | skipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $value === 0 |
||||
0 ignored issues
–
show
The parameter
$isAttributeMissing is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
782 | ), |
||||
783 | ], |
||||
784 | ], |
||||
785 | [ |
||||
786 | new Error($stringLessThanMinMessage, [ |
||||
787 | 'min' => 8, |
||||
788 | 'attribute' => 'name', |
||||
789 | 'number' => 7, |
||||
790 | ], ['name']), |
||||
791 | new Error($incorrectNumberMessage, [ |
||||
792 | 'attribute' => 'age', |
||||
793 | 'type' => 'null', |
||||
794 | ], ['age']), |
||||
795 | ], |
||||
796 | ], |
||||
797 | 'rule, skipOnEmpty: custom callback, value is empty' => [ |
||||
798 | $validator, |
||||
799 | new ArrayDataSet([ |
||||
800 | 'name' => 'Dmitriy', |
||||
801 | 'age' => 0, |
||||
802 | ]), |
||||
803 | [ |
||||
804 | 'name' => [new Length(min: 8)], |
||||
805 | 'age' => [ |
||||
806 | new Integer( |
||||
807 | min: 18, |
||||
808 | skipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $value === 0 |
||||
0 ignored issues
–
show
The parameter
$isAttributeMissing is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
809 | ), |
||||
810 | ], |
||||
811 | ], |
||||
812 | [ |
||||
813 | new Error($stringLessThanMinMessage, [ |
||||
814 | 'min' => 8, |
||||
815 | 'attribute' => 'name', |
||||
816 | 'number' => 7, |
||||
817 | ], ['name']), |
||||
818 | ], |
||||
819 | ], |
||||
820 | 'rule, skipOnEmpty, custom callback, value is not empty' => [ |
||||
821 | $validator, |
||||
822 | new ArrayDataSet([ |
||||
823 | 'name' => 'Dmitriy', |
||||
824 | 'age' => 17, |
||||
825 | ]), |
||||
826 | [ |
||||
827 | 'name' => [new Length(min: 8)], |
||||
828 | 'age' => [ |
||||
829 | new Integer( |
||||
830 | min: 18, |
||||
831 | skipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $value === 0 |
||||
0 ignored issues
–
show
The parameter
$isAttributeMissing is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
832 | ), |
||||
833 | ], |
||||
834 | ], |
||||
835 | [ |
||||
836 | new Error($stringLessThanMinMessage, [ |
||||
837 | 'min' => 8, |
||||
838 | 'attribute' => 'name', |
||||
839 | 'number' => 7, |
||||
840 | ], ['name']), |
||||
841 | new Error($intLessThanMinMessage, [ |
||||
842 | 'min' => 18, |
||||
843 | 'attribute' => 'age', |
||||
844 | 'value' => 17, |
||||
845 | ], ['age']), |
||||
846 | ], |
||||
847 | ], |
||||
848 | 'rule, skipOnEmpty, custom callback, value is not empty (null)' => [ |
||||
849 | $validator, |
||||
850 | new ArrayDataSet([ |
||||
851 | 'name' => 'Dmitriy', |
||||
852 | 'age' => null, |
||||
853 | ]), |
||||
854 | [ |
||||
855 | 'name' => [new Length(min: 8)], |
||||
856 | 'age' => [ |
||||
857 | new Integer( |
||||
858 | min: 18, |
||||
859 | skipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $value === 0 |
||||
0 ignored issues
–
show
The parameter
$isAttributeMissing is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
860 | ), |
||||
861 | ], |
||||
862 | ], |
||||
863 | [ |
||||
864 | new Error($stringLessThanMinMessage, [ |
||||
865 | 'min' => 8, |
||||
866 | 'attribute' => 'name', |
||||
867 | 'number' => 7, |
||||
868 | ], ['name']), |
||||
869 | new Error($incorrectNumberMessage, [ |
||||
870 | 'attribute' => 'age', |
||||
871 | 'type' => 'null', |
||||
872 | ], ['age']), |
||||
873 | ], |
||||
874 | ], |
||||
875 | |||||
876 | 'validator, skipOnEmpty: true, value not passed' => [ |
||||
877 | new Validator(defaultSkipOnEmpty: true), |
||||
878 | new ArrayDataSet([ |
||||
879 | 'name' => 'Dmitriy', |
||||
880 | ]), |
||||
881 | $rules, |
||||
882 | [ |
||||
883 | new Error($stringLessThanMinMessage, [ |
||||
884 | 'min' => 8, |
||||
885 | 'attribute' => 'name', |
||||
886 | 'number' => 7, |
||||
887 | ], ['name']), |
||||
888 | ], |
||||
889 | ], |
||||
890 | 'validator, skipOnEmpty: true, value is empty' => [ |
||||
891 | new Validator(defaultSkipOnEmpty: true), |
||||
892 | new ArrayDataSet([ |
||||
893 | 'name' => 'Dmitriy', |
||||
894 | 'age' => null, |
||||
895 | ]), |
||||
896 | $rules, |
||||
897 | [ |
||||
898 | new Error($stringLessThanMinMessage, [ |
||||
899 | 'min' => 8, |
||||
900 | 'attribute' => 'name', |
||||
901 | 'number' => 7, |
||||
902 | ], ['name']), |
||||
903 | ], |
||||
904 | ], |
||||
905 | 'validator, skipOnEmpty: true, value is not empty' => [ |
||||
906 | new Validator(defaultSkipOnEmpty: true), |
||||
907 | new ArrayDataSet([ |
||||
908 | 'name' => 'Dmitriy', |
||||
909 | 'age' => 17, |
||||
910 | ]), |
||||
911 | $rules, |
||||
912 | [ |
||||
913 | new Error($stringLessThanMinMessage, [ |
||||
914 | 'min' => 8, |
||||
915 | 'attribute' => 'name', |
||||
916 | 'number' => 7, |
||||
917 | ], ['name']), |
||||
918 | new Error($intLessThanMinMessage, [ |
||||
919 | 'min' => 18, |
||||
920 | 'attribute' => 'age', |
||||
921 | 'value' => 17, |
||||
922 | ], ['age']), |
||||
923 | ], |
||||
924 | ], |
||||
925 | |||||
926 | 'validator, skipOnEmpty: SkipOnNull, value not passed' => [ |
||||
927 | new Validator(defaultSkipOnEmpty: new WhenNull()), |
||||
928 | new ArrayDataSet([ |
||||
929 | 'name' => 'Dmitriy', |
||||
930 | ]), |
||||
931 | $rules, |
||||
932 | [ |
||||
933 | new Error($stringLessThanMinMessage, [ |
||||
934 | 'min' => 8, |
||||
935 | 'attribute' => 'name', |
||||
936 | 'number' => 7, |
||||
937 | ], ['name']), |
||||
938 | ], |
||||
939 | ], |
||||
940 | 'validator, skipOnEmpty: SkipOnNull, value is empty' => [ |
||||
941 | new Validator(defaultSkipOnEmpty: new WhenNull()), |
||||
942 | new ArrayDataSet([ |
||||
943 | 'name' => 'Dmitriy', |
||||
944 | 'age' => null, |
||||
945 | ]), |
||||
946 | $rules, |
||||
947 | [ |
||||
948 | new Error($stringLessThanMinMessage, [ |
||||
949 | 'min' => 8, |
||||
950 | 'attribute' => 'name', |
||||
951 | 'number' => 7, |
||||
952 | ], ['name']), |
||||
953 | ], |
||||
954 | ], |
||||
955 | 'validator, skipOnEmpty: SkipOnNull, value is not empty' => [ |
||||
956 | new Validator(defaultSkipOnEmpty: new WhenNull()), |
||||
957 | new ArrayDataSet([ |
||||
958 | 'name' => 'Dmitriy', |
||||
959 | 'age' => 17, |
||||
960 | ]), |
||||
961 | $rules, |
||||
962 | [ |
||||
963 | new Error($stringLessThanMinMessage, [ |
||||
964 | 'min' => 8, |
||||
965 | 'attribute' => 'name', |
||||
966 | 'number' => 7, |
||||
967 | ], ['name']), |
||||
968 | new Error($intLessThanMinMessage, [ |
||||
969 | 'min' => 18, |
||||
970 | 'attribute' => 'age', |
||||
971 | 'value' => 17, |
||||
972 | ], ['age']), |
||||
973 | ], |
||||
974 | ], |
||||
975 | 'validator, skipOnEmpty: SkipOnNull, value is not empty (empty string)' => [ |
||||
976 | new Validator(defaultSkipOnEmpty: new WhenNull()), |
||||
977 | new ArrayDataSet([ |
||||
978 | 'name' => 'Dmitriy', |
||||
979 | 'age' => '', |
||||
980 | ]), |
||||
981 | $rules, |
||||
982 | [ |
||||
983 | new Error($stringLessThanMinMessage, [ |
||||
984 | 'min' => 8, |
||||
985 | 'attribute' => 'name', |
||||
986 | 'number' => 7, |
||||
987 | ], ['name']), |
||||
988 | new Error($intMessage, [ |
||||
989 | 'attribute' => 'age', |
||||
990 | 'value' => '', |
||||
991 | ], ['age']), |
||||
992 | ], |
||||
993 | ], |
||||
994 | |||||
995 | 'validator, skipOnEmpty: custom callback, value not passed' => [ |
||||
996 | new Validator( |
||||
997 | defaultSkipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $value === 0 |
||||
0 ignored issues
–
show
The parameter
$isAttributeMissing is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
998 | ), |
||||
999 | new ArrayDataSet([ |
||||
1000 | 'name' => 'Dmitriy', |
||||
1001 | ]), |
||||
1002 | $rules, |
||||
1003 | [ |
||||
1004 | new Error($stringLessThanMinMessage, [ |
||||
1005 | 'min' => 8, |
||||
1006 | 'attribute' => 'name', |
||||
1007 | 'number' => 7, |
||||
1008 | ], ['name']), |
||||
1009 | new Error($incorrectNumberMessage, [ |
||||
1010 | 'attribute' => 'age', |
||||
1011 | 'type' => 'null', |
||||
1012 | ], ['age']), |
||||
1013 | ], |
||||
1014 | ], |
||||
1015 | 'validator, skipOnEmpty: custom callback, value is empty' => [ |
||||
1016 | new Validator( |
||||
1017 | defaultSkipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $value === 0 |
||||
0 ignored issues
–
show
The parameter
$isAttributeMissing is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
1018 | ), |
||||
1019 | new ArrayDataSet([ |
||||
1020 | 'name' => 'Dmitriy', |
||||
1021 | 'age' => 0, |
||||
1022 | ]), |
||||
1023 | $rules, |
||||
1024 | [ |
||||
1025 | new Error($stringLessThanMinMessage, [ |
||||
1026 | 'min' => 8, |
||||
1027 | 'attribute' => 'name', |
||||
1028 | 'number' => 7, |
||||
1029 | ], ['name']), |
||||
1030 | ], |
||||
1031 | ], |
||||
1032 | 'validator, skipOnEmpty: custom callback, value is not empty' => [ |
||||
1033 | new Validator( |
||||
1034 | defaultSkipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $value === 0 |
||||
0 ignored issues
–
show
The parameter
$isAttributeMissing is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
1035 | ), |
||||
1036 | new ArrayDataSet([ |
||||
1037 | 'name' => 'Dmitriy', |
||||
1038 | 'age' => 17, |
||||
1039 | ]), |
||||
1040 | $rules, |
||||
1041 | [ |
||||
1042 | new Error($stringLessThanMinMessage, [ |
||||
1043 | 'min' => 8, |
||||
1044 | 'attribute' => 'name', |
||||
1045 | 'number' => 7, |
||||
1046 | ], ['name']), |
||||
1047 | new Error($intLessThanMinMessage, [ |
||||
1048 | 'min' => 18, |
||||
1049 | 'attribute' => 'age', |
||||
1050 | 'value' => 17, |
||||
1051 | ], ['age']), |
||||
1052 | ], |
||||
1053 | ], |
||||
1054 | 'validator, skipOnEmpty: custom callback, value is not empty (null)' => [ |
||||
1055 | new Validator( |
||||
1056 | defaultSkipOnEmpty: static fn (mixed $value, bool $isAttributeMissing): bool => $value === 0 |
||||
0 ignored issues
–
show
The parameter
$isAttributeMissing is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
1057 | ), |
||||
1058 | new ArrayDataSet([ |
||||
1059 | 'name' => 'Dmitriy', |
||||
1060 | 'age' => null, |
||||
1061 | ]), |
||||
1062 | $rules, |
||||
1063 | [ |
||||
1064 | new Error($stringLessThanMinMessage, [ |
||||
1065 | 'min' => 8, |
||||
1066 | 'attribute' => 'name', |
||||
1067 | 'number' => 7, |
||||
1068 | ], ['name']), |
||||
1069 | new Error($incorrectNumberMessage, [ |
||||
1070 | 'attribute' => 'age', |
||||
1071 | 'type' => 'null', |
||||
1072 | ], ['age']), |
||||
1073 | ], |
||||
1074 | ], |
||||
1075 | ]; |
||||
1076 | } |
||||
1077 | |||||
1078 | /** |
||||
1079 | * @param StubDumpedRule[] $rules |
||||
1080 | * @param Error[] $expectedErrors |
||||
1081 | * |
||||
1082 | * @dataProvider skipOnEmptyDataProvider |
||||
1083 | */ |
||||
1084 | public function testSkipOnEmpty(Validator $validator, ArrayDataSet $data, array $rules, array $expectedErrors): void |
||||
1085 | { |
||||
1086 | $result = $validator->validate($data, $rules); |
||||
1087 | $this->assertEquals($expectedErrors, $result->getErrors()); |
||||
1088 | } |
||||
1089 | |||||
1090 | public function initSkipOnEmptyDataProvider(): array |
||||
1091 | { |
||||
1092 | return [ |
||||
1093 | 'null' => [ |
||||
1094 | null, |
||||
1095 | new class () { |
||||
1096 | #[Number] |
||||
1097 | public ?string $name = null; |
||||
1098 | }, |
||||
1099 | false, |
||||
1100 | ], |
||||
1101 | 'false' => [ |
||||
1102 | false, |
||||
1103 | new class () { |
||||
1104 | #[Number] |
||||
1105 | public ?string $name = null; |
||||
1106 | }, |
||||
1107 | false, |
||||
1108 | ], |
||||
1109 | 'true' => [ |
||||
1110 | true, |
||||
1111 | new class () { |
||||
1112 | #[Number] |
||||
1113 | public ?string $name = null; |
||||
1114 | }, |
||||
1115 | true, |
||||
1116 | ], |
||||
1117 | 'callable' => [ |
||||
1118 | new WhenNull(), |
||||
1119 | new class () { |
||||
1120 | #[Number] |
||||
1121 | public ?string $name = null; |
||||
1122 | }, |
||||
1123 | true, |
||||
1124 | ], |
||||
1125 | 'do-not-override-rule' => [ |
||||
1126 | false, |
||||
1127 | new class () { |
||||
1128 | #[Number(skipOnEmpty: true)] |
||||
1129 | public string $name = ''; |
||||
1130 | }, |
||||
1131 | true, |
||||
1132 | ], |
||||
1133 | ]; |
||||
1134 | } |
||||
1135 | |||||
1136 | /** |
||||
1137 | * @dataProvider initSkipOnEmptyDataProvider |
||||
1138 | */ |
||||
1139 | public function testInitSkipOnEmpty( |
||||
1140 | bool|callable|null $skipOnEmpty, |
||||
1141 | mixed $data, |
||||
1142 | bool $expectedResult, |
||||
1143 | ): void { |
||||
1144 | $validator = new Validator(defaultSkipOnEmpty: $skipOnEmpty); |
||||
1145 | |||||
1146 | $result = $validator->validate($data); |
||||
1147 | |||||
1148 | $this->assertSame($expectedResult, $result->isValid()); |
||||
1149 | } |
||||
1150 | |||||
1151 | public function testObjectWithAttributesOnly(): void |
||||
1152 | { |
||||
1153 | $object = new ObjectWithAttributesOnly(); |
||||
1154 | |||||
1155 | $validator = new Validator(); |
||||
1156 | |||||
1157 | $result = $validator->validate($object); |
||||
1158 | |||||
1159 | $this->assertFalse($result->isValid()); |
||||
1160 | $this->assertCount(1, $result->getErrorMessages()); |
||||
1161 | $this->assertStringStartsWith('This value must contain at least', $result->getErrorMessages()[0]); |
||||
1162 | } |
||||
1163 | |||||
1164 | public function testRuleWithoutSkipOnEmpty(): void |
||||
1165 | { |
||||
1166 | $validator = new Validator(defaultSkipOnEmpty: new WhenNull()); |
||||
1167 | |||||
1168 | $data = new class () { |
||||
1169 | #[NotNull] |
||||
1170 | public ?string $name = null; |
||||
1171 | }; |
||||
1172 | |||||
1173 | $result = $validator->validate($data); |
||||
1174 | |||||
1175 | $this->assertFalse($result->isValid()); |
||||
1176 | } |
||||
1177 | |||||
1178 | public function testValidateWithSingleRule(): void |
||||
1179 | { |
||||
1180 | $result = (new Validator())->validate(3, new Number(min: 5)); |
||||
1181 | |||||
1182 | $this->assertFalse($result->isValid()); |
||||
1183 | $this->assertSame( |
||||
1184 | ['' => ['Value must be no less than 5.']], |
||||
1185 | $result->getErrorMessagesIndexedByPath(), |
||||
1186 | ); |
||||
1187 | } |
||||
1188 | |||||
1189 | public function testComposition(): void |
||||
1190 | { |
||||
1191 | $validator = new class () implements ValidatorInterface { |
||||
1192 | private Validator $validator; |
||||
1193 | |||||
1194 | public function __construct() |
||||
1195 | { |
||||
1196 | $this->validator = new Validator(); |
||||
1197 | } |
||||
1198 | |||||
1199 | public function validate( |
||||
1200 | mixed $data, |
||||
1201 | callable|iterable|object|string|null $rules = null, |
||||
1202 | ?ValidationContext $context = null |
||||
1203 | ): Result { |
||||
1204 | $context ??= new ValidationContext(); |
||||
1205 | |||||
1206 | $result = $this->validator->validate($data, $rules, $context); |
||||
1207 | |||||
1208 | return $context->getParameter('forceSuccess') === true ? new Result() : $result; |
||||
1209 | } |
||||
1210 | }; |
||||
1211 | |||||
1212 | $rules = [ |
||||
1213 | static function ($value, $rule, ValidationContext $context) { |
||||
1214 | $context->setParameter('forceSuccess', true); |
||||
1215 | return (new Result())->addError('fail'); |
||||
1216 | }, |
||||
1217 | ]; |
||||
1218 | |||||
1219 | $result = $validator->validate([], $rules); |
||||
1220 | |||||
1221 | $this->assertTrue($result->isValid()); |
||||
1222 | } |
||||
1223 | |||||
1224 | public function testRulesWithWrongKey(): void |
||||
1225 | { |
||||
1226 | $validator = new Validator(); |
||||
1227 | |||||
1228 | $this->expectException(InvalidArgumentException::class); |
||||
1229 | $this->expectExceptionMessage('An attribute can only have an integer or a string type. bool given.'); |
||||
1230 | $validator->validate([], new IteratorWithBooleanKey()); |
||||
1231 | } |
||||
1232 | |||||
1233 | public function testRulesWithWrongRule(): void |
||||
1234 | { |
||||
1235 | $validator = new Validator(); |
||||
1236 | |||||
1237 | $this->expectException(InvalidArgumentException::class); |
||||
1238 | $message = 'Rule must be either an instance of Yiisoft\Validator\RuleInterface or a callable, int given.'; |
||||
1239 | $this->expectExceptionMessage($message); |
||||
1240 | $validator->validate([], [new BooleanValue(), 1]); |
||||
1241 | } |
||||
1242 | |||||
1243 | public function testRulesAsObjectNameWithRuleAttributes(): void |
||||
1244 | { |
||||
1245 | $validator = new Validator(); |
||||
1246 | $result = $validator->validate(['name' => 'Test name'], ObjectWithAttributesOnly::class); |
||||
1247 | $this->assertTrue($result->isValid()); |
||||
1248 | } |
||||
1249 | |||||
1250 | public function testRulesAsObjectWithRuleAttributes(): void |
||||
1251 | { |
||||
1252 | $validator = new Validator(); |
||||
1253 | $result = $validator->validate(['name' => 'Test name'], new ObjectWithAttributesOnly()); |
||||
1254 | $this->assertTrue($result->isValid()); |
||||
1255 | } |
||||
1256 | |||||
1257 | public function testDataSetWithPostValidationHook(): void |
||||
1258 | { |
||||
1259 | $validator = new Validator(); |
||||
1260 | $dataSet = new DataSetWithPostValidationHook(); |
||||
1261 | |||||
1262 | $result = $validator->validate($dataSet); |
||||
1263 | |||||
1264 | $this->assertTrue($result->isValid()); |
||||
1265 | $this->assertTrue($dataSet->hookCalled); |
||||
1266 | } |
||||
1267 | |||||
1268 | public function testObjectWithPostValidationHook(): void |
||||
1269 | { |
||||
1270 | $validator = new Validator(); |
||||
1271 | $object = new ObjectWithPostValidationHook(); |
||||
1272 | |||||
1273 | $result = $validator->validate($object); |
||||
1274 | |||||
1275 | $this->assertTrue($result->isValid()); |
||||
1276 | $this->assertTrue($object->hookCalled); |
||||
1277 | } |
||||
1278 | |||||
1279 | public function testSkippingRuleInPreValidate(): void |
||||
1280 | { |
||||
1281 | $data = ['agree' => false, 'viewsCount' => -1]; |
||||
1282 | $rules = [ |
||||
1283 | 'agree' => [new BooleanValue(skipOnEmpty: static fn (): bool => true), new TrueValue()], |
||||
1284 | 'viewsCount' => [new Integer(min: 0)], |
||||
1285 | ]; |
||||
1286 | $validator = new Validator(); |
||||
1287 | |||||
1288 | $result = $validator->validate($data, $rules); |
||||
1289 | $this->assertSame( |
||||
1290 | [ |
||||
1291 | 'agree' => ['The value must be "1".'], |
||||
1292 | 'viewsCount' => ['Value must be no less than 0.'], |
||||
1293 | ], |
||||
1294 | $result->getErrorMessagesIndexedByPath(), |
||||
1295 | ); |
||||
1296 | } |
||||
1297 | |||||
1298 | public function testDefaultTranslatorWithIntl(): void |
||||
1299 | { |
||||
1300 | $data = ['number' => 3]; |
||||
1301 | $rules = [ |
||||
1302 | 'number' => new Integer( |
||||
1303 | max: 2, |
||||
1304 | greaterThanMaxMessage: '{value, selectordinal, one{#-one} two{#-two} few{#-few} other{#-other}}', |
||||
1305 | ), |
||||
1306 | ]; |
||||
1307 | $validator = new Validator(); |
||||
1308 | |||||
1309 | $result = $validator->validate($data, $rules); |
||||
1310 | $this->assertSame(['number' => ['3-few']], $result->getErrorMessagesIndexedByPath()); |
||||
1311 | } |
||||
1312 | |||||
1313 | public function dataSimpleForm(): array |
||||
1314 | { |
||||
1315 | return [ |
||||
1316 | [ |
||||
1317 | [ |
||||
1318 | 'name' => [ |
||||
1319 | 'Имя плохое.', |
||||
1320 | ], |
||||
1321 | 'mail' => [ |
||||
1322 | 'This value is not a valid email address.', |
||||
1323 | ], |
||||
1324 | ], |
||||
1325 | null, |
||||
1326 | ], |
||||
1327 | [ |
||||
1328 | [ |
||||
1329 | 'name' => [ |
||||
1330 | 'name плохое.', |
||||
1331 | ], |
||||
1332 | 'mail' => [ |
||||
1333 | 'This value is not a valid email address.', |
||||
1334 | ], |
||||
1335 | ], |
||||
1336 | new ValidationContext(attributeTranslator: new NullAttributeTranslator()), |
||||
1337 | ], |
||||
1338 | ]; |
||||
1339 | } |
||||
1340 | |||||
1341 | /** |
||||
1342 | * @dataProvider dataSimpleForm |
||||
1343 | */ |
||||
1344 | public function testSimpleForm(array $expectedMessages, ?ValidationContext $validationContext): void |
||||
1345 | { |
||||
1346 | $form = new SimpleForm(); |
||||
1347 | |||||
1348 | $result = (new Validator())->validate($form, context: $validationContext); |
||||
1349 | |||||
1350 | $this->assertSame( |
||||
1351 | $expectedMessages, |
||||
1352 | $result->getErrorMessagesIndexedByPath() |
||||
1353 | ); |
||||
1354 | } |
||||
1355 | |||||
1356 | public function dataOriginalValueUsage(): array |
||||
1357 | { |
||||
1358 | $data = [ |
||||
1359 | 'null' => [null, null], |
||||
1360 | 'string' => ['hello', 'hello'], |
||||
1361 | 'integer' => [42, 42], |
||||
1362 | 'array' => [['param' => 7], ['param' => 7]], |
||||
1363 | 'array-data-set' => [['param' => 42], new ArrayDataSet(['param' => 42])], |
||||
1364 | 'single-value-data-set' => [7, new SingleValueDataSet(7)], |
||||
1365 | ]; |
||||
1366 | |||||
1367 | $object = new stdClass(); |
||||
1368 | $data['object'] = [$object, $object]; |
||||
1369 | |||||
1370 | $simpleDto = new SimpleDto(); |
||||
1371 | $data['object-data-set'] = [$simpleDto, new ObjectDataSet($simpleDto)]; |
||||
1372 | |||||
1373 | return $data; |
||||
1374 | } |
||||
1375 | |||||
1376 | /** |
||||
1377 | * @dataProvider dataOriginalValueUsage |
||||
1378 | */ |
||||
1379 | public function testOriginalValueUsage(mixed $expectedValue, mixed $value): void |
||||
1380 | { |
||||
1381 | $valueHandled = false; |
||||
1382 | $valueInHandler = null; |
||||
1383 | |||||
1384 | (new Validator())->validate( |
||||
1385 | $value, |
||||
1386 | static function ($value) use (&$valueHandled, &$valueInHandler): Result { |
||||
1387 | $valueHandled = true; |
||||
1388 | $valueInHandler = $value; |
||||
1389 | return new Result(); |
||||
1390 | }, |
||||
1391 | ); |
||||
1392 | |||||
1393 | $this->assertTrue($valueHandled); |
||||
1394 | $this->assertSame($expectedValue, $valueInHandler); |
||||
1395 | } |
||||
1396 | |||||
1397 | public function testRuleWithBuiltInHandler(): void |
||||
1398 | { |
||||
1399 | $rule = new RuleWithBuiltInHandler(); |
||||
1400 | |||||
1401 | $result = (new Validator())->validate(19, $rule); |
||||
1402 | |||||
1403 | $this->assertSame( |
||||
1404 | ['' => ['Value must be 42.']], |
||||
1405 | $result->getErrorMessagesIndexedByPath() |
||||
1406 | ); |
||||
1407 | } |
||||
1408 | |||||
1409 | public function testDifferentValueAsArrayInSameContext(): void |
||||
1410 | { |
||||
1411 | $result = (new Validator())->validate( |
||||
1412 | ['x' => ['a' => 1, 'b' => 2]], |
||||
1413 | [ |
||||
1414 | new AtLeast(['x']), |
||||
1415 | 'x' => new AtLeast(['a', 'b']), |
||||
1416 | ], |
||||
1417 | ); |
||||
1418 | $this->assertTrue($result->isValid()); |
||||
1419 | } |
||||
1420 | |||||
1421 | public function dataErrorMessagesWithLabels(): array |
||||
1422 | { |
||||
1423 | return [ |
||||
1424 | [ |
||||
1425 | new class () { |
||||
1426 | #[Label('Test')] |
||||
1427 | #[Length( |
||||
1428 | min: 20, |
||||
1429 | lessThanMinMessage: '{attribute} value must contain at least {min, number} {min, plural, ' . |
||||
1430 | 'one{character} other{characters}}.', |
||||
1431 | )] |
||||
1432 | public string $property = 'test'; |
||||
1433 | }, |
||||
1434 | ['property' => ['Test value must contain at least 20 characters.']], |
||||
1435 | ], |
||||
1436 | [ |
||||
1437 | new ObjectWithLabelsProvider(), |
||||
1438 | [ |
||||
1439 | 'name' => ['Имя cannot be blank.'], |
||||
1440 | 'age' => ['Возраст must be no less than 21.'], |
||||
1441 | ], |
||||
1442 | ], |
||||
1443 | ]; |
||||
1444 | } |
||||
1445 | |||||
1446 | /** |
||||
1447 | * @dataProvider dataErrorMessagesWithLabels |
||||
1448 | */ |
||||
1449 | public function testErrorMessagesWithLabels( |
||||
1450 | mixed $data, |
||||
1451 | array $expectedErrorMessages, |
||||
1452 | ): void { |
||||
1453 | $validator = new Validator(); |
||||
1454 | $result = $validator->validate($data, $data); |
||||
1455 | $this->assertSame($expectedErrorMessages, $result->getErrorMessagesIndexedByAttribute()); |
||||
1456 | } |
||||
1457 | } |
||||
1458 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.