These arrays I put into Laravel Validator as arguments:
['item.*' => 'string'] // rules
['item.*.string' => 'Item number (index) is not string'] // messages
I want to have index number in validation message. Code above is just for demonstration and does not work. How to do this?
Try this or use this one
'name' : [ { 'value' : 'raju' } , { 'value' : 'rani'} ]
and validate it by
'name.*' or 'name.*.value' => 'required|string|min:5'
The message will be
'name.*.required' => 'The :attribute is required'
'name.*.value.required' => 'The :attribute is required'
I think it will help to you..
Try this one,
public function messages()
{
$messages = [];
foreach ($this->request->get('name') as $key => $value){
$messages['name.'. $key .'.required'] = 'The item '. $key .' is not string';
}
return $messages;
}
Related
If there a way to check whether or not the validator failed specifically because of the unique rule?
$rules = array(
'email_address' => 'required|email|unique:users,email',
'postal_code' => 'required|alpha_num',
);
$messages = array(
'required' => 'The :attribute field is required',
'email' => 'The :attribute field is required',
'alpha_num' => 'The :attribute field must only be letters and numbers (no spaces)'
);
$validator = Validator::make(Input::all(), $rules, $messages);
if ($validator->fails()) {
In laymans terms, I basically want to know: "did the validation fail because the email_address was not unique?"
Check for a specific rule within the returned array of failed rules
if ($validator->fails()) {
$failedRules = $validator->failed();
if(isset($failedRules['email_address']['Unique'])) {
...
This will display an error and tell you what failed:
Controller
if($validation->fails()){
return Redirect::back()->withErrors($validation)->withInput();
}
foreach($errors->all() as $error) {
echo $error;
}
And in your blade template add this:
#foreach($errors->all() as $error)
<div>
{{$error}}
</div>
#endforeach
And that will return a message with whatever the error is. Email doesn't match. Field is required. Blah blah
You can also remove that email array from the $message. The validator will handle all that for you. You only want to use that if you want custom messages.
You can also try to var_dump this statement:
var_dump($validation->errors()); die;
I have two fields
data[0][student]
data[0][teacher]
data[1][student]
data[1][teacher]
I tried this rule
$rules['data.*.student'] = 'required';
which gives this error
{
"error": {
"status_code": 412,
"validation": {
"data.student.*": [
"The data.*.student field is required."
]
},
"message": "Validation Failed"
}
}
how can I achieve this and make fields required if user missed this input field
data[student][0]?
For that you need to set a custom messages for rules inside Formrequest file.
You need to add rules and messages function Like this demostrated example:
Rules
public function rules()
{
return [
'item.*.name' => 'required|string|max:255',
'item.*.description' => 'sometimes|nullable|string|min:60',
'sku' => 'required|array',
'sku.*' => 'sometimes|required|string|regex:/^[a-zA-Z0-9]+$/',
'sku' => 'required|array',
'price.*' => 'sometimes|required|numeric'
];
}
Message
public function messages()
{
return [
'item.*.name.required' => 'You must have an item name.',
'item.*.name.max' => 'The item name must not surpass 255 characters.',
'item.*.description.min' => 'The description must have a minimum of 60 characters.',
'sku.*.regex' => 'The SKU must only have alphanumeric characters.',
'price.*.numeric' => 'You have invalid characters in the price field.'
];
}
I'm trying to validate a field array, and I'd like to point out which field is wrong in the validation errors.
I have a form to upload multiple images. For each image, there must be a caption and the alt attribute for HTML. If I try to upload 3 images and miss the fields for two of them, I'll get an error message like the following:
The field 'image file' is required.
The field 'image caption' is required.
The field 'image alt' is required.
The field 'image caption' is required.
The field 'image alt' is required.
The field 'image file' is required.
The problem is that the :attribute is repeated and if the user wants to update multiple images he/she will have to check all of them to find which field is missing!
What I want is this:
The field 'image file (item 1)' is required.
The field 'image caption (item 1)' is required.
The field 'image alt (item 1)' is required.
The field 'image caption (item 3)' is required.
The field 'image alt (item 3)' is required.
The field 'image file (item 1)' is required.
So the user can know where to fix the problem.
First, I tried this:
$attributes = [
'img.*.file' => 'Image file (item :* )',
'img.*.alt' => 'Image alt (item :* )',
'img.*.caption' => 'Image caption (item :* )',
];
//
$this->validate($request, $rules, [], $attributes);
I supposed that the :* would be replaced by the index of the field (1, 2, 3, 4, etc) as the same way :attribute is replaced by the attribute. However, the :* is not replaced by the index of the fields; instead, it is displayed as plain text.
It worths to note that I designed the code in such way that the HTML name attribute is indexed sequentially for all fields (img[1][alt], [img][2][alt], etc, img[1][caption], [img][2][caption], etc), so each field has the right index. Having that in mind, I suppose there is a way to get the index and use to create custom attributes in the error messages.
I searched for this problem and found the same question here Validation on fields using index position, but it uses angular, not laravel.
How can I get the index and put it in the attribute?If that is not possible, is there any other way to accomplish the desirable result without having to set up the error messages?
I would like to change the attributes and keep the default error messages that laravel provides
Try this example
$input = Request::all();
$rules = array(
'name' => 'required',
'location' => 'required',
'capacity' => 'required',
'description' => 'required',
'image' => 'required|array'
);
$validator = Validator::make($input, $rules);
if ($validator->fails()) {
$messages = $validator->messages();
return Redirect::to('venue-add')
->withErrors($messages);
}
$imageRules = array(
'image' => 'image|max:2000'
);
foreach($input['image'] as $image)
{
$image = array('image' => $image);
$imageValidator = Validator::make($image, $imageRules);
if ($imageValidator->fails()) {
$messages = $imageValidator->messages();
return Redirect::to('venue-add')
->withErrors($messages);
}
}
Thanks to the user sss S, I could implement his/her ideas to solve the problem.
Here is the code for the store method. It replaces (item) with (item $i) in the error message, where $i is the index of the field. Therefore the user can know exactly where is the error.
public function store(Request $request)
{
$rules = $this->rules();
$attributes = $this->attributes();
$validator = Validator::make($request->all(), $rules, [], $attributes);
$errors = [];
if ($validator->fails()) {
$errors = $validator->errors()->all();
}
$imgRules = [
'file' => 'required|image|mimes:jpeg,jpg,webp,png|max:1999',
'alt' => 'required|string|max:100|min:5',
'caption' => 'required|string|max:100|min:5',
];
$imgAttributes = [
'alt' => 'HTML alt attribute (item)',
'caption' => 'Caption(item)',
'file' => 'image file (item)',
];
foreach($request->img as $i => $img) {
$imgValidator = Validator::make($img, $imgRules, [], $imgAttributes);
$imgErrors = [];
if($imgValidator->fails()) {
$imgErrors = $imgValidator->errors()->all();
}
foreach($imgErrors as $k => $v) {
$imgErrors[$k] = str_replace('(item)', "(item $i)", $v);
}
$errors = array_merge($errors, $imgErrors);
}
if(count($errors) > 0) {
return response()->json(['success' => false, 'errors' => $errors]);
}
// here is the code store the new resource
// ...
// then return success message
}
I have custom request data:
{
"data": {
"checkThisKeyForExists": [
{
"value": "Array key Validation"
}
]
}
}
And this validation rules:
$rules = [
'data' => ['required','array'],
'data.*' => ['exists:table,id']
];
How I can validate array key using Laravel?
maybe it will helpful for you
$rules = ([
'name' => 'required|string', //your field
'children.*.name' => 'required|string', //your 1st nested field
'children.*.children.*.name => 'required|string' //your 2nd nested field
]);
The right way
This isn't possible in Laravel out of the box, but you can add a new validation rule to validate array keys:
php artisan make:rule KeysIn
The rule should look roughly like the following:
class KeysIn implements Rule
{
public function __construct(protected array $values)
{
}
public function message(): string
{
return ':attribute contains invalid fields';
}
public function passes($attribute, $value): bool
{
// Swap keys with their values in our field list, so we
// get ['foo' => 0, 'bar' => 1] instead of ['foo', 'bar']
$allowedKeys = array_flip($this->values);
// Compare the value's array *keys* with the flipped fields
$unknownKeys = array_diff_key($value, $allowedKeys);
// The validation only passes if there are no unknown keys
return count($unknownKeys) === 0;
}
}
You can use this rule like so:
$rules = [
'data' => ['required','array', new KeysIn(['foo', 'bar'])],
'data.*' => ['exists:table,id']
];
The quick way
If you only need to do this once, you can do it the quick-and-dirty way, too:
$rules = [
'data' => [
'required',
'array',
fn(attribute, $value, $fail) => count(array_diff_key($value, $array_flip([
'foo',
'bar'
]))) > 0 ? $fail("{$attribute} contains invalid fields") : null
],
'data.*' => ['exists:table,id']
];
I think this is what you are looking:
$rules = [
'data.checkThisKeyForExists.value' => ['exists:table,id']
];
I am sending multiple arrays via AJAX to my controller and I'm having trouble with validation.
I have 2 text inputs. Now, the issue is that at times both these inputs are present, but at other times only one might be present.
<input type="text" name="typeDetails[games]" class="form-control input-global"/>
<input type="text" name="typeDetails[art]" class="form-control input-global"/>
My JS is like this.
var data = { 'typeDetails[games]' : [], 'typeDetails[art]' : [] };
$("input[name='typeDetails[games]']").each(function() {
data['typeDetails[games]'].push($(this).val());
});
$("input[name='typeDetails[art]']").each(function() {
data['typeDetails[art]'].push($(this).val());
});
In my controller, I want to (1) make sure that there's a validation of required and (2) if the "games" array is present, perform a particular action and if the "art" array is present, perform a different action.
$typeDetails = Input::get('typeDetails');
if ($request->has('typeDetails.games'))
{
return 'games';
}
if ($request->has('typeDetails.art'))
{
return 'art';
}
What happens here is that in my console it properly returns 'games', but even if the "art" array has values and is sent with the request, it doesn't return 'art'. I must be missing a fundamental understanding with php here.
Thanks!
ANSWER
Here's how I got it to work.
$typeDetails = Input::get('typeDetails');
$this->validate($request, [
'typeDetails.*.*' => 'required|max:50'
],[
'required' => 'You must type in some keywords to continue.',
'max' => 'Your input must be less than 50 characters.'
]);
if ($request->has('typeDetails.games'))
{
$gameInfo = Input::get('typeDetails.games');
foreach ($gameInfo as $key => $value)
{
DB::table('user_type')->insert([
'user_id' => Auth::user()->id,
'type_id' => '1',
'user_type_details' => $value,
'created_at' => Carbon::now()
]);
}
}
if ($request->has('typeDetails.art'))
{
$artInfo = Input::get('typeDetails.art');
foreach ($artInfo as $key => $value)
{
DB::table('user_type')->insert([
'user_id' => Auth::user()->id,
'type_id' => '2',
'user_type_details' => $value,
'created_at' => Carbon::now()
]);
}
}