Yii2 rules compareAttribute compare with attribute of another model - validation

during validation I would like to compare with an attribute from another model. Is it possible? If yes, I would be grateful if you would point me to the right direction. I imagine it somehow to access model B in model A, but maybe my logic is not good, and I have no clue how can this be achieved. Thanks.

You can try to build an inline validator see this doc for validator and for inline validator
this is a brief sample
public function rules()
{
return [
.....
['my_field', 'validateMyCompare'],
....
];
}
public function validateMyCompare($attribute, $params)
{
if (YourModel::findOne(['your_model_field'=> $attribute]) {
$this->addError($attribute, \Yii::t('view', 'The fields don't match.'));
}
}

I've solved it this way:
public function getRelatedmodel() {
return $this->hasOne(\app\models\Relatedmodel::className(), ['id' => 'relatedId']);
}
public function getMotherRelatedAttribute() {
if ($mother = Model::findOne($this->mother)) {
return $mother->relatedmodel->attribute;
}
}
And in rules:
['attribute', 'compare', 'compareAttribute' => 'MotherRelatedAttribute', 'operator' => '<=', 'on' => self::SCENARIO_CREATE_RST],

compare
[
// validates if the value of "password" attribute equals to that of "password_repeat"
['password', 'compare'],
// validates if age is greater than or equal to 30
['age', 'compare', 'compareValue' => 30, 'operator' => '>='],
]
This validator compares the specified input value with another one and make sure if their relationship is as specified by the operator property.
compareAttribute: the name of the attribute whose value should be compared with. When the validator is being used to validate an attribute, the default value of this property would be the name of the attribute suffixed with _repeat. For example, if the attribute being validated is password, then this property will default to password_repeat.
compareValue: a constant value that the input value should be compared with. When both of this property and compareAttribute are specified, this property will take precedence.
operator: the comparison operator. Defaults to ==, meaning checking if the input value is equal to that of compareAttribute or compareValue. The following operators are supported:
==: check if two values are equal. The comparison is done is non-strict mode.
===: check if two values are equal. The comparison is done is strict mode.
!=: check if two values are NOT equal. The comparison is done is non-strict mode.
!==: check if two values are NOT equal. The comparison is done is strict mode.
: check if value being validated is greater than the value being compared with.
=: check if value being validated is greater than or equal to the value being compared with.
<: check if value being validated is less than the value being compared with.
<=: check if value being validated is less than or equal to the value being compared with.

Related

How to add validation for field accept number and null? [Laravel 7.x]

I want to store the score value as a number when is_pass is true. If is_pass is false then score should be null. So I added validation like below for score
'score' => 'required_if:is_pass,true|numeric'
But I have an issue when is_pass is false then also it's expected score value as numeric. How to solve this issue? Is there any diffrent option is there other than custom validation? I am using laravel 7.
You should define a variable to keep you rules.
Then base on condition change your rules.
if((bool) $request->is_pass === true)
$rules['score'] = 'required_if:is_pass,true|numeric';
else
$rules['score'] = 'required_if:is_pass,false|null';
You can use nullable validation with numeric here and here
'score' => 'nullable|numeric'
what this will do is check if the value is not null then apply numeric validation otherwise skip validation and accept it as null.

Laravel FormRequest validating minimum string length only in minimum amount of input fields

In my laravel (5.7) app I have a form request with an array of input fields.
The Array "answers" has 8 distinct input fields. Until now I've been able to have a validation rule that checks each of the elements are at least 10 characters long.
class MyFormRequest extends FormRequest
{
public function rules()
{
$rules = [
'answers' =>'required',
'answers.*' =>'required|min:10',
];
}
}
but I want to change the requirement to only apply to 4 of the input fields, regardless of order. So if for example the user filled input fields number 1,5,6,8, each with 10 characters, the form would be accepted although fields 2,3,4,7 are empty.
How can I achieve this? I read in the documentation that one can use the sometimes rule, but the examples use it in the controller and I don't undertand how I apply a custom sometimes rule in the FormRequest class.
Thanks in advance!
Try this;
$rules = [
'answers' => 'required|array|min:4',
'answers.*' => 'sometimes|min:10',
];
meaning;
"answers" -> answers is an array, has at least 4 indexes,
"answers.*" -> in answers array, indexes should validate when it present
Check Validating When Present and Validating Arrays

How to have a CakePHP model field requirement checked manually?

QUESTION UPDATED: I found out more information and therefor changed my question.
I want to save my user with his license number, but only if he selects that he has a license. I have three possible values for the pilot_type field (ROC, ROC-light and recreative) and only the last option should allow for an empty string to be submitted.
In order to achieve this, I wrote the following validation function:
$validator
->add('license_nr', 'present_if_license', [
'rule' => function ($value, $context) {
return $context['data']['pilot_type'] == 'recreative' || !empty($value);
},
'message' => "If you don't fly recreatively, a license number needs to be supplied"
]);
The problem is that setting any validation rule on a field will trigger an additional check in the CakePHP Model class that will reject the value if it's empty. I tried to fix this by adding ->allowEmpty('license_nr'), but that rule makes for the model to accept an empty string without even running my custom function. Even putting them in order and using 'last' => true on my custom rule doesn't resolve this problem:
$validator
->add('license_nr', 'present_if_license', [
'rule' => function ($value, $context) {
return false;
// return $context['data']['pilot_type'] == 'recreative' || !empty($value);
},
'last' => true,
'message' => "If you don't fly recreatively, a license number needs to be supplied"
])
->allowEmpty('license_nr');
How do I make CakePHP run my custom function in order to see if the field can be empty, rather than just assuming that it can never be empty or must always be empty?
By default fields aren't allowed to be empty, so that's the expected behavior and you'll have to explicitly allow empty values.
In order to achieve what you're trying to do, instead of using an additional rule, you should customize the allowEmpty() rule, use the second argument to supply a callback (note that unlike rule callbacks it will receive a single argument that provides the context).
So you'd do something like this, which you may need to modify a bit, for example depending on whether you need it to work differently for creating ($context['newRecord'] = true) and updating ($context['newRecord'] = false) records:
->allowEmpty(
'license_nr',
function ($context) {
return $context['data']['pilot_type'] === 'recreative';
},
"If you don't fly recreatively, a license number needs to be supplied"
)
As of CakePHP 3.7 you can use allowEmptyString(), it will work the same way, you just need to swap the second and third arguments, as allowEmptyString() takes the message as the second argument, and the callback as the third argument.
See also
Cookbook > Validation > Conditional Validation

Laravel price validation only accept positive number and not only 0

I want to validate a "price" field in Laravel.
The price should only contain numbers without (.) or (,) and cant start with 0 as well.
Eg
2500 // Pass
02500 // Fails
12.12 // Fails
12,12 / Fails
The rule I have now looks like this:
'price' => 'required|integer|not_in:0',
It seems to work with the example above, however I dont understand it. Why does not integer allow something like 0123 with a starting zero. I just want to make sure that my rule works as excpected and that I dont miss something
Thanks
This works for me:
'price' => 'required|numeric|gt:0',
You can format the input before sending it to the validator in your Request class.
public function formatInput()
{
$input = array_map('trim', $this->all());
$input['price'] = (int)($input['price']);
$this->replace($input);
return $this->all();
}
Then you can use
'price' => 'required|integer|min:0',
Hope this helps
if you're not sure about the rule "integer", you can use the regex expression validation as following :
'price' => 'required|regex:^[1-9][0-9]+|not_in:0',
I had some issue same way as you, and since then i always used the regex validation for this kind of requirements. Furthermore it allow you to take back the same regex if you want to make a front validation with js.
Here is the laravel function allowing to validate integers :
public function validateInteger($attribute, $value)
{
return filter_var($value, FILTER_VALIDATE_INT) !== false;
}
SO it's PHP itself that is concerned by this behavior. PHP tells us this thing about FILTER_VALIDATE_INT :
Validates value as integer, optionally from the specified range, and
converts to int on success.
No other informations are set by PHP about the "0" value, but it's known that this function doesn't consider numbers starting by "0".
Use regex rule to not allow for integer with starting 0
'price' => 'required|integer|not_in:0|regex:^[1-9][0-9]+',

CakePHP :: What to return for custom validation method?

I have a custom validation rule to make sure that a non-zero price is set in a field. I have a placeholder (0.00) in the field to keep users from entering things like dollar signs. When I go to validate for a non-zero entry, however, $this->data[$this->alias]['price'] is '0.00' in my test, but the validation is working - it invalidates. But when I put in 1000.00, it's also invalidating.
One thing I can't find is what/how to return from a custom validation field to invalidate the field. Currently, the code is:
public function notZeroPrice($check){
if ($check == '0.00')
return true;
return false;
}
The docs aren't clear on the structure of $check either.
If it validates, return true. If the doesn't, return false.
However, your validation method is flawed to begin with. $check is an array if you debug it, so your method is always going to return false. Secondly, you want to test if its > 0, not just equal to '0.00'. You'll be comparing 2 string so that won't work, either.
Instead, return true if the value is greater than 0 (int). You can get it value out of the array easily by using array_shift($check);
return array_shift($check) > 0; // or something similar.
You may even get away with 'rule' => array('comparison', '>', 0), core validation.
(I'm assuming not zero for a price also means not a negative price)

Resources