Reputation: 41
I have a problem, how do you add / remove a rule if another rule passed/fails?
public function rules()
{
$rules = [
'description' => 'required|unique:orders,description',
'user_id' => 'required|unique:users,id',
'supplier_id' => 'required',
'warehouse_id' => 'required|unique:warehouse,id',
'warehouse_qty' => 'required'
];
return $rules;
}
For example, if the "warehouse_id" rule fails, it would not be necessary to evaluate the "warehouse_qty" field's rules (since the warehouse id is not found in the db).
Or if the "user_id" field's rule succeeds, new rules should be activated, like for "user_name" and "user_phone" fields.
Thanks!
Upvotes: 2
Views: 2836
Reputation: 8751
To validate a field only if another passes validation, there are multiple solutions.
Since Laravel 5.3.23; Simply move any field validation that depends on another field's rules, into Controller's withValidator(...)
method, like:
use Illuminate\Support\Facades\Validator;
// ...
public function withValidator($validator)
{
$validator->after(function ($validator) {
// Skip if any previous field was invalid.
if ($validator->failed()) return;
// Actual validation (for fields depending on previous).
Validator::make($this->input(), [
'warehouse_qty' => ['required']
])->validate();
});
}
This has the advantage of simply using existing rules, as you would normally (instead of rewriting the "required
" rule's source-code, which the below approach does).
See also related Laracast post.
Note that if
rules()
method is not defined,withValidator(...)
is never called (and calling$this->input()
may result in function not defined error).
Since Laravel 5.6 and later we can do below:
use Illuminate\Support\Facades\Validator;
// ...
public function rules()
{
$result = [
// ...
'warehouse_id' => 'required|unique:warehouse,id',
];
if (Validator::make($this->input(), $result)->passes()) {
$result['warehouse_qty'] = [
function ($attribute, $value, $fail) {
if (empty($value)) {
$fail('The '.$attribute.' is required.');
}
},
];
}
return $result;
}
Note that for above to work, the fields order is important, and the
closure
should be added to array right after the fields it is depending on.
-------===-------
While above are custom approaches (for asked matter), doing that for rules of the same field is built-in Laravel.
|
character) to separate rules.Simply because any rule after the failed one is ignored.
Upvotes: 3
Reputation: 41
Thanks to all who gave their solutions to my problem, especially Top-Master, since his explanation showed me another point of view.
I was finally able to solve my problem, and this is my solution. If anyone can improve the code, it is welcome.
public function rules()
{
$rules = [
'description' => 'required|unique:orders,description',
'user_id' => 'required|unique:users,id',
'supplier_id' => 'required'
];
$rules = $this->validateItems($rules);
return $rules;
}
public function validateItems($rules){
$rules["warehouse_id"] = ['required',
'unique:warehouse,id'];
//Here I validate if the rules of the "warehouse_id" field fail or not.
$validator = Validator::make($this->input('warehouse_id'), [
"id" => ['required',
'unique:warehouse,id']
]);
//If the validation doesn't fail, the "warehouse_qty" field is added to $rule
if(!($validator->fails())){
$rules["warehouse_qty"] = ['required'];
}
}
return $rules;
}
Upvotes: 0