Validate a field using another field - laravel

I have a dynamic phone number validation rule, and I need 2 values for it: number and country.
The library I'm using to validate the phone number is brick/phonenumber which can include the country code to parse it accurately.
So, my current working approach looks like this:
$request->validate([
'country' => ['required', 'max:2'],
]);
$request->validate([
'number' => ['required', new PhoneNumberValidator($request->input('country')],
]);
Because when I put it like this:
$request->validate([
'country' => ['required', 'max:2'],
'number' => ['required', new PhoneNumberValidator($request->input('country'))],
]);
The number validation runs even if the country is not valid. So I'd like to know if there's a way to have all the validations in one validate() call, so, having the country value validated before calling the number rule (I tried with bail but that stops the validations for 1 attribute, not the rest of attributes in the queue).

You can create a custom rule and validate both inputs at the same time.
You may also want to look at the various validation rules. You might find something helpful.

Related

Laravel validation - Different Attributes Specifications

I'm using a LaravelMiddleware, which should check for Access.
Therefore, I check for a specific Attributes, which sometimes have different names.
EG:
$request->key
$request->moduleKey
Im asking if there is a possiblitiy to check for 2 different attributes specifications?
Like so:
$data = $request->validate([
'key|moduleKey' => ['required', 'numeric'],
]);
It's not possible this way, but you have 2 other options:
Validation
https://laravel.com/docs/9.x/validation#rule-required-without
$data = $request->validate([
'key' => ['required_without:moduleKey', 'numeric'],
'moduleKey' => ['required_without:key', 'numeric'],
]);
but the problem is you still dont know which one you need unless you always get them both: $data['key'] ?? $data['moduleKey']
You can also update the request beforenhand:
$request['key'] = $request['key'] ?? $request['moduleKey'];
$data = $request->validate([rules]);
this code above you could put in a middleware to make sure every request always have the "key" variable in the request.

Array Validation: unique validation on multiple columns

I am trying to check unique validation on three columns employee_id,designation_id,station_id but the data are coming as an array which is making my situation unique and different from other SO questions/answers. I already checked few question like below: checks unique validation on multiple columns
But in my case, I can't get the value as they are inside an array. I also tried to implement Custom Rule or Request but in vain. For all the attempts, I am failing to get the field value such as $request->employee_id as they are inside an array for my case. May be I'm not trying it right.
Controller Code:
$this->validate($request, [
'posting.*.employee_id' => 'required,unique: // what to do here ??',
'posting.*.designation_id' => 'required',
'posting.*.station_id' => 'required',
'posting.*.from_date' => 'required|date',
]);
I am trying to validate uniqueness for both create and update (along with ignore $this->id facility) but don't know how to implement it here for array. It would be no problem if there was no array. Any help/suggestion/guide is much appreciated. Thanks in advance.
You can do this by creating a rule i.e UniquePosting so your controller code would look like
$this->validate($request, [
'posting' => ['required'],
'posting.*' => ['required', new UniquePosting()],
'posting.*.employee_id' => 'required',
'posting.*.designation_id' => 'required',
'posting.*.station_id' => 'required',
'posting.*.from_date' => 'required|date',
]);
Now inside your UniquePosting rule passes function will look like
public function passes($attribute, $value) {
$exists = Posting::where(['employee_id' => $value['employee_id'], 'designation_id' => $value['designation_id'],'station_id' => $value['station_id')->exists();
return !$exists;
}
Add any change if needed, overall that's the concept for testing uniqueness of the whole array.

Does Laravel validation rule default to sometimes?

If you create a validation rule in Laravel, but leave out |required and just use, say the email rule. What does it default to?
For example
$request->validate([
'email' => 'email'
]);
Are these validation rules equal?
$request->validate([
'email' => 'sometimes|email'
]);
// vs
$request->validate([
'email' => 'email'
]);
Apologies if this has been answered before. I tried my very best to search for similar questions, but I may have used the wrong words (not sure how to phrase this for a Google/Stack Overflow search).
$request->validate([
'email' => 'email'
]);
This will always validate the email key, even if empty, to be a valid email format.
$request->validate([
'email' => 'sometimes|email'
]);
This will only validate the email key if the key is present in $request->all().
So the difference is that with sometimes you'll only validate it if the $request object contains it, whilst otherwise it would always validate against the key.
If I could simplify it, I would say sometimes means, only apply the rest of the validation rules if the field shows up in the request. Imagine sometimes is like an if statement that checks if the field is present in the request/input before applying any of the rules.
It can be a tedious thing to wrap ones head around, but here is some examples:
input: []
rules: ['email' => 'sometimes|email']
result: pass, the request is empty so sometimes won't apply any of the rules
input: ['email' => '1']
rules: ['email' => 'sometimes|email']
result: fail, the field is present though invalid email so the email rule fails!
input: []
rules: ['email' => 'email']
result: fail, the request is empty so email is invalid!
I personally have never used the sometimes rule once. According to the docs:
https://laravel.com/docs/7.x/validation#conditionally-adding-rules
you may wish to run validation checks against a field only if that field is present in the input array. To quickly accomplish this, add the sometimes rule to your rule list
If I understand correctly, this largely depends on your frontend implementation. If you are using regular html <form> elements where you have an input with name="email", it will send a key named email as soon as you submit the form.
So in order to NOT send such key, you have to remove it from the form, or manually make a HTTP request (so disregarding any HTML form) such that you can decide your own input fields.

Laravel: Validate input only if available in DOM

I created a form with the following fields:
Name
Email
Country
City
Address
If the user selects a country that has states (ex. United States) then the form transforms to:
Name
Email
Country
State
City
Address
To validate this I created a separate form request like so:
public function rules()
{
return [
'name' => 'required|max:255',
'email' => 'required|email,
'country_id' => 'required|integer',
'state_id' => 'nullable|integer',
'city_id' => 'required|integer',
'address' => 'required',
];
}
The problem is that if I leave it like that, then if I don't select a state it will pass validation.
If i make it:
'state_id' => 'sometimes|nullable|integer',
Then again it passes validation.
If I make it:
'state_id' => 'required|nullable|integer',
It will not pass validation, but then again it will throw a validation error if there is no state field in the form.
I read a lot of articles about this but nothing seems to solve it for me.
PS1: I want to solve this in the form request, not in the controller. I assume that an
if($request->has('states')){...}
can help, but then again, i would like to keep everything tidy in the form request.
PS2: I am using VueJS and Axios to add/remove states from the form. The whole form is actually a Vue component.
Any clues?
Thank you in advance!
You can conditionally add rules via the sometimes method on Validator.
$v->sometimes('state_id', 'required|integer', function ($input) {
return in_array($input->countries, [1,2,3,4...]
});
You could use the required_with line of parameters, but because the validation is based on the value of the input instead of just the presence, the custom validation rule is probably your best bet.
Per https://laravel.com/docs/5.7/validation#conditionally-adding-rules

How to allow empty value for Laravel numeric validation

How to set not require numeric validation for Laravel5.2? I just used this Code but when i don't send value or select box haven't selected item I have error the val field most be numeric... I need if request hasn't bed input leave bed alone. leave bed validate ...
$this->validate($request, [
'provinces_id' => 'required|numeric',
'type' => 'required',
'bed' => 'numeric',
]);
If I understood you correctly, you're looking for sometimes rule:
'bed' => 'sometimes|numeric',
In some situations, you may wish to run validation checks against a field only if that field is present in the input array. To quickly accomplish this, add the sometimes rule to your rule list
In Laravel 6 or 5.8, you should use nullable. But sometimes keyword doesn't work on that versions.
Use sometimes instead of required in validation rules. It checks if only there is a value. Otherwise it treats parameter as optional.
You may need nullable – sometimes and
present didn't work for me when combined with integer|min:0 on a standard text input type - the integer error was always triggered.
A Note on Optional Fields
By default, Laravel includes the TrimStrings and ConvertEmptyStringsToNull middleware in your application's global middleware stack. These middleware are listed in the stack by the App\Http\Kernel class. Because of this, you will often need to mark your "optional" request fields as nullable if you do not want the validator to consider null values as invalid.
Tested with Laravel 6.0-dev
Full list of available rules
In laravel 5.5 or versions after it, we begin to use nullable instead of sometimes.
according to laravel documentation 8 you must to set nullable rule
for example:
$validated = $request->validate([
'firstName' => ['required','max:255'],
'lastName' => ['required','max:255'],
'branches' => ['required'],
'services' => ['required' , 'json'],
'contract' => ['required' , 'max:255'],
'FixSalary' => ['nullable','numeric' , 'max:90000000'],
'Percent' => ['nullable','numeric' , 'max:100'],
]);
in your case :
$this->validate($request, [
'provinces_id' => 'required|numeric',
'type' => 'required',
'bed' => 'nullable|numeric',
]);

Resources