Reputation: 493
I'm trying to create a validator that require at least one of three input.
I tried this
protected function validateFundingSource (): array
{
return request()->validate([
'title' => 'required',
'description' => 'required',
'national' => 'nullable',
'province' => Rule::requiredIf(!request('national')),
'url' => [
'required_without_all:phone,email',
'active_url'
],
'phone' => [
'required_without_all:url,email|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im'
],
'email' => [
'required_without_all:url,phone|email:rfc,dns'
],
'categories' => 'exists:categories,id'
]);
}
But it was was forcing only the first field (url). So I tried with Complex Conditional Validation.
protected function validateFundingSource ()
{
$v = Validator::make(request()->all(), [
'title' => 'required',
'description' => 'required',
'national' => 'nullable',
'categories' => 'exists:categories,id',
]);
$v->sometimes('province', 'required', function ($input) {
return ($input->national === null) ;
});
$v->sometimes('url', 'required|active_url', function ($input) {
return (($input->phone === null) && ($input->email === null));
});
$v->sometimes('phone', 'required|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im', function ($input) {
return (($input->url === null) && ($input->email === null));
});
$v->sometimes('email', 'required|email:rfc,dns', function ($input) {
return (($input->url === null) && ($input->phone === null));
});
return $v;
}
But still no luck... Now it's never required I can submit all three empty field and it's working...
Any clues to help me please ?
Thank you !
Upvotes: 3
Views: 3201
Reputation: 42720
If you're looking for "at least one of" url
, phone
, or email
then you want to use required_without
. This rule means the field is required when any of the specified fields are missing; required_without_all
means it's required when all of the specified fields are missing.
You are also confusing rule syntax, you must use either array or pipe-delimited string syntax, not both at once.
You may want to improve your phone number regex as well; + -. (000-111.9999 #8
is not a great phone number, but would pass your validation. I'd suggest sanitizing your value to remove everything except digits and a leading +, then using a better pattern on what's left.
And, it's just a cosmetic change but you can replace Rule::requiredIf(!request('national')),
with a simple required_if
rule like the others.
Changing to a form request validation, this would look like:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreFundingsource extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$phone = preg_replace("/[^0-9]/", "", $this->phone);
if (strpos($this->phone, "+") === 0) {
$phone = "+$phone";
}
$this->merge(["phone"=>$phone]);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => ['required'],
'description' => ['required'],
'national' => ['nullable'],
'province' => ['required_if,national,'],
'categories' => ['exists:categories,id']
'url' => [
'required_without:phone,email',
'active_url'
],
'phone' => [
'required_without:url,email',
'regex:/^\+?1?[2-9][0-9]{5,14}$/'
],
'email' => [
'required_without:url,phone',
'email:rfc,dns'
],
];
}
}
Upvotes: 2
Reputation: 546
You code is working fine. you just forget to check if validate pass or not. because when you use Validator::make you need to manually check it. for request()->validate laravel will do it for you. inside your validateFundingSource () function just check it pass validate or not before return like this:
private function validateFundingSource () {
$v = Validator::make(request()->all(), [
'title' => 'required',
'description' => 'required',
'national' => 'nullable',
'categories' => 'exists:categories,id',
]);
$v->sometimes('province', 'required', function ($input) {
return ($input->national === null) ;
});
$v->sometimes('url', 'required|active_url', function ($input) {
return (($input->phone === null) && ($input->email === null));
});
$v->sometimes('phone', 'required|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im', function ($input) {
return (($input->url === null) && ($input->email === null));
});
$v->sometimes('email', 'required|email:rfc,dns', function ($input) {
return (($input->url === null) && ($input->phone === null));
});
// check if validae failed
if($v->fails()) {
dd('fail', $v); // do something when it failed
}
}
also sorry for my bad English & hope it help
Upvotes: 2