Yii2 rules work only use scenario - yii2

I write two scenario in Yii2 comment model, when user logged on or is guest.
my rules is:
public function rules()
{
return [
[['user_id'], 'required', 'on' => self::SCENARIO_USER],
[['name', 'email'], 'required', 'on' => self::SCENARIO_GUEST],
[['post_id', 'body', 'date'], 'required'],
[['user_id', 'parent_id', 'post_id', 'status'], 'integer'],
[['body'], 'string'],
[['date'], 'safe'],
[['name', 'email', 'site'], 'string', 'max' => 256],
];
}
and senarios funtion :
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_GUEST] = ['name' , 'email'];
$scenarios[self::SCENARIO_USER] = ['user_id'];
return $scenarios;
}
I use it as follows:
$commentModel = Yii::$app->user->isGuest ? new Comment(['scenario' => Comment::SCENARIO_GUEST]) : new Comment(['scenario' => Comment::SCENARIO_USER]);
if guest view form, only name and email checked and user fill form, no field checked !
why other rules don't check? how to fix it?

Refer Yii2 Scenarios
The scenarios() method returns an array whose keys are the scenario names and values the corresponding active attributes. An active attribute can be massively assigned and is subject to validation.
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_GUEST] = ['name' , 'email', 'date', 'body', 'site', 'post_id'];
$scenarios[self::SCENARIO_USER] = ['user_id', 'date', 'body', 'site', 'post_id'];
return $scenarios;
}

If you use scenarios() you need to define all attributes allowed to assign in given scenario. So if you want to allow guest to edit also body and date you need something like:
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_GUEST] = ['name' , 'email', 'body', 'date'];
$scenarios[self::SCENARIO_USER] = ['user_id'];
return $scenarios;
}
If you have many "shared" attributes between scenarios, you probably should not override this method and define it in rules() only.
See more in scenarios documentation.

Related

Grading System Validation using Yii2

I am developiging a Grading System as shown below:
Model
public static function tableName()
{
return 'grade_item';
}
public function rules()
{
return [
[['grade_max', 'grade_min'], 'required'],
[['grade_max', 'grade_min'], 'number'],
];
}
How do I validate, probably from the Model between the grade_min and grade_max. Also, grade_min should not be greater that or equal to grade_max. I want to do it as shown in the diagram below. None of the contents of each row should be the same.
Use Compare validator
This validator compares the specified input value with another one and make sure if their relationship is as specified by the operator property.
public function rules()
{
return [
[['grade_max', 'grade_min'], 'required'],
[['grade_max', 'grade_min'], 'number'],
['grade_max', 'compare', 'compareAttribute' => 'grade_min', 'operator' => '>', 'type' => 'number'],
['grade_min', 'compare', 'compareAttribute' => 'grade_max', 'operator' => '<', 'type' => 'number'],
];
}

Yii2 remove unique validator

I have an AR model, it has the following rules:
/**
* #inheritdoc
*/
public function rules() {
return [
[['category_id', 'source', 'url', 'title', 'thumbs', 'duration', 'status', 'created_at'], 'required'],
[['category_id', 'status', 'views', 'ratings', 'created_at'], 'integer'],
[['rating'], 'double'],
[['source', 'url', 'title', 'slug'], 'string', 'max' => 255],
[['url'], 'unique', 'on' => 'create'],
[['category_id'], 'exist', 'skipOnError' => true, 'targetClass' => Category::className(), 'targetAttribute' => ['category_id' => 'id']],
];
}
I want to do a soft delete so I have the following.
/**
* Deletes an existing Video model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* #param integer $id
* #return mixed
*/
public function actionDelete($id)
{
$model = $this->findModel($id);
$model->status = 0;
//var_dump($model->validate());
//var_dump($model->getErrors());die;
$model->save();
return $this->redirect(['index']);
}
But unfortunately I cannot change the status of model, because the validation says that (The url xxxxxxx has been taken) so I went to the PostgreSql, and I checked the records, but unfortunately only the updating record has this value! So in my mind the Yii2 unique validatios is bad. I would like to remove the unique validator, but it seems it is impossible. Because I commented out the uniqure row in the rule array, but it did not help me. I restarted the machine, but I do not know, it seems Yii2 want always check the url is unique or not.
You can use scenario
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['soft_delete'] = ['status',]; //Scenario Values Only Accepted
return $scenarios;
}
public function actionDelete($id)
{
$model = $this->findModel($id);
$model->status = 0;
$model->scenario = 'soft_delete';
//var_dump($model->validate());
//var_dump($model->getErrors());die;
$model->save();
return $this->redirect(['index']);
}
or another way is suppress validation for this action
public function actionDelete($id)
{
$model = $this->findModel($id);
$model->status = 0;
//var_dump($model->validate());
//var_dump($model->getErrors());die;
$model->save(false);
return $this->redirect(['index']);
}

Yii2 dektrium add new field to user model and change it in account form

I have added a new field to user model 'paypal' and need to change it in overridden account form.
Override user model
<?php
namespace common\models;
class User extends \dektrium\user\models\User
{
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['create'][] = 'paypal';
$scenarios['update'][] = 'paypal';
$scenarios['register'][] = 'paypal';
return $scenarios;
}
public function rules()
{
$rules = parent::rules();
$rules['paypalLength'] = ['paypal', 'string', 'max' => 255];
return $rules;
}
}
Override SettingsForm model
<?php
namespace common\models;
class SettingsForm extends \dektrium\user\models\SettingsForm
{
public $paypal;
public function rules()
{
$rules = parent::rules();
$rules['paypalLength'] = ['paypal', 'string', 'max' => 255];
return $rules;
}
}
Configure module
'user' => [
'class' => 'dektrium\user\Module',
'modelMap' => [
'User' => 'common\models\User',
'RegistrationForm' => 'common\models\RegistrationForm',
'SettingsForm' => 'common\models\SettingsForm',
],
'controllerMap' => [
...
And I have overridden account form view. When I'm trying to change paypal field in user/settings/account it doesn't change it. What should I do to make it work?
Thanks.
Also you must override view paths:
'view' => [
'theme' => [
'pathMap' => [
'#dektrium/user/views' => '#app/views/user',
],
],
],
And after that open #vendor/dektrium/yii2-user/views and make a folder on #app/views based on dektrium view folders. For example create a folder named admin (because you have on #vendor/dektrium/yii2-user/views a folder named admin) and create corresponded folder on app views, i.e. #app/views/admin.
After that create your view file that you want to change on #app/views/[dektrium-folder] and change it.

yii2 disable the rules if a checkbox is selected

In the active form, I have 3 textinput and one checkbox.
All the 3 textinputs have rules that says cannot be empty. What I want is if the checkbox is clicked, It will disable the rules and will save the empty record in the database.
here is screen shot of the active form..
You could define the rules that way (using when):
public function rules()
{
return [
['cancelled', 'boolean'],
['checkNumber', 'required'],
['payee', 'required', 'when' => function ($model) {return !$model->cancelled;}],
['particulars', 'required', 'when' => function ($model) {return !$model->cancelled;}],
];
}
You may want to add whenClient as well to let the browser check this before it submits the form.
You can do something like this:
$model = new SomeForm();
if ($model->load(Yii::$app->request->post())){
if ($model->checkbox == true) $model->scenario = 'checked';
}
// your model rules:
[['name', 'email', 'subject', 'body'], 'safe', 'on' => 'checked']
or alternatively You can do this:
if ($model->checkbox == true) $model->save(false); //this will disable any validation so be carefull
edit:
if You need cliend side validation switch, You have to use this:
[['name', 'email', 'subject', 'body'], 'required', 'when' => function ($model) {
return $model->cancelled == '0';
}, 'whenClient' => new JsExpression("function (attribute, value) { return $('#mailform-cancelled').val() == '0';}")]

Yii2 validation rule specific to a scenarios

I have the following rules and scenarios
public function rules(){
return [
[['name','email','password'],'required'],
['email','myvalidation'],
['email','email'],
[['name', 'email', 'password'], 'required', 'on' => 'register'],
];
}
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['login'] = ['name','password','email'];//Scenario Values Only Accepted
return $scenarios;
}
I want the rule 'myvalidation' applied only to the login scenario and not at all in other cases.How this can be achieved in Yii2 ?
Remember you can also use "except". In example:
public function rules()
{
return [
[['first_name', 'email', 'phone', 'password'], 'required', 'except' => 'changepassword'],
[['password'], 'required', 'on' => 'changepassword']
]}
Just specify on property in this validation rule:
['email', 'myvalidation', 'on' => 'login'],