Skip to content
This repository was archived by the owner on Sep 13, 2024. It is now read-only.

Commit 1ab78a9

Browse files
authored
Merge pull request #10 from VladimirBerdnik/feature/rule-when
Add conditional rule set building possibility
2 parents f616d79 + 2acbc9a commit 1ab78a9

File tree

5 files changed

+156
-2
lines changed

5 files changed

+156
-2
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changes History
22

3+
1.0.11
4+
------
5+
Added when() method that allows to build rules according to conditions
6+
37
1.0.10
48
------
59
Enum rule. See https://github.com/Saritasa/php-common#enum

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ Use fluent-style syntax to build [Laravel validation rules](https://laravel.com/
1313
$rules = [
1414
'id' => Rule::int()->required(),
1515
'name' => Rule::string()->required()->minLength(3)->toString(),
16+
'salary' => Rule::int()->when($isPHPDeveloper,
17+
function($ruleWhenTrue) {
18+
return $ruleWhenTrue->min(1000000);
19+
},
20+
function($ruleWhenFalse) {
21+
return $ruleWhenFalse->max(1000);
22+
}
23+
),
1624
'email' => Rule::string()->required()->email()->toArray()
1725
]
1826
```

src/Rule.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
6464
* @method static DatabaseRuleSet exists(string $table, string $column, \Closure $closure = null) Get a exists constraint builder instance.
6565
* @method static DatabaseRuleSet unique(string $table, string $column, \Closure $closure = null) Get a unique constraint builder instance.
66+
*
67+
* @method static RuleSet when($condition, \Closure $trueCallback, \Closure $falseCallback = null): RuleSet Performs conditional building of rule set.
6668
6769
*/
6870
class Rule

src/RuleSet.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class RuleSet implements IRule
5151
'size',
5252
'sometimes',
5353
'custom',
54+
'when',
5455
];
5556

5657
/**
@@ -116,6 +117,34 @@ protected static function mergeIfNotExists(string $rule, array $rules = []): arr
116117
}
117118
}
118119

120+
/**
121+
* Performs conditional building of rule set.
122+
*
123+
* @param mixed $condition Condition to check
124+
* @param \Closure $trueCallback Callback that will be called when condition is TRUE.
125+
* Receives current rule set value and should return instance of RuleSer class.
126+
* @param \Closure|null $falseCallback Callback that will be called when condition is FALSE.
127+
* Receives current rule set value and should return instance of RuleSer class.
128+
*
129+
* @return RuleSet
130+
*/
131+
public function when($condition, \Closure $trueCallback, \Closure $falseCallback = null): RuleSet
132+
{
133+
if ((bool)$condition) {
134+
$result = $trueCallback($this);
135+
} elseif ($falseCallback !== null) {
136+
$result = $falseCallback($this);
137+
} else {
138+
$result = $this;
139+
}
140+
141+
if (!is_a($result, RuleSet::class)) {
142+
throw new \UnexpectedValueException('Callback should return instance of [' . RuleSet::class . '] class');
143+
}
144+
145+
return $result;
146+
}
147+
119148
/** Return current rule set as array */
120149
public function toArray(): array
121150
{

tests/RuleTest.php

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
namespace Saritasa\Laravel\Validation\Tests;
44

5+
use Illuminate\Support\Facades\Config;
56
use Illuminate\Support\Str;
67
use PHPUnit\Framework\TestCase;
78
use Saritasa\Enums\Gender;
89
use Saritasa\Exceptions\NotImplementedException;
910
use Saritasa\Laravel\Validation\Rule;
1011
use Saritasa\Laravel\Validation\RuleSet;
12+
use UnexpectedValueException;
1113

1214
/**
1315
* Test basic features
@@ -101,10 +103,10 @@ public function testMixed()
101103
$rules = Rule::string()->required()->min(3);
102104
$this->assertEquals('string|required|min:3', $rules);
103105

104-
$this->assertEquals('string|email|nullable|present', Rule::email()->nullable()->present());
106+
$this->assertEquals('string|email|nullable|present', Rule::email()->nullable()->present());
105107

106108
$rules = Rule::requiredWithout('facebook_token')->confirmed();
107-
$this->assertEquals('required_without:facebook_token|confirmed', $rules);
109+
$this->assertEquals('required_without:facebook_token|confirmed', $rules);
108110
}
109111

110112

@@ -116,4 +118,113 @@ public function testNonExistent()
116118
$this->expectException(NotImplementedException::class);
117119
Rule::nonExistent();
118120
}
121+
122+
/**
123+
* Test that rule appended inside true callback of when() method.
124+
*/
125+
public function testWhenTrueCallback()
126+
{
127+
$isPHPDeveloper = true;
128+
129+
$salaryRule = Rule::int()->when($isPHPDeveloper,
130+
function(RuleSet $ruleWhenTrue) {
131+
return $ruleWhenTrue->min(1000000);
132+
},
133+
function(RuleSet $ruleWhenFalse) {
134+
return $ruleWhenFalse->max(1000);
135+
}
136+
);
137+
138+
$this->assertEquals('integer|min:1000000', $salaryRule->toString());
139+
}
140+
141+
/**
142+
* Test that rule appended inside false callback of when() method.
143+
*/
144+
public function testWhenFalseCallback()
145+
{
146+
$rule = Rule::string()->when(
147+
false,
148+
function (RuleSet $rule) {
149+
return $rule->max(10); // Should not be executed as passed condition is false
150+
},
151+
function (RuleSet $rule) {
152+
return $rule->min(10); // Should be executed as passed condition if false
153+
}
154+
);
155+
156+
$this->assertEquals('string|min:10', $rule->toString());
157+
}
158+
159+
/**
160+
* Test that rule leaves the same when condition is false and false callback not passed to when() method.
161+
*/
162+
public function testWhenFalseCallbackNotPassed()
163+
{
164+
$rule = Rule::string()->when(
165+
false,
166+
function (RuleSet $rule) {
167+
return $rule->max(10); // Should not be executed as passed condition is false
168+
}
169+
);
170+
171+
$this->assertEquals('string', $rule->toString());
172+
}
173+
174+
/**
175+
* Test that callback of when() method should return instance of RuleSet class.
176+
*/
177+
public function testWhenUnexpectedResultInCallback()
178+
{
179+
$this->expectException(UnexpectedValueException::class);
180+
181+
Rule::string()->when(true, function () {
182+
return 'min:10'; // Invalid value. Instance of RuleSet expected
183+
});
184+
}
185+
186+
/**
187+
* Test that rule appended inside callback of when() method and inside of this callback.
188+
*/
189+
public function testDeepWhenCallback()
190+
{
191+
$rule = Rule::string()
192+
->when(true, function (RuleSet $rule) { // First level of condition
193+
return $rule->max(10)
194+
->when(true, function (RuleSet $rule) { // Second level of condition
195+
return $rule->nullable();
196+
});
197+
});
198+
199+
$this->assertEquals('string|max:10|nullable', $rule->toString());
200+
}
201+
202+
/**
203+
* Test that method when() works from static call of Rule class.
204+
*/
205+
public function testWhenFromRuleClass()
206+
{
207+
$rule = Rule::when(true, function (RuleSet $rule) {
208+
return $rule->required()->max(10);
209+
});
210+
211+
$this->assertEquals('required|max:10', $rule->toString());
212+
}
213+
214+
/**
215+
* Test that method when() works in instance of DatabaseRuleSet class (not only from GenericRuleSet).
216+
*/
217+
public function testWhenFromDatabaseRuleSetClass()
218+
{
219+
Config::shouldReceive('get')->with('validation.allow_db', false)->andReturn(true);
220+
221+
$rule = Rule::exists('users', 'id')
222+
->when(true, function (RuleSet $rule) {
223+
return $rule->nullable();
224+
});
225+
226+
$this->assertEquals('exists:users,id|nullable', $rule->toString());
227+
228+
Config::clearResolvedInstances();
229+
}
119230
}

0 commit comments

Comments
 (0)