Laravel, use only custom rule class for validation? - laravel

I have some dynamic fields and can't use usual field validation. My question is, how can I use only my custom rule class without defining if it's required or not?
This doesn't work:
$this->validate($request, [
'social_links.fb' => new SocialFieldValidation($fieldDataFb),
'social_links.linkedin' => new SocialFieldValidation($fieldDataLinkedIn),
'social_links.twitter' => new SocialFieldValidation($fieldDataTwitter)
]);
To get this work I need to add something like:
$this->validate($request, [
'social_links.fb' => ['sometimes', new SocialFieldValidation($fieldDataFb)],
'social_links.linkedin' => ['sometimes', new SocialFieldValidation($fieldDataLinkedIn)],
'social_links.twitter' => ['sometimes', new SocialFieldValidation($fieldDataTwitter)]
]);
To use always validation class I need to set required or sometimes but I would need only to use validation class without other definitions, is that possible?

As mentionned in your comment, if putting your custom rule validation in array works but you want this working in case of null value, then you need to do use the nullable validation:
$this->validate($request, [
'social_links.fb' => ['nullable', new SocialFieldValidation($fieldDataFb)],
'social_links.linkedin' => ['nullable', new SocialFieldValidation($fieldDataLinkedIn)],
'social_links.twitter' => ['nullable', new SocialFieldValidation($fieldDataTwitter)]
]);
If you need the documentation:
https://laravel.com/docs/8.x/validation#rule-nullable
https://laravel.com/docs/8.x/validation#a-note-on-optional-fields

Related

Conditional Validation with dependency to other fields in import

I am trying to validate import data using Laravel Excel. I got through to using required_if when a field is required when another field has a certain value. But what if validation rule I want to implement in this scenario is regex instead of required.
public function collection(Collection $rows){
$validator = Validator::make($rows->toArray(), [
'*.question_categories' => 'required',
'*.question' => 'required',
'*.question_type' => 'required',
'*.mark' => 'required',
'*.correct_answer' => ['required_if:*.question_type,Single Answer',
]
])->validate();
// Code below
}
Here I want to check value of "question_type" to determine the regular expression for "correct_answer".
I am using Laravel 6x.

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.

Skip Laravel's FormRequest Validation

I've recently added HaveIBeenPwned to my form request class to check for cracked passwords. Given that this makes an external API call, is there a way for me to skip either this validation rule or the FormRequest class altogether during testing?
Here's the request I make in my test.
$params = [
'first_name' => $this->faker->firstName(),
'last_name' => $this->faker->lastName(),
'email' => $email,
'password' => '$password',
'password_confirmation' => '$password',
'terms' => true,
'invitation' => $invitation->token
];
$response = $this->json('POST', '/register-invited', $params);
The functionality I'm testing resides on a controller. In my test I POST an array of data that passes through a FormRequest with the following rules.
public function rules()
{
return [
'first_name' => 'required|string|max:70',
'last_name' => 'required|string|max:70',
'email' =>
'required|email|unique:users,email|max:255|exists:invitations,email',
'password' => 'required|string|min:8|pwned|confirmed',
'is_trial_user' => 'nullable|boolean',
'terms' => 'required|boolean|accepted',
];
}
I want to override the 'pwned' rule on the password so I can just get to the controller without having to worry about passing validation.
With the information provided I'd say you are executing an integration test which does an actual web request. In such a context I'd say it's fine for your test suite to connect to a 3rd party since that's part of 'integrating'.
In case you still prefer to mock the validation rule you could swap out the Validator using either the swap
$mock = Mockery::mock(Validator::class);
$mock->shouldReceive('some-method')->andReturn('some-result');
Validator::swap($mock);
Or by replacing its instance in the service container
$mock = Mockery::mock(Validator::class);
$mock->shouldReceive('some-method')->andReturn('some-result');
App:bind($mock);
Alternatively you could mock the Cache::remember() call which is an interal part of the Pwned validation rule itself. Which would result into something like
Cache::shouldReceive('remember')
->once()
->andReturn(new \Illuminate\Support\Collection([]));

Laravel Validation custom messages using nested attributes

I would like to ask for some advices about Laravel Validation...
Let's say I've got an input named invoiceAddress[name] and in a controller I've got a rule
$rule = ['invoiceAddress.name' => 'required',];
or just a
$validator = \Validator::make($request->all(), [
'invoiceAddress.name' => 'required',
]);
now, inside custom validation language file validation.php, am I able to nest attributes somehow? like:
'required' => ':attribute is mandatory',
'attributes' => [
'invoiceAddress' => [
'name' => 'blahblah'
],
],
If I try to nest the attribute the way above, i get
ErrorException
mb_strtoupper() expects parameter 1 to be string, array given
because I am using a field (as above)
['name' => 'blahblah']
I am trying to get custom messages using the file and the :attribute directive (as mentioned in the code above).
I am basically trying to do this How to set custom attribute labels for nested inputs in Laravel but i get the mentioned error...
Thank you in advance...
A Note On Nested Attributes
If your HTTP request contains "nested" parameters, you may specify them in your validation rules using "dot" syntax:
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
Reference: https://laravel.com/docs/5.3/validation#quick-writing-the-validation-logic (A Note On Nested Attributes Section)

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