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.
Related
I'm trying to combine two data into one column. I already managed to combine two data in one column. But my problem is I don't know how to do a break line to separate the data. I have tried this way but doesn't work.
This is my code
'NAME_PROG_ENG'.'REMARKS' => ['label' => "Programme Name",'value' => function ($data) {return ($data->NAME_PROG_ENG)."\r\n".nl2br("Previously known as: ".($data->REMARKS));}],
I think you refer to GridView component.
Some explanation:
'NAME_PROG_ENG'.'REMARKS' =>
the array index is the model field name, you can't combine 2 columns just by concatenating the column name. In this way you just define a column in the grid wich is not connected to the model. This is not an error, is just to notice that this does not give you the expected result.
'value' => function ($data) {return ($data->NAME_PROG_ENG)."\r\n".nl2br("Previously known as: ".($data->REMARKS));}
Between $data->NAME_PROG_ENG and $data->REMARKS you put a "\r\n" which is fine, but you apply nl2br() function only to the second part of the string.
Now about Gridview. Text are automatically converted to entities, this is a security feature to avoid script injection from user input. If you plan to use input from an untrusted user, ensure that you clean it using htmlpurifier before saving it in database or before showing it (in your 'value'=>... function)
https://www.yiiframework.com/search?language=en&version=2.0&type=guide&q=htmlpurifier
You can bypass html entity conversion by specifies the output format as raw in grid column option
'format'=>'raw'
So you column definition should be something like
'prog_and_remark_combined' => [
'format' => 'raw',
'label' => "Programme Name",
'value' => function ($data) {
return nl2br(
$data->NAME_PROG_ENG .
"\r\nPreviously known as: " .
$data->REMARKS
);
}
],
Gridview allow a short notation
https://www.yiiframework.com/doc/api/2.0/yii-grid-gridview#$columns-detail
which is like this
<column name>:<fomat>:<label>
your code can be as follow as well
'prog_and_remark_combined:raw:Programme Name' => [
'value' => function ($data) {
return nl2br(
$data->NAME_PROG_ENG .
"\r\nPreviously known as: " .
$data->REMARKS
);
}
],
Last note, if the fields does not contain new line to be converted, just concatenate them without using nltobr() function
return $data->NAME_PROG_ENG . "<br>Previously known as: " . $data->REMARKS
I have a Model who has a column (attribute) that stored a comma separated value of IDs.
For Example,
Movie has a column "Genre" that includes more than one genre, e.g.: 40,20,1,3
How can I use Select2 widget to show these values separated when 'multiple' => true
And how can I save them back into comma-separated value as a string. I want a solution that will allow for quick flexibility. I know you can implode and explode the string but seems too much.
Any help appreciated
If I remember correctly pass the default option as part of the $options configuration for the widget:
echo $form->field($model, 'model_attribute_name')->widget(Select2::className(), [
'data' => $data
'options' => [
'class' => 'form-control',
'placeholder' => 'Choose Option...',
'selected' => 40
],
'pluginOptions' => [
'allowClear' => true,
],
])->label('Select2 Form Field');
This is from memory for grain fo salt here. The documentation at http://demos.krajee.com/widget-details/select2 is not very specific about how to do this.
I don't believe you can do that. Select2 sends the data in post as an array, so you would still need to use implode before saving. What i would do instead is in your model class:
class MyModel extends \yii\db\ActiveRecord {
$public myArrayAttribute;
...
public function beforeSave($insert) {
if (parent::beforeSave($insert)) {
$this->myAttribute = implode(',', $this->myArrayAttribute);
return true;
}
return false;
}
public function afterFind() {
parent::afterFind();
$this->myArrayAttribute = explode(',', $this->myAttribute);
}
}
This way myArrayAttribute will hold the values from the comma separated field as an array. Of course you will need to add validation rules for it and use it instead of your other attribute in create and update forms.
if you're displaying a form with already populated fields, maybe you want to update an already existing object, and you want to display the already saved value for the Select2 field, use 'data' => [ 1 => 'Some value' ], where 1 is the value, associated to the value displayed in the form. You can retrieve stuff to put in data from DB beforehand.
Source: https://github.com/kartik-v/yii2-widget-select2/issues/37
I've 2 different tables with 2 columns [code,status] each and the column 'code' contains unique code in integers (392,21,2981,2743,..etc) and they are about 100 in each table while the status tells if these codes were used or not.
I want the form to be only submitted when both of the provided codes from the user match the codes in those 2 tables and have the status '0'
I could create a very simple validation in the controller but that dosen't make much sense to what i just explained
public function formValidationPost(Request $request)
{
$this->validate($request,[
'name' => 'required|min:5|max:35',
'email' => 'required|email|unique:users',
'mobile' => 'required|numeric',
'code_a' => 'bail|required|exists:code_a,code',
'code_b' => 'bail|required|exists:code_b,code'
],[
'name.required' => ' The name field is required.',
'name.min' => ' The name must be at least 5 characters.',
'name.max' => ' The name may not be greater than 35 characters.',
]);
dd('You successfully added all fields.');
}
So with my validation rules I want to be able to make sure that:
Form doesn't submit unless both the provided codes are matched in the database ( code_a[table] and code_b[table] ) and their status to be '0'
I hope this makes sense.
Thanks
Reference
use Illuminate\Validation\Rule;
$this->validate($request,
[...
'mobile' => 'required|numeric',
'code_a' => [
'bail',
'required',
Rule::exists('code_a', 'code')->where(function($query) {
$query->where('status', 0);
})
],
'code_b' => [
'bail',
'required',
Rule::exists('code_b', 'code')->where(function($query) {
$query->where('status', 0);
})
]
],
[...]);
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']
];
}
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'