Skip to content

Commit cb9ff13

Browse files
committed
Stops validation if a custom rule specifies it
1 parent abf823f commit cb9ff13

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;
@@ -482,7 +484,7 @@ public function passes()
482484
break;
483485
}
484486

485-
if ($this->shouldStopValidating($attribute)) {
487+
if ($this->shouldStopValidating($attribute, $rule)) {
486488
break;
487489
}
488490
}
@@ -909,16 +911,21 @@ protected function validateUsingCustomRule($attribute, $value, $rule)
909911
* Check if we should stop further validations on a given attribute.
910912
*
911913
* @param string $attribute
914+
* @param string|ValidationRule
912915
* @return bool
913916
*/
914-
protected function shouldStopValidating($attribute)
917+
protected function shouldStopValidating($attribute, $rule)
915918
{
916919
$cleanedAttribute = $this->replacePlaceholderInString($attribute);
917920

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

925+
if ($rule instanceof InvokableValidationRule && $rule->invokable() instanceof StopUponFailure) {
926+
return $rule->invokable()->shouldStop();
927+
}
928+
922929
if (isset($this->failedRules[$cleanedAttribute]) &&
923930
array_key_exists('uploaded', $this->failedRules[$cleanedAttribute])) {
924931
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)