@@ -342,6 +342,35 @@ static function ($value, $data, &$error, $field): bool {
342342 $ this ->assertSame ([], $ this ->validation ->getValidated ());
343343 }
344344
345+ public function testClosureRuleWithParamErrorPlaceholders (): void
346+ {
347+ $ this ->validation ->setRules ([
348+ 'status ' => [
349+ 'label ' => 'Status ' ,
350+ 'rules ' => [
351+ static function ($ value , $ data , &$ error , $ field ): bool {
352+ if ($ value !== 'active ' ) {
353+ $ error = 'The field {field} must be one of: {param}. Received: {value} ' ;
354+
355+ return false ;
356+ }
357+
358+ return true ;
359+ },
360+ ],
361+ ],
362+ ]);
363+
364+ $ data = ['status ' => 'invalid ' ];
365+ $ result = $ this ->validation ->run ($ data );
366+
367+ $ this ->assertFalse ($ result );
368+ $ this ->assertSame (
369+ ['status ' => 'The field Status must be one of: . Received: invalid ' ],
370+ $ this ->validation ->getErrors (),
371+ );
372+ }
373+
345374 public function testClosureRuleWithLabel (): void
346375 {
347376 $ this ->validation ->setRules ([
@@ -415,6 +444,22 @@ public function rule2(mixed $value, array $data, ?string &$error, string $field)
415444 return true ;
416445 }
417446
447+ /**
448+ * Validation rule3
449+ *
450+ * @param array<string, mixed> $data
451+ */
452+ public function rule3 (mixed $ value , array $ data , ?string &$ error , string $ field ): bool
453+ {
454+ if ($ value !== 'active ' ) {
455+ $ error = 'The field {field} must be one of: {param}. Received: {value} ' ;
456+
457+ return false ;
458+ }
459+
460+ return true ;
461+ }
462+
418463 public function testCallableRuleWithParamError (): void
419464 {
420465 $ this ->validation ->setRules ([
@@ -435,6 +480,68 @@ public function testCallableRuleWithParamError(): void
435480 $ this ->assertSame ([], $ this ->validation ->getValidated ());
436481 }
437482
483+ public function testCallableRuleWithParamErrorPlaceholders (): void
484+ {
485+ $ this ->validation ->setRules ([
486+ 'status ' => [
487+ 'label ' => 'Status ' ,
488+ 'rules ' => [$ this ->rule3 (...)],
489+ ],
490+ ]);
491+
492+ $ data = ['status ' => 'invalid ' ];
493+ $ result = $ this ->validation ->run ($ data );
494+
495+ $ this ->assertFalse ($ result );
496+ $ this ->assertSame (
497+ ['status ' => 'The field Status must be one of: . Received: invalid ' ],
498+ $ this ->validation ->getErrors (),
499+ );
500+ }
501+
502+ public function testRuleSetRuleWithParamErrorPlaceholders (): void
503+ {
504+ $ this ->validation ->setRules ([
505+ 'status ' => [
506+ 'label ' => 'Status ' ,
507+ 'rules ' => 'custom_error_with_param[active,inactive] ' ,
508+ ],
509+ ]);
510+
511+ $ data = ['status ' => 'invalid ' ];
512+ $ result = $ this ->validation ->run ($ data );
513+
514+ $ this ->assertFalse ($ result );
515+ $ this ->assertSame (
516+ ['status ' => 'The Status must be one of: active,inactive. Got: invalid ' ],
517+ $ this ->validation ->getErrors (),
518+ );
519+ }
520+
521+ public function testClosureRuleErrorWithUnknownPlaceholderPreserved (): void
522+ {
523+ $ this ->validation ->setRules ([
524+ 'status ' => [
525+ 'rules ' => [
526+ static function ($ value , $ data , &$ error , $ field ): bool {
527+ $ error = 'Value {value} is invalid. See {link} for details. ' ;
528+
529+ return false ;
530+ },
531+ ],
532+ ],
533+ ]);
534+
535+ $ data = ['status ' => 'bad ' ];
536+ $ result = $ this ->validation ->run ($ data );
537+
538+ $ this ->assertFalse ($ result );
539+ $ this ->assertSame (
540+ ['status ' => 'Value bad is invalid. See {link} for details. ' ],
541+ $ this ->validation ->getErrors (),
542+ );
543+ }
544+
438545 public function testCallableRuleWithLabel (): void
439546 {
440547 $ this ->validation ->setRules ([
0 commit comments