Laravel validation - Different Attributes Specifications - laravel

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.

Related

How to validate laravel input only when data is present?

So I have a Laravel form where I'm collecting data, I use same form for creating and updating the table. Problem is that I only want the input fields to be validated when they contain data, this is my validation logic.
$validated = $request->validate([
'site_name' => 'sometimes|string',
'site_email' => 'sometimes|email',
'site_keywords' => 'sometimes|string',
'site_description' => 'sometimes|string',
'site_acronym' => 'sometimes|string|max:7',
'site_favicon' => 'sometimes|mimes:jpg,png,jpeg,svg',
'site_logo' => 'sometimes||mimes:jpg,png,jpeg,svg',
'site_currency' => 'sometimes|string',
'site_currency_symbol' => 'sometimes|string',
]);
But when the form is submitted, laravel returns an error for empty input fields, e.g it returns an error like so "The site name must be a string." for the first validation rule.
What am I doing wrong please?
EDIT
So I took the advice from #roj-vroemen and modified my code by using the nullable validation rule and it works just fine now.
Here's the new code block
$validated = $request->validate([
'site_name' => 'string|nullable|sometimes',
'site_email' => 'email|nullable|sometimes',
'site_keywords' => 'string|nullable|sometimes',
'site_description' => 'string|nullable|sometimes',
'site_acronym' => 'string|nullable|sometimes|max:7',
'site_favicon' => 'mimes:jpg,png,jpeg,svg|nullable|sometimes',
'site_logo' => 'mimes:jpg,png,jpeg,svg|nullable|sometimes',
'site_currency' => 'string|nullable|sometimes',
'site_currency_symbol' => 'string|nullable|sometimes',
]);
You'll want to use nullable in this case. sometimes basically means it only runs the validation for that field when it's present in the data.
In short:
Use nullable when you want to allow null values.
https://laravel.com/docs/8.x/validation#rule-nullable
Use sometimes if your only want to validate the field when it's present in the given input array.
https://laravel.com/docs/8.x/validation#validating-when-present
Note: you might want to make sure to filter out the empty values as the fields containing null will still be there:
$validated = array_filter($validated);

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.

Validate a field using another field

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.

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',
]);

Validating Matching Strings

When I use the Validation feature in Laravel, how can I add a pre-defined strings that are allowed in an Input?
For example, let's say I want the Input to contain only one of the following: foo,bar,baz, how can I do that?
$validator = Validator::make($credentials, [
'profile' => 'required|max:255', // Here I want Predefined allowed values for it
]);
Best to use the 'in' validation rule like this:
$validator = Validator::make($credentials, [
'profile' => ["required" , "max:255", "in:foo,bar,baz"]
]);
It is recommended in Laravel docs to put the validation rules in an array when they get bigger and I thought 3 rules were sufficient. I think it makes it for a more readable content but you do not have to. I added the regex portion below and I have it works. I am not that great with regexing stuff. Let me know.
$validator = Validator::make($credentials, [
'profile' => ["required" , "max:255", "regex:(foo|bar|baz)"]
]);
Works for me in Laravel 9:
use Illuminate\Validation\Rule;
 
Validator::make($data, [
'toppings' => [
'required',
Rule::notIn(['sprinkles', 'cherries']),
],
]);
Docs: https://laravel.com/docs/9.x/validation#rule-not-in
For the opposite you could use Rule::in(['foo', 'bar', 'baz'])

Resources