Laravel validating required at least one element in array - php

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

Related

Validating non-required associative array with required fields

I want to validate that if my request contains a field of associative array type, that array needs to contain specific fields (but only if it's present)
Ie, array, if present, needs to contain foo:
{ data: {}}
and
{ data: { array: { foo: 1 } }
is fine, but
{ data: { array: {} }
and
{ data: { array: { bar: 1 } }
is not.
I've written this validator:
['data.array' => 'sometimes', 'data.array.foo' => 'required']
But it doesn't accept the first scenario.
>>> \Illuminate\Support\Facades\Validator::make(
['data' => []],
['data.array' => 'sometimes', 'data.array.foo' => 'required']
)->errors()->all();
=> [
"The data.array.foo field is required.",
]
I'd like to avoid using 'data.array.foo' => 'required_with:data.array' (it also doesn't work for scenario when array is empty)
>>> \Illuminate\Support\Facades\Validator::make(
['data' => ['array' => []]],
['data.array' => 'sometimes', 'data.array.foo' => 'required_with:data.array']
)->errors()->all();
=> []
Are there any non-custom validators that will help me accomplish this?
You can also use Rule::requiredIf after Laravel 5.6 and up, try this:
$validator = Validator::make( $request->input(), [
// ...
'data.array.foo'=> Rule::requiredIf( function () use ($request){
return (bool) $request->input('data.array');
})
]);

Laravel validation - required only when two conditions are true

I want purchaser_first_name and purchaser_last_name to be required only when the value of gift input in the request is true and the value of authenticated input is false.
What I have tried so far:
public function rules()
{
return [
'gift' => 'required',
'authenticated'=>required,
'purchaser_first_name' => 'required_if:gift,true,required_if:authenticated,false',
'purchaser_last_name' => 'required_if:gift,true,required_if:authenticated,false',
];
}
This approach turns out to use OR operator instead I want the AND operator.
You can try like this:
'purchaser_first_name' => Rule::requiredIf(function () use ($request) {
return $request->input('gift') && !$request->input('authenticated');
}),
In the function, you can set your logic. I'm not sure what you need for real, but it's good for a start.
Also, check docs for more info about that.
Try to change your validation code as below :
return [
'gift' => 'required',
'authenticated'=>'required',
'purchaser_first_name' => 'required_if:gift,true|required_if:authenticated,false',
'purchaser_last_name' => 'required_if:gift,true|required_if:authenticated,false',
];

Laravel 5.5 Conditionally adding validation rule

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.

Converting Laravel validation message dot syntax into array

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

Laravel 5.4 Validator - Show the wrong value passed

Is there a way to insert, in the validator message, the wrong value passed from user?
UPDATE:
For example, If the field must accept a value from "1" to "10" and you insert "200" I'd like to write:
'The :attribute must be between 1 and 10. Your value is 200.':
$validator_default_message = [
'digits_between' => 'The ":attribute" must be between :min and :max.',
];
$validator = Validator::make($phase, [
'depth' => 'digits_between:0,10',
], $validator_default_message);
if ($validator->fails()) {
$status = $validator->failed();
$errorMessage = $validator->messages()->all();
abort($status, $errorMessage);
}
And I'd like to return the message:The depth must be between 0 and 10. Your input value is 200.
Thank you.
inside Request file add :
public function messages()
{
return [
'input_name.numeric' => 'your massage'
];
}
for more info check here : https://laravel.com/docs/5.4/validation#customizing-the-error-messages
public function messages()
{
return [
'fieldname.numeric' => 'The :attribute must be numeric. Your value is '.$request->input('fieldname')
];
}
This might offer you more insight:
https://laracasts.com/discuss/channels/general-discussion/laravel-5-custom-error-messages
That messages() method can be put on here: app/Http/Requests/YourRequest.php
From #Laracasts:
Using Laravel 5 .4 and saw that the validate() method optionally accepts the messages[] as its third argument and did this.
$this->validate($request,
[
'document_date_created' => 'required',
'document' => 'required'
],
[
'document_created_at.required' => 'Sample message',
'document.required' => 'Another Sample Message'
]
);
When you have an instance of a Validator on which you used the validate() method, it will return back to the page with the old values which can be retrieved by using old('form field') i.e. old('title')
In your view you can check if you have an error message for a specific field and rule by using:
if($errors->has('input_name.numeric')){
//code
)
Here you could use the old input value to return a message:
{{$errors->get('input_name.numeric').
' Your value was ' . old('input_name') . '.'}}
This will print for example:
The input_name must be between 1 and 10. Your value was 200.
Documentation about retrieving old input can be found here.
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
so basically the rule of the game is
return [
yourFieldName.ValidationRule => Customessage
]
and $request->input('fieldname') to access the value
this is an example taken from laravel doc

Categories