I have this scenario where I have a form as follows:
public $selling_price;
public $numbers;
public $inventory_factor;
public function rules() {
return [
['selling_price'], 'integer'],
[['inventory_factor'], 'safe'],
['numbers', 'each', 'rule' => ['integer']],
}
I have this last validation rule to make sure that I get an array of integers. This works fine when the input is a string for example. IT does not work though if an array [null] is sent. This for example does not throw errors
{
"selling_price": 2200,
"numbers": [null]
}
Using vardumper, gives the numbers array to be
[
0 => null
]
Is there way in Yii2 through which I can either remove(filter) the null values from the array before starting, or validating those as well?
Having looked at the special topic for the core validators, I see that under the each validator it shows:
rule: an array specifying a validation rule. The first element in the array specifies the class name or the alias of the validator. The rest of the name-value pairs in the array are used to configure the validator object.
Also, for the yii\validators\EachValidator, which extends yii\validators\Validator it has a property $skipOnEmpty, which defaults to true:
$skipOnEmpty public property
- Whether this validation rule should be skipped if the attribute value is null or an empty string.
public boolean $skipOnEmpty = true
So, accordingly, you need to tweak your rule as follows.
['numbers', 'each', 'rule' => ['integer', 'skipOnEmpty' => false]],
Now your validator for numbers will not turn a blind eye to the values in the array that are empty - if it finds any empty or non-integer values, the validation will fail.
['numbers', 'integer', 'min' => 0]
This will Validate that the value is an integer greater than 0 if it is not empty. Normal validators have $skipOnEmpty set to true.
Reference : https://www.yiiframework.com/doc/guide/2.0/en/input-validation
in this Data Filtering topic you can refer for these
Related
Summary
Context
Sources
2.1. Unit test
2.2. FormRequest's rules method
Behaviors
3.1. Actual behavior
3.2. Expected behavior
Question
Context
In a Unit test, I want to send data to a FormRequest in a REST call. I am testing the behavior of the validation rules I've written in the rules method of the FormRequest.
Sources
Unit test
public function test_detach_user_job_status()
{
$response = $this->put(route('users.update', ['user' => $this->applier['id']], [
'job' => [
]
]));
$response->assertStatus(200);
}
FormRequest's rules method
public function rules()
{
return [
'name' => 'nullable|string',
'job' => 'nullable|array:id,attach_or_detach,message|required_array_keys:id,attach_or_detach',
'job.id' => 'integer|gt:0',
'job.attach_or_detach' => 'boolean',
'job.message' => 'required_if:job.attach_or_detach,true|string',
];
}
Behaviors
Actual behavior
The test succeeds.
Expected behavior
The test fails. Indeed, the array job is provided but no keys id or attach_or_detach or (eventually) message are provided, whereas the validation rules do specify: required_array_keys:id,attach_or_detach.
Also, if no job array is specified at all, then the validator must not reject the request because this array is not provided, nor its keys: it's perfectly normal since the array must be optional (it is nullable to provide this feature).
Question
Why doesn't Laravel make my test fail since my nullable (= optional) array is provided, and that its keys are required?
You didn't put the correct input. you should put the post body to put() method instead of route() method
change this:
$response = $this->put(route('users.update', ['user' => $this->applier['id']], [
'job' => [
]
]));
to:
$response = $this->put(route('users.update', ['user' => $this->applier['id']]),
[
'job' => []
]);
Laravel's exclude_unless,field,value rule doesn't seem to work in the instance where field is an array of values and value is contained within the field array.
Given the following:
$validator = Validator::make($request->all(), [
'some_array' => 'array',
'some_field' => 'exclude_unless:some_array,foo|alpha_num',
]);
Where some_array is equal to ['foo'], the validator will fail to exclude some_field. This seems to be because the comparison that lies beneath excludes_unless is in_array(['foo'], ['foo']) which returns false.
Is it possible to achieve the same logic of exclude_unless — excluding a field from validation if another field equals a certain value, but where the field being compared against is an array and we're checking that the value is in that array?
As long as you're using Laravel 8.55 or above, you could use Rule::when():
use Illuminate\Validation\Rule;
$someArray = $request->input('some_array', []);
$validator = Validator::make($request->all(), [
'some_array' => 'array',
'some_field' => Rule::when(!empty(array_intersect(['foo'], $someArray)), ['exclude']),
]);
Laravel 5.7. I have a form request validation for a model Foo. The model has an optional field bar, which must be an array. If it is present, it must contain two keys, bing and bang. But if the array is absent, obviously these two keys should not be validated.
This is what I have so far:
return [
'bar' => 'bail|array|size:2',
'bar.bing' => 'required|numeric',
'bar.bang' => 'required|numeric',
];
This works when I send a request with the bar array present. But when I send a request without the bar array, I still get the validation errors
The bar.bing field is required
The bar.bang field is required
How can I make them only required when bar is present?
Try with this rules
return [
'bar' => 'nullable|bail|array|size:2',
'bar.bing' => 'required_with:bar|numeric',
'bar.bang' => 'required_with:bar|numeric',
]
Docs for required_with
Here's what I tend to do in this sort of situations
public function rules(): array
{
$rules = [
// ...
];
if ($this->bar) {
$rules['bar'] = 'array|size:2';
$rules['bar.bing'] = 'required|numeric';
$rules['bar.bang'] = 'required|numeric';
}
return $rules;
}
I'm working on an admin panel where an administrator can setup validation custom validation rules for membership applications. I understand need to setup a $attribute => $rules pair in the database.
However, there is a requested feature I am not quite sure how to implement. The administrator wants each $key => $rule pair to recursively and optionally have children $key => $rule pairs that would be executed if the parent failed. So in the end, each rule could have 0 to many children rules that would all need to pass to make the parent rule pass.
Example:
// Original validation (Assume age = 16, time_at_job = 18 and monthly_income = 3000)
[
'age' => 'min:21', // Fail, but pass because of subset is all pass
'time_at_job' => 'min:6' // Pass
'monthly_income' => 'min:2000' // Pass
]
// If the original age fails and this passes, then age passes and continue to the original
time_at_job.
[
'age' => 'min:18, // Fail, but pass because of subset is all pass
'time_at_job' => 'min:12' // Pass
'monthly_income' => 'min:2500' // Pass
]
// If the subset age passed and this passes, then the subset age passes, but the subset
time_at_job and monthly income will need to pass before the original age can pass.
[
'age' => 'min:16, // Pass
'time_at_job' => 'min:18' // Pass
'monthly_income' => 'min:3000' // Pass
]
Any help on where to start with this would be greatly appreciated.
I would imagine you could use a method call as the array value, like
public function rules(){
return [
'age' => $this->ageChildCheck(),
]
}
Then after the rules in the validator:
public function ageChildCheck(){
$data = $this->validationData();
if($data['time_at_job'] > passNumber && $data['monthly_income'] > passNumber2){
return 'min:0';
}else{
return 'min:18';
}
}
that should allow you to variably set what the validation rules will be in the end. Set it to 0 if it will auto pass if the conditions are met, and to 18 when they fail.
I need to check input array of strings and raise warning if at least one of array elements is empty.
The following rule is used:
return Validator::make($data, [
'branches' => 'array',
'branches.*' => 'filled|max:255'
]);
However it seems filled rule doesn't work (while min:1 works fine).
Should it work with array elements or not?
UPDATE:
branches array is not mandatory, but if exists it should contain non empty elements.
UPDATE:
Finally found mistake in my validation rule.
It should look like
return Validator::make($data, [
'branches' => 'array',
'branches.*.*' => 'filled|max:255'
]);
since input array is array of arrays. Now filled rule works as expected with my input data.
Use required instead
return Validator::make($data, [
'branches' => 'required|array',
'branches.*' => 'required|max:255'
]);
From the documentation: https://laravel.com/docs/5.5/validation#available-validation-rules
required
The field under validation must be present in the input data and not
empty. A field is considered "empty" if one of the following
conditions are true:
The value is null.
The value is an empty string.
The value is an empty array or empty Countable object.
The value is an uploaded file with no path.
If you want to validate the array only if there is field data present use filled. You can combine this with present.
return Validator::make($data, [
'branches' => 'present|array',
'branches.*' => 'filled|max:255'
]);
filled
The field under validation must not be empty when it is present.
present
The field under validation must be present in the input data but can be empty.
Considering your comment you should try nullable
return Validator::make($data, [
'branches' => 'nullable|array',
'branches.*' => 'nullable|max:255'
]);
OR
You can use presentthis will ensure that array should be passed either with values or just an empty array
return Validator::make($data, [
'branches' => 'present|array',
'branches.*' => 'nullable|max:255'
]);