Skip to content

Commit 5b42ec1

Browse files
committed
Stops validation if a custom rule specifies it
1 parent dc63a5d commit 5b42ec1

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Illuminate\Contracts\Validation;
4+
5+
interface StopUponFailure
6+
{
7+
/**
8+
* Trigger the validation of the field to no longer continue.
9+
*
10+
* @return bool
11+
*/
12+
public function shouldStop(): bool;
13+
}

src/Illuminate/Validation/Validator.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
use Illuminate\Contracts\Validation\DataAwareRule;
99
use Illuminate\Contracts\Validation\ImplicitRule;
1010
use Illuminate\Contracts\Validation\Rule as RuleContract;
11+
use Illuminate\Contracts\Validation\StopUponFailure;
12+
use Illuminate\Contracts\Validation\ValidationRule;
1113
use Illuminate\Contracts\Validation\Validator as ValidatorContract;
1214
use Illuminate\Contracts\Validation\ValidatorAwareRule;
1315
use Illuminate\Support\Arr;
@@ -480,7 +482,7 @@ public function passes()
480482
break;
481483
}
482484

483-
if ($this->shouldStopValidating($attribute)) {
485+
if ($this->shouldStopValidating($attribute, $rule)) {
484486
break;
485487
}
486488
}
@@ -907,16 +909,21 @@ protected function validateUsingCustomRule($attribute, $value, $rule)
907909
* Check if we should stop further validations on a given attribute.
908910
*
909911
* @param string $attribute
912+
* @param string|ValidationRule
910913
* @return bool
911914
*/
912-
protected function shouldStopValidating($attribute)
915+
protected function shouldStopValidating($attribute, $rule)
913916
{
914917
$cleanedAttribute = $this->replacePlaceholderInString($attribute);
915918

916919
if ($this->hasRule($attribute, ['Bail'])) {
917920
return $this->messages->has($cleanedAttribute);
918921
}
919922

923+
if ($rule instanceof InvokableValidationRule && $rule->invokable() instanceof StopUponFailure) {
924+
return $rule->invokable()->shouldStop();
925+
}
926+
920927
if (isset($this->failedRules[$cleanedAttribute]) &&
921928
array_key_exists('uploaded', $this->failedRules[$cleanedAttribute])) {
922929
return true;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Validation;
4+
5+
use Closure;
6+
use Illuminate\Contracts\Validation\StopUponFailure;
7+
use Illuminate\Contracts\Validation\ValidationRule;
8+
use Illuminate\Translation\ArrayLoader;
9+
use Illuminate\Translation\Translator;
10+
use Illuminate\Validation\Validator;
11+
use PHPUnit\Framework\TestCase;
12+
13+
class ValidationStopOnFailureTest extends TestCase
14+
{
15+
public function testFailingStopsFurtherValidation()
16+
{
17+
$trans = new Translator(new ArrayLoader, 'en');
18+
$v = new Validator(
19+
$trans,
20+
['foo' => 'foobar'],
21+
['foo' => [new StoppingValidationRule(), 'numeric']],
22+
);
23+
$this->assertFalse($v->passes());
24+
$this->assertEquals(
25+
['foo' => ['Illuminate\Tests\Validation\StoppingValidationRule' => []]],
26+
$v->failed()
27+
);
28+
}
29+
}
30+
31+
class StoppingValidationRule implements ValidationRule, StopUponFailure
32+
{
33+
public function shouldStop(): bool
34+
{
35+
return true;
36+
}
37+
38+
public function validate(string $attribute, mixed $value, Closure $fail): void
39+
{
40+
$fail('failed');
41+
}
42+
}

0 commit comments

Comments
 (0)