YII2 - How to put conditional validation for dynamic form fild? - php

How to put conditional validation in to dynamic form this is the model file and address1 is the dynamic fileds
/**
* #inheritdoc
*/
public function rules()
{
return [
[['client_id'], 'integer'],
[['client_type', 'address1', 'address_type', 'address2', 'forn_address1', 'forn_address2', 'is_deleted', 'state', 'city', 'forn_city', 'forn_country', 'zip', 'forn_zip'], 'string'],
[['added_on', 'updated_on'], 'safe'],
[['zip','forn_zip'], 'match' ,'pattern'=> '/^[0-9]*$/' ,'message'=> 'Zip code must be numeric.'],
[['address1', 'state', 'city', 'zip'], 'required',
'when' => function ($model) {
return $model->address_type == "domestic_address";
},
'whenClient' => "function (attribute, value) { console.log($('div.address_type label input[type=radio]:checked').val());
return $('div.address_type label input[type=radio]:checked').val() == 'domestic_address';}"],
[['forn_address1', 'forn_city', 'forn_zip', 'forn_country'], 'required', 'when' => function ($model) { return $model->address_type == "foreign_address"; }, 'whenClient' => "function (attribute, value) { console.log($('div.address_type label input[type=radio]:checked').val());
return $('div.address_type label input[type=radio]:checked').val() == 'foreign_address';}"]
];
}
How to put conditional validation in to dynamic form ?

Use a Standalone Validator.
/**
* #inheritdoc
*/
public function rules()
{
return [
['address', 'validateAddress']
]
}
/**
* Check your address.
*/
public function validateAddress($attribute, $params, $validator)
{
//
// You can access other model fields like so:
// $this->address_type or $this->address or $this->other_field
/* Add your conditions as you see fit.*/
if (strtolower($this->address_type) = 'domestic_address')) {
$this->addError($attribute, 'Address TYPE is too domestic');
}
// or for example
if (strtolower($this->address) = '123 Road-ABC')) {
$this->addError($attribute, 'Address is goofy');
}
}

Related

Yii2 how to handle required field one of two for two different models

I have two forms to validate for phone number and email where input fields I am generating with \kidzen\dynamicform\DynamicFormWidget
Phone number form rules:
<?php
namespace common\models\form;
class Telephone extends someExtend
{
/**
* #inheritdoc
*/
public function rules()
{
return [
['value', 'trim'],
[['value'], 'required'],
[['value'], 'string', 'max' => 26],
[['value'], 'match', 'pattern' => "/^\\+?\\d{1,4}?[-.\\s]?\\(?\\d{1,3}?\\)?[-.\\s]?\\d{1,4}[-.\\s]?\\d{1,4}[-.\\s]?\\d{1,9}$/" ,
'message' => \Yii::t('models', 'Invalid Phone Number Format')]
];
}
}
Email rules:
<?php
namespace common\models\form;
class Email extends someExtend
{
/**
* #inheritdoc
*/
public function rules()
{
return [
['value', 'trim'],
[['value'], 'required'],
[['value'], 'string', 'max' => 512],
[['value'], 'match', 'pattern' => "/^[a-z0-9!#$%&'*+\\/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+\\/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/",
'message' => \Yii::t('models', 'Invalid Email Format')]
];
}
}
they are a part of bigger form
<?php
namespace common\models\form;
/* some uses */
/**
* #property Email[] $sender_email
* #property Telephone[] $sender_telephone
*/
class UpdateContentsForm extends Model
{
public array $sender_email = [];
public array $sender_telephone = [];
public function __construct($config = [])
{
parent::__construct($config);
}
public function attributeLabels()
{
return [
'sender_telephone' => Yii::t('models', 'Sender Telephone'),
'sender_email' => Yii::t('models', 'Sender Email'),
];
}
public function rules()
{
return [
// Rules for other fields in this form model
];
}
On submit I call UpdateContentsForm. How can I validate that one of those two is required if in UpdateContentsForm they both are arrays from 1 - 3 elements?
If you need some more information, please feel free to ask and I will modify information shortly.
You must use 'when' property of the validator
public function rules()
{
return [
...,
[['value'], 'required', 'when' => function($model) {
// make the validation
if ($isValid) {
return true; // run the required validation
}
return false; // dont run the required validation
}],
];
}

Yii2: Access model value in view

I have a variable status declared in model. Status is a column in gridview that is populated using this:
[
'attribute' => 'status',
'contentOptions' => ['class' => 'text-center'],
'value' => function($model){
if($model->nginSum != $model->sapValue){
return 'NOK';
} else {
return 'OK';
}
},
],
I want to count the number os OKs and NOKs to display equal and diferent entries with a counter.
I've tried declaring a function in search model:
public function getStatus()
{
return $this->status;
}
and in view i did this:
$equal = 0;
$different = 0;
$stat = new EtuLojaSearch;
if ($stat->getStatus() == 'OK') {
$equal += 1;
} else {
$different += 1;
}
but it's returning null.
What am i doing wrong?
Edited:
function in model:
public function getStatus()
{
if($this->nginSum != $this->sapValue){
return 'NOK';
} else {
return 'OK';
}
}
In view:
$iguais = 0;
$diferentes = 0;
$stat = new EtuLojaSearch;
if ($stat->status == 'OK') {
$iguais += 1;
} else {
$diferentes += 1;
}
Edit 2:
Status is ot getting bound to model using getStatus() function.
Model
class EtuLoja extends \yii\db\ActiveRecord
{
public $nginSum;
public $sapValue;
public $status;
public $Data_Sap;
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'etu_loja';
}
public function getStatus()
{
if($this->nginSum != $this->sapValue){
return 'NOK';
} else {
return 'OK';
}
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['id_master', 'nginSum', 'sapValue'], 'integer'],
[['user'], 'required'],
[['user', 'status'], 'string', 'max' => 100],
[['Atendedora', 'Loja', 'Obs'], 'string', 'max' => 255],
[['id_master'], 'exist', 'skipOnError' => true, 'targetClass' => MasterLoja::className(), 'targetAttribute' => ['id_master' => 'id']],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'ID' => 'ETU(Slave)',
'id_master' => 'Master',
'master.regiao' => 'Master/RegiĆ£o',
'user' => 'User',
'Atendedora' => 'Atendedora',
'Loja' => 'Loja',
'Obs' => 'Obs',
'nginValue' => 'Valor Ngin',
'status' => 'Estado',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getMaster()
{
return $this->hasOne(MasterLoja::className(), ['id' => 'id_master']);
}
public function getNginAgentDetail()
{
return $this->hasMany(NginAgentDetail::className(),['CLIENT_ID' => 'ID']);
}
public function getSap()
{
return $this->hasMany(Sap::className(),['Criado_por' => 'user']);
}
}
Search Model:
class EtuLojaSearch extends EtuLoja
{
public $regiao;
public $nginValue;
public $sapValue;
public $operationDate;
public $from_date;
public $to_date;
public $Data_Sap;
public function rules()
{
return [
[['ID'], 'integer'],
[['Atendedora', 'Loja', 'Obs', 'id_master', 'regiao', 'user', 'nginValue', 'sapValue', 'operationDate', 'status', 'from_date', 'to_date', 'Data_Sap'], 'safe'],
];
}
/**
* {#inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = EtuLoja::find();
// add conditions that should always apply here
$query->joinWith('master');
// $query->joinWith('nginAgentDetail');
// $query->joinWith('sap');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['Data_Sap'] = [
'asc' => ['Data_Sap' => SORT_ASC],
'desc' => ['Data_Sap' => SORT_DESC],
];
$dataProvider->sort->attributes['regiao'] = [
// The tables are the ones our relation are configured to
// in my case they are prefixed with "tbl_"
'asc' => ['master_loja.regiao' => SORT_ASC],
'desc' => ['master_loja.regiao' => SORT_DESC],
];
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'etu_loja.ID' => $this->ID,
// 'id_master' => $this->id_master,
]);
$query->andFilterWhere(['like', 'Atendedora', $this->Atendedora])
->andFilterWhere(['like', 'Loja', $this->Loja])
->andFilterWhere(['like', 'Obs', $this->Obs])
->andFilterWhere(['like', 'user', $this->user]);
if ($this->status === 'OK') {
$query->andWhere('nginSum = sapValue');
} elseif ($this->status === 'NOK') {
$query->andWhere('nginSum <> sapValue');
}
if(" " !== $this->operationDate) {
$query->andFilterWhere(['master_loja.regiao'=>$this->regiao]);
}
return $dataProvider;
}
}
Update your getStatus method with following.
public function getStatus()
{
if($this->nginSum != $this->sapValue){
return 'NOK';
} else {
return 'OK';
}
}
It will bind value (OK, NOK) with status attribute when active record is fetched and later on you can use that value in whatever way you wish eg $model->status. With this approach, your attribute rendering code will be like following.
[
'attribute' => 'status',
'contentOptions' => ['class' => 'text-center'],
'value' => function($model){
return $model->status;
},
],
But to count different values for status, you'll have to loop through all models i-e
$equal = 0;
$different = 0;
foreach($dataProvider->getModels() as $item){
if ($item->status == 'OK') {
$equal += 1;
} else {
$different += 1;
}
}

Yii2: Either one field is required Validation

I have to implement the validation as mentioned in the title that either one of the two fields (email, phone) is required. I am doing this in my model:
[['email'],'either', ['other' => ['phone']]],
And this is the method:
public function either($attribute_name, $params) {
$field1 = $this->getAttributeLabel($attribute_name);
$field2 = $this->getAttributeLabel($params['other']);
if (empty($this->$attribute_name) && empty($this->$params['other'])) {
$this->addError($attribute_name, Yii::t('user', "either {$field1} or {$field2} is required."));
return false;
}
return true;
}
When I access my index page, it gives me this error:
Exception (Unknown Property) 'yii\base\UnknownPropertyException' with
message 'Setting unknown property: yii\validators\InlineValidator::0'
Any help?
If you don't care that both fields show an error when the user provides neither of both fields:
This solutions is shorter than the other answers and does not require a new validator type/class:
$rules = [
['email', 'required', 'when' => function($model) { return empty($model->phone); }],
['phone', 'required', 'when' => function($model) { return empty($model->email); }],
];
If you want to have a customized error message, just set the message option:
$rules = [
[
'email', 'required',
'message' => 'Either email or phone is required.',
'when' => function($model) { return empty($model->phone); }
],
[
'phone', 'required',
'message' => 'Either email or phone is required.',
'when' => function($model) { return empty($model->email); }
],
];
The rule should be:
['email', 'either', 'params' => ['other' => 'phone']],
And method:
public function either($attribute_name, $params)
{
$field1 = $this->getAttributeLabel($attribute_name);
$field2 = $this->getAttributeLabel($params['other']);
if (empty($this->$attribute_name) && empty($this->{$params['other']})) {
$this->addError($attribute_name, Yii::t('user', "either {$field1} or {$field2} is required."));
}
}
Improved variant
['gipsy_team_name', 'either', 'skipOnEmpty'=>false, 'params' => ['other' => 'poker_strategy_nick_name']],
['vkontakte', 'either', 'skipOnEmpty'=>false, 'params' => ['other' => ['odnoklasniki','odnoklasniki']]],
Added 'skipOnEmpty'=>false for forcing validating and 'other' can be array
/**
* validation rule
* #param string $attribute_name
* #param array $params
*/
public function either($attribute_name, $params)
{
/**
* validate actula attribute
*/
if(!empty($this->$attribute_name)){
return;
}
if(!is_array($params['other'])){
$params['other'] = [$params['other']];
}
/**
* validate other attributes
*/
foreach($params['other'] as $field){
if(!empty($this->$field)){
return;
}
}
/**
* get attributes labels
*/
$fieldsLabels = [$this->getAttributeLabel($attribute_name)];
foreach($params['other'] as $field){
$fieldsLabels[] = $this->getAttributeLabel($field);
}
$this->addError($attribute_name, \Yii::t('poker_reg', 'One of fields "{fieldList}" is required.',[
'fieldList' => implode('"", "', $fieldsLabels),
]));
}

How to manage password during update user profile in Yii2

I can add user successfully, For Password hashing I am using md5() But when I update user it is giving an error.
Here are the model rules:
public function rules()
{
return [
[['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status'], 'required'],
['email','email'],
[['confirm'], 'compare', 'compareAttribute' => 'password','on'=>'create'],
[['firstname', 'lastname', 'username', 'email', 'password', 'confirm', ], 'string', 'max' => 255],
];
}
In the form i.e. View, I am using following code:
<div class="form-group">
<?php
if($case == 'create') { //this condition called when create user
echo $form->field($model, 'password')->passwordInput([
'maxlength' => true,
'placeholder' => 'Enter the Password',
]);
}
else { // during update
echo $form->field($model, 'password')->passwordInput([
'maxlength' => true,
'placeholder' => 'Enter the Password',
'value' => '',
]);
}
?>
</div>
<div class="form-group">
<?= $form->field($model, 'confirm')->passwordInput([
'maxlength' => true,
'placeholder' => 'Confirm Password',
]) ?>
</div>
and in controller I am using following code:
public function actionUpdate($id)
{
$model = $this->findModel($id);
$case = "update";
if ($model->load(Yii::$app->request->post())) {
$model->save();
return $this->redirect(['view', 'id' => $model->id]);
}
else {
return $this->render('update', [
'model' => $model,
'all_users_array' => $all_users_array,
'all_groups_array' => $all_groups_array,
'case' => $case,
]);
}
}
I am getting the error:
Undefined offset: 1 Failed to prepare SQL: UPDATE xbox_user SET
password=:qp0, role=:qp1, modified=:qp2, status=:qp3 WHERE
id=:qp4
Can anyone please let me what code should be modified there?
Thank you!
It is better to use scenarios in your case and use rules() too for other requirements, In Users.php model file write the following code:
public function scenarios(){
$scenarios = parent::scenarios();
$scenarios['create'] = ['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status', 'password','confirm'];
$scenarios['update'] = ['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status'];
return $scenarios;
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status', 'password','confirm'], 'required'],
['email', 'filter', 'filter' => 'trim'],
['email', 'unique' ],
['email', 'unique' ,'targetAttribute' => 'email'],
['email', 'required'],
['email', 'email'],
['email', 'unique', 'targetClass' => '\common\models\Users', 'message' => 'This email address has already been taken.'],
['confirm', 'compare', 'compareAttribute'=>'password', 'message'=>"Passwords does not match." ],
[['firstname', 'lastname', 'username', 'email', 'password', 'confirm', ], 'string', 'max' => 255],
];
}
In your views file use the following code:
<div class="form-group">
<?php
if($case == 'create'){
echo $form->field($model, 'password')->passwordInput(['maxlength' => true,'placeholder'=>'Enter the Password']);
}
else{
echo $form->field($model, 'password')->passwordInput(['maxlength' => true,'placeholder'=>'Enter the Password']);
}
?>
</div>
<div class="form-group">
<?= $form->field($model, 'confirm')->passwordInput(['maxlength' =>true,'placeholder'=>'Confirm Password']) ?>
</div>
and in your controller file, UsersController.php use the following code:
public function actionUpdate($id)
{
$model = $this->findModel($id);
$model->scenario = 'update'; // calling scenario of update
if ($model->load(Yii::$app->request->post())) {
$req_array = yii::$app->request->post();
$role = $req_array['Users']['role'][0];
$model->role = $role;
if($req_array['Users']['password'] !== $req_array['Users']['confirm'])
{
$model->addError('confirm','Password and Confirm should be same.');
$model->password = $req_array['Users']['password'];
$model->confirm = $req_array['Users']['confirm'];
return $this->render('update', [
'model' => $model,
'all_users_array'=>$all_users_array,
'all_groups_array'=>$all_groups_array,
'case'=>$case,
]);
}
elseif( ($req_array['Users']['password'] == $req_array['Users']['confirm']) && (!empty($req_array['Users']['password'])))
{
$model->password = MD5($req_array['Users']['password']);
$model->save();
return $this->redirect(['view', 'id' => $model->id]);
}
else
{
$model->save();
return $this->redirect(['view', 'id' => $model->id]);
}
} else {
$model->password = '';
return $this->render('update', [
'model' => $model,
'all_users_array'=>$all_users_array,
'all_groups_array'=>$all_groups_array,
'case'=>$case,
]);
}
}
Using this code, you will not get error of required password in update, In case if you fill the password then process of confirm password and required will be run.
Hope this helps for you.
User Model
public function rules()
{
return [
[['firstname', 'lastname', 'username', 'email', 'role', 'group_user','status'], 'required'],
['email','email'],
[['password', 'confirm'], 'required', 'on' => 'create'],
['confirm', 'compare', 'compareAttribute' => 'password', 'message'=>"Passwords does not match." ],
[['firstname', 'lastname', 'username', 'email', 'password', 'confirm', ], 'string', 'max' => 255],
];
}
Update Action
public function actionUpdate($id)
{
$model = $this->findModel($id);
$model->passowrd = '';
$model->confirm = '';
if ($model->load(Yii::$app->request->post())) {
$model->role = $model->role[0];
if (empty($model->password) || empty($model->confirm)) {
$model->password = $model->getOldAttribute('password');
$model->confirm = $model->getOldAttribute('confirm');
}
if ($model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
} else {
return $this->render('update', [
'model' => $model,
'all_users_array'=>$all_users_array,
'all_groups_array'=>$all_groups_array,
]);
}
}
Form
<div class="form-group">
<?= $form->field($model, 'password')->passwordInput(['maxlength' => true,'placeholder'=>'Enter the Password']) ?>
</div>
<div class="form-group">
<?= $form->field($model, 'confirm')->passwordInput(['maxlength' => true,'placeholder'=>'Confirm Password']) ?>
</div>
First try this one
[['confirm'], 'compare', 'compareAttribute' => 'password','on'=>'create']
if not work then please follow the following steps create your scenario for updation and don't compare password
Did you try scenarios.. i will give a simple example for user registration and user login i hope it will help you
<?php
class User extends Model
{
public $name;
public $email;
public $password;
public function rules(){
return [
[['name','email','password'],'required'],
['email','email'],
[['name', 'email', 'password'], 'required', 'on' => 'register'],
];
}
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['login'] = ['name','password'];//Scenario Values Only Accepted
return $scenarios;
}
}
?>
Apply Scenario For Model
See the below code, We added two ways of setting the scenario of a model. By default, scenario will support the model rules.
<?php
class UserController extends Controller
{
// APPLY SCENARIOS
// scenario is set as a property
public function actionLogin(){
$model = new User;
$model->scenario = 'login';
}
// scenario is set through configuration
public function actionRegister(){
$model = new User(['scenario' => 'register']);
}
}
?>
I have my own basic User model i reuse for most projects, which handles updating new password or leaving the previous one if no password is provided by the update form. Also implements IdentityInterface so it can be used for login to the Application.
My basic User model:
<?php
namespace app\models;
use Yii;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface {
const SCENARIO_LOGIN = 'login';
const SCENARIO_CREATE = 'create';
const SCENARIO_UPDATE = 'update';
// We use $hash to save the hashed password we already have saved in the DB
public $hash;
public $password_repeat;
/**
* #inheritdoc
*/
public static function tableName() {
return 'user';
}
/**
* #inheritdoc
*/
public function scenarios() {
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_LOGIN] = ['user', 'password'];
$scenarios[self::SCENARIO_CREATE] = ['user', 'password', 'password_repeat', 'email', 'authKey'];
$scenarios[self::SCENARIO_UPDATE] = ['user', 'password', 'password_repeat', 'email'];
return $scenarios;
}
/**
* #inheritdoc
*/
public function rules() {
return [
[['user'], 'string', 'max' => 45],
[['email'], 'string', 'max' => 45],
[['email'], 'email'],
[['password', 'password_repeat'], 'string', 'max' => 60],
[['authKey'], 'string', 'max' => 32],
[['user', 'password'], 'required', 'on' => self::SCENARIO_LOGIN],
[['user', 'password', 'password_repeat', 'email'], 'required', 'on' => self::SCENARIO_CREATE],
[['user', 'email'], 'required', 'on' => self::SCENARIO_UPDATE],
// Generate a random String with 32 characters to use as AuthKey
[['authKey'], 'default', 'on' => self::SCENARIO_CREATE, 'value' => Yii::$app->getSecurity()->generateRandomString()],
[['password'], 'compare', 'on' => self::SCENARIO_CREATE, 'skipOnEmpty' => true],
[['user'], 'unique'],
];
}
/**
* #inheritdoc
*/
public function attributeLabels() {
return [
'id' => 'Id',
'user' => 'User',
'password' => 'Password',
'authKey' => 'AuthKey',
'email' => 'Email',
];
}
/**
* #inheritdoc
*/
public function beforeSave($insert) {
if (parent::beforeSave($insert)) {
if($insert) {
$this->password = Yii::$app->getSecurity()->generatePasswordHash($this->password);
}
else {
if(strlen($this->password) > 0) {
$this->password = Yii::$app->getSecurity()->generatePasswordHash($this->password);
}
else {
$this->password = $this->hash;
}
}
return true;
}
return false;
}
/**
* #inheritdoc
*/
public function afterFind() {
$this->hash = $this->password;
$this->password = '';
parent::afterFind();
}
/**
* #inheritdoc
*/
public static function findIdentity($id) {
return self::findOne($id);
}
/**
* #inheritdoc
*/
public static function findIdentityByAccessToken($token, $type = null) {
throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
}
/**
* #inheritdoc
*/
public static function findByUsername($username) {
$model = static::findOne(['user' => $username]);
return $model;
}
/**
* #inheritdoc
*/
public function getId() {
return $this->getPrimaryKey();
}
/**
* #inheritdoc
*/
public function getAuthKey() {
return $this->authKey;
}
/**
* #inheritdoc
*/
public function validateAuthKey($authKey) {
return $this->authKey === $authKey;
}
/**
* Validates password
*
* #param string $password password to validate
* #return boolean if password provided is valid for current user
*/
public function validatePassword($password) {
return Yii::$app->getSecurity()->validatePassword($password, $this->hash);
}
}
This way you only need to use the corresponding scenario in your create, update and login actions:
$model->scenario = User::SCENARIO_LOGIN;
$model->scenario = User::SCENARIO_CREATE;
$model->scenario = User::SCENARIO_UPDATE;

Yii2 Login with database

I have a table in my DB called 'member' where I intend to store username, password and all other related info of a user and I want to use those username/password for login instead yii2's default User.php model. I have been trying for almost a day and modified the Member.php model but can't make it work. Every time I use my custom username/password from db, it says username or password is incorrect.
Can anyone please help me out? Thanks in advance. :)
FYI, I have no such field in member table such as authKey or accessToken. I have tried all the related stackoverflow posts but in vein.
Member.php Model
namespace app\models;
use Yii;
use yii\web\IdentityInterface;
class Member extends \yii\db\ActiveRecord implements IdentityInterface
{
public static function tableName()
{
return 'member';
}
public function rules()
{
return [
[['username', 'password', 'first_name', 'last_name', 'role'], 'required'],
[['created_by_date', 'last_modified_by_date'], 'safe'],
[['username', 'password', 'role', 'created_by_id', 'last_modified_by_id'], 'string', 'max' => 50],
[['first_name', 'last_name', 'middle_name', 'phone', 'mobile'], 'string', 'max' => 100],
[['email'], 'string', 'max' => 250],
[['address_line1', 'address_line2', 'address_line3'], 'string', 'max' => 512]
];
}
public function attributeLabels()
{
return [
'id' => 'ID',
'username' => 'Username',
'password' => 'Password',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'middle_name' => 'Middle Name',
'email' => 'Email',
'phone' => 'Phone',
'mobile' => 'Mobile',
'address_line1' => 'Address Line1',
'address_line2' => 'Address Line2',
'address_line3' => 'Address Line3',
'role' => 'Role',
'created_by_id' => 'Created By ID',
'created_by_date' => 'Created By Date',
'last_modified_by_id' => 'Last Modified By ID',
'last_modified_by_date' => 'Last Modified By Date',
];
}
public static function find()
{
return new MemberQuery(get_called_class());
}
public static function findIdentity($id)
{
$dbUser = self::find()
->where([
"id" => $id
])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
public static function findIdentityByAccessToken($token, $userType = null)
{
$dbUser = self::find()
->where(["accessToken" => $token])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
public static function findByUsername($username)
{
$dbUser = self::find()
->where(["username" => $username])
->one();
if (!count($dbUser)) {
return null;
}
return $dbUser;
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->authKey;
}
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
/**
* Validates password
*
* #param string $password password to validate
* #return boolean if password provided is valid for current user
*/
public function validatePassword($password)
{
return $this->password === $password;
}
}
config/web.php
'user' => [
'identityClass' => 'app\models\Member',
'enableAutoLogin' => true,
],
I didnt change the User.php model. Here it is:
namespace app\models;
class User extends \yii\base\Object implements \yii\web\IdentityInterface
{
private static $users = [
'100' => [
'id' => '100',
'username' => 'admin',
'password' => 'admin',
'authKey' => 'test100key',
'accessToken' => '100-token',
],
'101' => [
'id' => '101',
'username' => 'demo',
'password' => 'demo',
'authKey' => 'test101key',
'accessToken' => '101-token',
],
];
/**
* #inheritdoc
*/
public static function findIdentity($id)
{
return isset(self::$users[$id]) ? new static(self::$users[$id]) : null;
}
/**
* #inheritdoc
*/
public static function findIdentityByAccessToken($token, $type = null)
{
foreach (self::$users as $user) {
if ($user['accessToken'] === $token) {
return new static($user);
}
}
return null;
}
/**
* Finds user by username
*
* #param string $username
* #return static|null
*/
public static function findByUsername($username)
{
foreach (self::$users as $user) {
if (strcasecmp($user['username'], $username) === 0) {
return new static($user);
}
}
return null;
}
/**
* #inheritdoc
*/
public function getId()
{
return $this->id;
}
/**
* #inheritdoc
*/
public function getAuthKey()
{
return $this->authKey;
}
/**
* #inheritdoc
*/
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
/**
* Validates password
*
* #param string $password password to validate
* #return boolean if password provided is valid for current user
*/
public function validatePassword($password)
{
return $this->password === $password;
}
}
You should make sure you change the getUser() method on models/LoginForm.php to use your Member model class, otherwise it will keep validating against the default User model.
public function getUser() {
if ($this->_user === false) {
$this->_user = Member::findByUsername($this->username);
}
return $this->_user;
}
Also, here is an example of my own User model class
namespace app\models;
use Yii;
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface {
const SCENARIO_LOGIN = 'login';
const SCENARIO_CREATE = 'create';
public static function tableName() {
return 'user';
}
public function scenarios() {
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_LOGIN] = ['username', 'password'];
$scenarios[self::SCENARIO_CREATE] = ['username', 'password', 'authKey'];
return $scenarios;
}
public function rules() {
return [
[['username', 'email'], 'string', 'max' => 45],
[['email'], 'email'],
[['password'], 'string', 'max' => 60],
[['authKey'], 'string', 'max' => 32],
[['username', 'password', 'email'], 'required', 'on' => self::SCENARIO_CREATE],
[['authKey'], 'default', 'on' => self::SCENARIO_CREATE, 'value' => Yii::$app->getSecurity()->generateRandomString()],
[['password'], 'filter', 'on' => self::SCENARIO_CREATE, 'filter' => function($value) {
return Yii::$app->getSecurity()->generatePasswordHash($value);
}],
[['username', 'password'], 'required', 'on' => self::SCENARIO_LOGIN],
[['username'], 'unique'],
[['email'], 'unique'],
[['authKey'], 'unique'],
];
}
public function attributeLabels() {
return [
'id' => 'Id',
'username' => 'Username',
'password' => 'Password',
'email' => 'Email',
'authKey' => 'authKey',
];
}
public static function findIdentity($id) {
return self::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null) {
throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
}
public static function findByUsername($username) {
return static::findOne(['username' => $username]);
}
public function getId() {
return $this->getPrimaryKey();
}
public function getAuthKey() {
return $this->authKey;
}
public function validateAuthKey($authKey) {
return $this->authKey === $authKey;
}
public function validatePassword($password) {
return Yii::$app->getSecurity()->validatePassword($password, $this->password);
}
}
Make sure the methods from IdentityInterface you implement but don't want to use throw an exception, just like i do on the findIdentityByAccessToken method.
You should extend User class with your Member class and set in main config:
[...]
'modules' => [
'user' => [
'class' => 'member class
'modelMap' => [
'User' => 'app\models\member',
More info: yii 2 : override user model

Categories