I have data coming in through an AJAX post like this:
data:
0: {type: 'percent', amount: 10,…}
1: {type: 'percent', amount: 200,…}
As you can see, the last item in the array is a problem. If the type is percent, and the amount is more than 100, the validation should fail.
I'm using the following function to validate the request:
public function validateRequest( $request ) {
$rules = [
'data.*.type' => 'required|alpha',
'data.*.amount' => 'required|min:1|int',
]
$messages = [...];
Validator::make($request->all(), $rules, $messages)->validate();
}
I've been looking on the Validation page, and I think I need to conditionally add the max:100 rule to that specific array index but only if that specific array index' type is percent. I'm just not sure how to get that done.
Thank you in advance!
I usually do such things as simple like this:
$rules = [
'data.*.type' => 'required|alpha',
'data.*.amount' => ['required', 'min:1', 'int'],
];
foreach ($request->input('data') as $key => $value)
{
if (array_get($value, 'type') == 'percent') {
$rules["data.{$key}.amount"][] = 'max:100';
}
}
Notice the array syntax for rules instead of pipe to make it easier to add additional rules.
Related
I'am using Laravel on server side. Let's imagine our controller receive two fields url [string] and data [array with index head]. We can validate data and customize errors messages with
$this->validate($request, [
'url' => 'required',
'data.head' => 'required',
], [
'url.required' => 'The :attribute field is required',
'data.head.required' => 'The :attribute field is required',
]);
If validation fails, Laravel send back response with json data
{
"url": ["The url field is required"],
"data.head": ["The data.head field is required"]
}
How we can convert response data to send json, as below?
{
"url": ["The url field is required"],
"data": {
"head": ["The data.head field is required"]
}
}
In javascript
Loop on errors
error: function (errors) {
$.each(errors['responseJSON']['errors'], function (index, error) {
var object = {};
element = dotToArray(index);
object[index] = error[0];
validator.showErrors(object);
});
}
convert in dot notation into array notation. i.e abc.1.xyz into abc[1][xyz]
function dotToArray(str) {
var output = '';
var chucks = str.split('.');
if(chucks.length > 1){
for(i = 0; i < chucks.length; i++){
if(i == 0){
output = chucks[i];
}else{
output += '['+chucks[i]+']';
}
}
}else{
output = chucks[0];
}
return output
}
Laravel has an helper called array_set that transform a dot based notation to array.
I don't know how you send the errors via ajax, but you should be able to do something like that:
$errors = [];
foreach ($validator->errors()->all() as $key => $value) {
array_set($errors, $key, $value);
}
Edit:
But apparently, you should be able to not use the dot notation by Specifying Custom Messages In Language Files like this example:
'custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
],
I don't know if it's still a valid question but to create a custom validation using dot notation in laravel, you can specify the array like this in your validation.php
'custom' => [
'parent' => [
'children' => [
'required' => 'custom message here'
]
]
This will be the parent.children property.
see ya.
key = key.replace(/\./g, '[') + Array(key.split('.').length).join(']');
I am trying to post the following data to an endpoint built up on Laravel.
{
"category": "2",
"title": "my text goes here",
"difficulty": 1,
"correct": {
"id": "NULL",
"text": "Correct"
},
"wrong": [
{
"id": "NULL",
"text": ""
},
{
"id": "NULL",
"text": ""
},
{
"id": "NULL",
"text": ""
}
]
}
and I have the following validation rules.
return [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|array|between:1,3'
];
What I am trying to accomplish is the wrong should be and array and it should contain at least one element and should not exceed 3. Now these rules are satisfying, but there is one more case I need to take care and that is the validation of the text in wrong . With the current rules, if I post the above data, it will accept as there is no rule in place for the text in the wrong section. Which rule I need to add to validate that the wrong section at least contains one entry with a not empty text.
tl;dr
If you have very specific needs for a validator rule, you can always create your own.
Create a Custom Validator
The scheme will be: properties_filled:propertyName:minimumOccurence. This rule will check if the field under validation:
Is an array.
Its elements have at least minimumOccurence amounts of non empty (!== '') values among element properties called propertyName.
In your app/Providers/AppServiceProvider.php file's boot method, you can add the custom rule implementation:
public function boot()
{
Validator::extend('properties_filled', function ($attribute, $value, $parameters, $validator) {
$validatedProperty = $parameters[0];
$minimumOccurrence = $parameters[1];
if (is_array($value)) {
$validElementCount = 0;
$valueCount = count($value);
for ($i = 0; $i < $valueCount; ++$i) {
if ($value[$i][$validatedProperty] !== '') {
++$validElementCount;
}
}
} else {
return false;
}
return $validElementCount >= $minimumOccurrence;
});
}
Then you can use it in your validation like this:
return [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|between:1,3|properties_filled:text,1'
];
Testing
Note: I assumed that you parse your JSON data with json_decode's $assoc parameter set to true. If you use an object then change the $value[$i][$validatedProperty] !== '' in the condition to: $value[$i]->{$validatedProperty} !== ''.
Here is my example test:
$data = json_decode('{"category":"2","title":"mytextgoeshere","difficulty":1,"correct":{"id":"NULL","text":"Correct"},"wrong":[{"id":"NULL","text":""},{"id":"NULL","text":""},{"id":"NULL","text":""}]}', true);
$validator = Validator::make($data, [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|between:1,3|properties_filled:text,1'
]);
$validator->fails();
Take advantage of the validation rule in
EDIT: I assume that wrong will have a specific value, therefore pass that value in this way
return [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|array|between:1,3',
'wrong.text' => 'sometimes|min:1|in:somevalue,someothervalue',
];
The sometimes validation makes sure that field is checked only if exists. To check that there will be at least
I'm not sure, but does min suffice to your request? Otherwise you have to write a custom validation rule as someone else suggested
I got the same issue while trying to validate an array on the API side. I made a solution. try this
$validator = Validator::make($request->all(), [
'target_user_ids' => 'required',
'target_user_ids.*' => 'present|exists:users,uuid|distinct',
]);
if ($validator->fails()) {
return response()->json([
'status' => false,
'error' => $validator->errors()->first(),
], 400);
}
If you want to validate input fields in array, you can define your rules like this:
return [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|array|between:1,3',
'wrong.*.text' => 'required|string|min:1',
];
I am having a form where i am having title, body, answers[][answer] and options[][option].
I want atleast one answer must be selected for the given question, for example:
i have ABC question and having 5 options for that question,now atleast one answer must be checked or all for given question.
Efforts
protected $rules = [
'title' => 'required|unique:contents|max:255',
'body' => 'required|min:10',
'type' => 'required',
'belongsto' => 'sometimes|required',
'options.*.option' => 'required|max:100',
'answers.*.answer' => 'required',
];
But this is not working. i want atleast one answer must be selected.
Please help me.
The problem is that on $_POST an array filled with empty strings will be passed if no answer is selected.
$answers[0][0] = ''
$answers[0][1] = ''
$answers[0][2] = ''
Hence the following will not work since array count will be greater than zero due to the empty strings:
$validator = Validator::make($request->all(), [
'answers.*' => 'required'
]);
The easiest way to solve this is to create a custom Validator rule by using Laravel's Validator::extend function.
Validator::extendImplicit('arrayRequireMin', function($attribute, $values, $parameters)
{
$countFilled = count(array_filter($values));
return ($countFilled >= $parameters[0]);
});
And then call it in your Validation request:
$validator = Validator::make($request->all(), [
'answers.*' => 'arrayRequireMin:1'
]);
The magic happens in array_filter() which removes all empty attributes from the array. Now you can set any minimum number of answers required.
Validator::extendImplicit() vs Validator::extend()
For a rule to run even when an attribute is empty, the rule must imply that the attribute is required. To create such an "implicit" extension, use the Validator::extendImplicit() method:
Laravel's validation docs
Try this,
'answer.0' => 'required'
it will help you. I think.
How can I perform validation on custom array in Lumen framework. e.g:
Example array:
$params = array('name' => 'john', 'gender' => 'male');
I have tried something like this but didn;t work:
$validator = Validator::make($params, [
'name' => 'required',
'gender' => 'required'
]);
if ($validator->fails()) {
$messages = $validator->errors();
$message = $messages->first();
echo $message;
exit;
}
The validation is passing because the fields are in fact present. Use something like min or maxor size to validate the length of a string.
http://lumen.laravel.com/docs/validation#rule-required
Edit
I stand corrected. The required does actually seem to validate if it contains anything.
Update
To clarify; the code that is supposed to run if $validator->fails() doesn't ever run if the validation passes.
I'm trying to validate this input:
$values = [
'id' => $input['id'][$i],
'template_id' => $input['template_id'][$i],
'schedulable_id' => $id,
'schedulable_type' => $type,
'order_by' => $i
];
Against these rules found in my Schedule class:
public static $rules = [
'template_id' => 'required|integer|exists:templates,id',
'schedulable_id' => 'required|integer',
'schedulable_type' => 'required|in:Item,Order',
'order_by' => 'integer'
];
When I do the following, I always get an array to string conversion error in "/laravel/vendor/laravel/framework/src/Illuminate/Validation/Validator.php" on line 905:
$validator = Validator::make($values, Schedule::$rules);
if ($validator->fails()) {
$errors[$i] = $validator->messages();
continue;
}
Why would this be happening?
Just discovered I had Ardent's $forceEntityHydrationFromInput = true and my input cannot be pulled directly from Input for validation purposes due to the fact that it is submitted as an array of partially referenced values.
To fix this, change to $forceEntityHydrationFromInput = false and use standard input validation procedure instead of relying on Ardent's magic.
Sometimes clever packages are too clever.