How can I set safe or allow empty captcha on scenario? - yii2

I want to set safe or allow empty captcha on scenario like bellow code.
public function rules() {
return [
[['verifyCode'], 'safe', 'on'=>'admin'],
];
}
But it does not work, and I got this error.
Invalid CAPTCHA action ID: site/captcha
and also this page didn't help me.

Try this. Add rule:
[['verifyCode'], 'captcha', 'skipOnEmpty' => true, 'on'=>'admin']
In controller, when create instance:
$model->scenario = 'admin';

Related

Yii2 validation message doesn't change

I have simple ajax validation for email.
$rules[] = [['email'], 'unique', "message"=>"Email адресът {value} вече съществува!"];
But my custom message doesn't show. It always return default message: This email address has already been taken. Any clue why is this? I thought it is as simple as that.Where i am wrong? Btw it is user dektrium module if that matters.Thank you in advance!
You should return the values in
public function rules()
{
return [
[['email'], 'unique', "message"=>"Email адресът {value} вече съществува!"];
// the email attribute should be a valid email address
['email', 'email'],
];
}
eventually you should extend or redefine the User Model rules() function

How to make that GridView buttons update and delete just only visible for admins?

I am new to Yii2 and I have 3 kind of user rights:
Admin, moderator and user. I have my GridView and I don't want to show for the user the Update and Delete buttons, just only the GridView. How should I do that?
Here is my actionCreate, there is an input form:
public function actionCreate()
{
$model = new Project();
$model->scenario = Project::SCENARIO_CREATE;
if ($model->load(Yii::$app->request->post())) {
if ($model->save()) {
Yii::$app->getSession()->setFlash('success', Yii::t('app', 'Skelbimas sėkmingai pridėtas!'));
return $this->redirect(['index']);
}
}
return $this->render('create', [
'model' => $model,
]);
}
I've tried to search the information according to this, but couldn't find useful ones. Thanks for any help or information.
To accomplish this, you have to use the property $visibleButtons of you ActionColum class.
So:
'visibleButtons' = [
'update' => Yii::$app->user->can('update'), // or whatever condition
'delete' => Yii::$app->user->can('update')
]
and so on. Each Key on the visibleButtons array is the name of the button.
Yii Framework's guide
    .........
        [
            'class'=>'yii\grid\ActionColumn',
            'template'=> '{view} {update} {delete} ',
            'buttons'=> [
                'update'=> function($url,$model) {
if (Yii::$app->user->can('admin')) {
                    returnHtml::a( '<span class="glyphicon glyphicon-pencil"></span>', $url);
}
                },
                'delete'=>function($url,$model,$key) {
if (Yii::$app->user->can('admin')) {
                        returnHtml::a('delete', $url);
}
                },
            ],
        ],
One possibility would be using the 'template' attribute of youe 'ActionColumn' like:
[
...
'template'=> (user has only user rights ? '{view}' ? '{view} {update} {delete}')
...
]
Please, bare in mind that even though this solution will hide the buttons for users with only user right, it won't prevent them of accessing update and delete action urls, so you have to check permissions also in the controller level.

Yii2: Non-Scenario fields are not saved

I'm using different scenario for validation purpose.
The field email is not required in a scenario but if i pass email, it is not getting saved in DB.
Rules in Model:
[['firstname','email'], 'string', 'max' => 256],
Scenario function
public function scenarios() {
$scenarios = parent::scenarios();
$scenarios['insert2'] = ['firstname', 'status'];
return $scenarios;
}
In controller:
$model = new User();
$model->scenario = "insert2";
$model->load($data);
print_r($model);
Print_r returns email with empty
From Yii 2 load() docs:
Note, that the data being populated is subject to the safety check by setAttributes().
Now, setAttributes() signature:
public void setAttributes ( $values, $safeOnly = true )
where $safeOnly set to true means the assignments should only be done to the safe attributes. A safe attribute is one that is associated with a validation rule in the current $scenario.
So email must be included in the scenario.
In Yii2, when you want the rule to be applied on certain scenarios, you can specify the on property of a rule, like the following
public function rules()
{
return [
//rule applied only in scenario 'insert2'
[['first_name','status'], 'required','on' => 'insert2'],
//rule applied in all scenarios
['email','safe'],
//rule applied only in scenario 'insert3'
[['first_name','status','email'], 'required','on' => 'insert3'],
];
}
Now if you specify $model->scenario = "insert2" in controller then first_name and status are required and email if you give any value will get saved because ['email','safe'] rule also applied here.
If you specify $model->scenario = "insert3" in controller then first_name,status and email are now required fields and rule ['email','safe'] also get applied.
Please note you may not use public function scenarios() {.. here
From http://www.yiiframework.com/doc-2.0/guide-structure-models.html#validation-rules

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

Ignore validation on soft deleted models

I have user table. I created a form with 3 fields:
Username
phonenumber
status
The first two fields are unique. Model rules for those fields look like this:
[['Username', 'phonenumber'], 'required'],
[['Username', 'phonenumber'], 'unique'],
I use soft deletion, so when record is deleted, it actually stays in database but status value will change to 0.
The problem is, if I add a record with existing username it shows an error message like "already added". I need to ignore validation if username have a status with value 0.
Use filter property of UniqueValidator
public function rules()
{
return [
...
['username', 'unique', 'filter' => ['<>', 'status', 0]];
...
];
}
It's better to declare constant instead of 0 (something like const STATUS_DELETED = 0) and user it as self::STATUS_DELETED inside of User class. Also you can use != instead of <>.
The last recommendation will be to use username instead of Username to follow convention of naming database table columns.
Read more about ways of declaring filter in official docs.
The ways of setting filter condition as array is described here.
You can use your own function to decide the given username already exists in active status or not. Use this function in "when" property of your unique validation rule.
Have a look :
public function rules()
{
$check = function($model) {
$existActiveUser = User::model()->findByAttributes(array("username"=>$model->username,"status"=>1));
if($existActiveUser)
return true;
else
return false;
};
return [
['Username', 'phonenumber'], 'required'],
[['Username','phonenumber'],'unique','when'=>$check],
}