Seeding validation array - laravel

I am creating a lot of questions via a seeder. The format I am doing is this
DB::table('questions')->insert([
'name' => 'questionOne',
'rule' => 'nullable|max:50|regex:/(?=.)^\£?(([1-9][0-9]{0,2}(,[0-9]{3})*)|[0-9]+)?(\.[0-9]{1,2})?$/'
]);
Whereby I provide a field name and a validation rule. I was noticing that when applying the above rule, the validation would fail, stating
preg_match(): No ending delimiter '/' found
I done some research and found out that
When using the regex pattern, it may be necessary to specify rules in
an array instead of using pipe delimiters, especially if the regular
expression contains a pipe character.
As recommended, I changed my seeder to this
DB::table('questions')->insert([
'name' => 'questionOne',
'rule' => ['nullable|max:50|regex:/(?=.)^\£?(([1-9][0-9]{0,2}(,[0-9]{3})*)|[0-9]+)?(\.[0-9]{1,2})?$/']
]);
However, when I try to seed with the above, I get an Array to String conversion error. The way I am applying the validation is like so
$rules = [];
$questions = Question::all();
foreach ($questions as $question) {
if (!empty($question->rule)) {
$rules["questions.{$question->id}"] = $question->rule;
}
}
$this->validate($request, $rules);
Is there any way I can get the above regex to work? One point to note is that only a few questions have this regex, if that matters?
Thanks

When using the regex pattern, it may be necessary to specify rules in an array instead of using pipe delimiters, especially if the regular expression contains a pipe character.
This is referring to the $rules variable passed into $this->validate; your regex pattern contains a pipe character | which interferes with Laravel's ability to split up the rule string into an array internally.
Storing the rules in string format with pipe separators also makes it difficult for you to split them into an array upon retrieval from the DB. I'd recommend storing them as a similarly delineated structure like JSON, which would make your seeder:
DB::table('questions')->insert([
'name' => 'questionOne',
'rule' => json_encode([
'nullable',
'max:50',
'regex:/(?=.)^\£?(([1-9][0-9]{0,2}(,[0-9]{3})*)|[0-9]+)?(\.[0-9]{1,2})?$/'
])
]);
and validation:
$rules = [];
$questions = Question::all();
foreach ($questions as $question) {
if (!empty($question->rule)) {
$rules["questions.{$question->id}"] = json_decode($question->rule, true);
}
}
$this->validate($request, $rules);
You would also want to change the rule column type to JSON in your questions table migration.
To further simplify the code, you could make use of Laravel's attribute casting feature which claims to handle the json_encode/json_decode for you:
protected $casts = [
'rule' => 'array',
];

Related

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.

Laravel Custom Validation Rules should be lowercase?

I have model, and it has several field names, and 'lastName' is among them.
In my FormRequest file, I have rules and messages for this field:
$rules = ['lastName.*' => 'lastName_fail: index'];
$messages = ['lastName.*lastName_fail' => This lastName has different value in DB!'];
When I am submitting a form, filling the 'lastName' field with intentionally 'wrong' value, it doesn't pass validation, and returns error message:
validation.last_name_fail
(which is not what's in $messages).
But when I change $rules and $messages to:
$rules = ['lastName.*' => 'lastname_fail: index'];
$messages = ['lastName.*lastname_fail' => This lastName has different value in DB!'];
(so the actual "rule" is now lowercase "lastname_fail"), it outputs what i want:
This lastName has different value in DB!
from this I may conclude that Laravel's validation rule name may be
only lowercase.
Is it declared anywhere in documentation?
If so, maybe it helps someone.
It is not mentioned in the documentation. However, there is a naming pattern for both validation rule method name and rule name.
Rule Method Name:
It must have validate prefix and the rest of it must be in Camel Case.
Rule Name:
It will be in lowercase without the validate prefix and each word will be separated by an underscore.
So if you want to add alpha_dash_spaces validation rule then the corresponding method will be named validateAlphaDashSpaces().
Simply parse $request[data] before Validator
use Illuminate\Support\Str;
$request['name_it'] = Str::lower($request['name_it']);
$request['name_en'] = Str::lower($request['name_en']);
$validator = Validator::make($request->all(), [
'name_it' => ['required', 'string', 'max:255', 'unique:categories'],
'name_en' => ['required', 'string', 'max:255', 'unique:categories'],
]);
if ($validator->fails()) {
return redirect()
->back()->withErrors($validator)
->withInput();
}

Laravel 5.2 Validate File Array

I have a form with three fields: title, body and photo[]. I'm trying to validate it so that at least one item is filled in, but I can't seem to get it to work. If I upload a file I still receive an error for title and body.
public function rules()
{
return [
'title' => 'required_without_all:body,photo.*',
'body' => 'required_without_all:title,photo.*',
'photo.*' => 'required_without_all:title,body',
'photo.*' => 'mimes:jpeg,gif,png',
];
}
Update: Jonathan pointed out that I had my rules wrong. I've fixed them and am now using this. It's still not working; when I try to upload a photo I get the error message that the other fields are required.
public function rules()
{
return [
'title' => 'required_without:body,photo.*',
'body' => 'required_without:title,photo.*',
'photo.*' => 'required_without:title,body|mimes:jpeg,gif,png',
];
}
If you're looking to ensure the photo field is an array then you need 'photo' => 'array' and then you can use 'photo.*' => '' for the other validations of the array's children.
The rules are separated by a pipe character | so if you were going to combine the two in your example it would be 'photo.*' => 'required_without_all:title,body|mimes:jpeg,gif,png',. I don't see you using the pipe to separate rules so I can't be sure you are aware of it.
This may have been where you were going wrong in the first place (two keys in the associative array that are identical) and some kind of precedence taking affect negating one of the rules.
You could try something like this (for the record I think you were on the right track to begin with using required_without_all as this stipulates the need to be required if all of the given fields are missing):
public function rules()
{
return [
'title' => 'required_without_all:body,photo',
'body' => 'required_without_all:title,photo',
'photo' => 'array',
'photo.*' => 'required_without_all:title,body|mimes:jpeg,gif,png',
];
}
Reference

Using Laravel Exists Validation with a condition specified with a function

I have a model where I am attempting to use a exists validation rule like
public static $rules = ['item' => 'exists:items,item,company_id,\Auth::user()->active_company',
'location' => 'exists:locations,location,company_id,\Auth::user()->active_company',
];
This validation rule is always failing.
$validation = Validator::make($this->attributes, static::$rules);
If I modify the rule for the specific user->active_company, it works.
public static $rules = ['item' => 'exists:items,item,company_id,17',
'location' => 'exists:locations,location,company_id,17',
];
It seems as if the function \Auth::user()->active_company isn't being evaluated when the rules are being checked. All of the examples I've seen use a constant rather than a function.
Will this work with laravel validation or do I need to take a different strategy?
The encapsulation of the rules in single quotes means that the contents are taken literally. This means that the validation rule is looking for a company ID which is literally '\Auth::user()->active_company' as opposed to the output of that, perhaps 1 for the sake of example.
See the single quoted strings manual page
There are few ways you could do it:
Break out of the quotes and concatenate the two strings with a period (.)
public static $rules = [
'item' => 'exists:items,item,company_id,'.\Auth::user()->active_company,
'location' => 'exists:locations,location,company_id,'.\Auth::user()->active_company,
];
Write active_company to a variable and break out of the quotes and concatenate the two strings with a period (.)
$activeCo = \Auth::user()->active_company;
public static $rules = [
'item' => 'exists:items,item,company_id,'.$activeCo,
'location' => 'exists:locations,location,company_id,'.$activeCo,
];
Write active_company to a variable and use double quotes as variables are expanded/interpreted inside double ones. "$activeCo" or "{$activeCo}" will work
$activeCo = \Auth::user()->active_company;
public static $rules = [
'item' => "exists:items,item,company_id,{$activeCo}",
'location' => "exists:locations,location,company_id,{$activeCo}",
];

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