Prb with inline validator yii2 - yii2

I have written my own rule which must validate an array:
public function arrayValidation($attribute, $params)
{
(is_array($this -> $attribute)
&& isset($params['min']) ? count($this -> $attribute) >= $params['min'] : true
&& isset($params['max']) ? count($this -> $attribute) <= $params['max'] : true)
? NULL : $this -> addError($attribute, "$attribute must be array.");
}
and use it on the rules function:
['hashtags', 'arrayValidation', 'min' => 0, 'max' => 3],
but yii2 complain of
Unknown Property – yii\base\UnknownPropertyException
Setting unknown property: yii\validators\InlineValidator::min
P.S. Sorry for my bad english.

You need to change your code like below:
['hashtags', 'arrayValidation','params'=>['min' => 0, 'max' => 3]],
In order to pass params to a custom validator, you should write it like above.

Related

Yii2 : Require at least one of the two fields

One of the two phone numbers phone_parent or phone_students must be provided AND they must be an integer. When combined, only atLeastValidator works, when I leave it out, the integer works. Out of ideas. Any hint?
[['phone_parent', 'phone_student'], 'integer'],
['phone_student', AtLeastValidator::class, 'in' => ['phone_student', 'phone_parent']],
['phone_parent', AtLeastValidator::class, 'in' => ['phone_student', 'phone_parent']],
update: I've just discovered that integer works when I try to submit (no request is sent yet, I remain on form page); However it should work on focus out - just like all the other validators; It's an instance of ActiveForm.
I don't think you need to have that custom AtLeastValidator, you can use when and whenClient in the following way to work the way you want.
Your rules should look like below
[
['phone_parent'],
'required',
'when' => function ($model) {
return ($model->phone_student == '');
},
'whenClient' => 'function(attribute,value){
return ($("#testform-phone_student").val()=="");
}',
'message' => 'Either Parent or Student Phone must be filled',
],
[
['phone_student'],
'required',
'when' => function ($model) {
return ($model->phone_parent == '');
},
'whenClient' => 'function(attribute,value){
return ($("#testform-phone_parent").val()=="");
}',
'message' => 'Either Parent or Student Phone must be filled',
],
[['phone_parent', 'phone_student'], 'integer'],
Above all i would use a regular expression in order to validate the phone number to be valid rather than just using integer that will allow 0 as a pone number or mobile number which isnt valid. using match validator with a regex in the pattern will make it solid.

Yii2 compareValidator when

During user input validation I would like to compare an attribute with a value.
I have this code:
['ao_id', 'compare', 'when' => function($model) {
return $model->lqp_id == 24 || $model->lqp_id == 26 || $model->lqp_id == 46;
}, 'compareValue' => 50],
It works (however only when 'enableClientValidation' => false), but is it possible, to show rather the name of the foreign attribute somehow? Because it doesn't help much if the user is getting an error message that outer surface (ao_id) must be 50. Nobody has a clue what does it mean, because in the dropdown you see only the names and not the ids. Many thanks!
First of all, if you want your conditional validation to work on the client-side too (when enableClientValidation=>true), then add the whenClient property which contains the javascript code that will do the validation.
Second, you can use the message property to specify a custom validation error.
[
'ao_id',
'compare',
'when' => function ($model) {
return $model->lqp_id == 24 || $model->lqp_id == 26 || $model->lqp_id == 46;
},
'whenClient' => "function (attribute, value) {
return $('#lqp_id').val() == '24' || $('#lqp_id').val() == '26' || $('#lqp_id').val() == '46';
}",
'compareValue' => 50,
'message'=>'ao_id must be 50 when lqp_id is 24, 26 or 46'
]
Attention: be sure to check and change the id of the input field $('#lqp_id') as this is most likely different to my example.
Add message key where you define your own message that will be displayed instead of default one.

Yii2 HTML purifier

I've got a question about Yii2's validation. So, my model validation rule's something like this:
return [
['status', 'required', 'on' => 'update'],
[['status'], function ($attribute) {
$this->$attribute = \yii\helpers\HtmlPurifier::process($this->$attribute);
}],
];
The problem is that if the content is <script>alert('something')</script>, it will be blank due to purifier and the content will pass the required validation.
So how can I revalidate the content for require? Or what is the good way to do it?
Validation rules are processed one after another so just put the second one as first.
return [
['status', 'filter', 'filter' => function ($value) {
return \yii\helpers\HtmlPurifier::process($value);
}],
['status', 'required', 'on' => 'update'],
];

targetAttribute (Or something similar) for required validator (Yii2)

So, here is my scenario. I have got a model called URL. URL has the following attributes: link (required), scheme (required, but not safe.scheme is parsed from the link) and a few other attributes as well, which are not in context to this question.
Now, I made a custom validator for the scheme, which is following:
public function validateScheme($attribute, $param) {
if(empty($this->scheme)){
$this->addError('link', Yii::t('app', 'This is an invalid URL.'));
}
if (!in_array($this->scheme, $this->allowedSchemes)) {
$this->addError('link', Yii::t('app', 'This is an invalid URL.'));
}
}
Rules for URL:
public function rules() {
return [
['link', 'required', 'message' => Yii::t('app', 'URL can\'t be blank.')],
[['link'], 'safe'],
[['link'], 'string'],
['scheme', 'validateScheme']
];
}
This works fine when an invalid scheme is encountered, for example like let's say ftp.
However, when a completely invalid URL is entered, the scheme remains empty and the validateScheme is never triggered as, attribute scheme is not required. To verify, I called $model->validate() and it returns true even if it should not (or should may be, because the attribute is not required anyway).
So, my question number 2 : Is there a way to force the validateScheme be triggered no matter if the attribute is empty, or non empty? I do not seem to find a way to do this in documentation.
I then tried the other way around, and made scheme a required field. The problem with that is the fact that scheme field is not safe and not there in the form. So, the URL does not save, but no error is shown.
My question number 1, in that case would be: Is there a way to assign targetAttribute for scheme so that the error message is shown below link?
P.S. I know I can do this in the controller. I do not want to do that. I want to use the model only.
Another solution is, instead of having a default value, you could enable verify on empty (by default, it does not validate empty and not required fields). Something like this:
public function rules() {
return [
['link', 'required', 'message' => Yii::t('app', 'URL can\'t be blank.')],
[['link'], 'string'],
['scheme', 'validateScheme', 'skipOnEmpty' => false]
];
}
See more here.
Okay, setting a default value in the rules() solved my problem. The modified rules():
public function rules() {
return [
['link', 'required', 'message' => Yii::t('app', 'URL can\'t be blank.')],
[['link'], 'safe'],
[['link'], 'string'],
['scheme', 'default', 'value' => 0],
['scheme', 'validateScheme']
];
}

Changing value of an attribute in DetailView widget

I have a table named Play and I'm showing details of each record in Yii2 detail view widget. I have an attribute in that table recurring which is of type tinyint, it can be 0 or 1. But I don't want to view it as a number, instead i want to display yes or no based on the value (0 or 1).
I'm trying to change that with a function in detailview widget but I'm getting an error: Object of class Closure could not be converted to string
My detail view code:
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'name',
'max_people_count',
'type',
[
'attribute' => 'recurring',
'format'=>'raw',
'value'=> function ($model) {
if($model->recurring == 1)
{
return 'yes';
}
else {
return 'no';
}
},
],
'day',
'time',
...
Any help would be appreciated !
Unlike GridView which processes a set of models, DetailView processes just one. So there is no need for using closure since $model is the only one model for display and available in view as variable.
You can definitely use solution suggested by rkm, but there is more simple option.
By the way you can simplify condition a bit since the allowed values are only 0 and 1:
'value' => $model->recurring ? 'yes' : 'no'
If you only want to display value as boolean, you can add formatter suffix with colon:
'recurring:boolean',
'format' => 'raw' is redundant here because it's just text without html.
If you want add more options, you can use this:
[
'attribute' => 'recurring',
'format' => 'boolean',
// Other options
],
Using formatter is more flexible approach because these labels will be generated depending on application language set in config.
Official documentation:
DetailView $attributes property
Formatter class
Formatter asBoolean() method
See also this question, it's quite similar to yours.
Try
'value' => $model->recurring == 1 ? 'yes' : 'no'