Related
Previously, I was not using $model->save() function for inserting or updating any data. I was simply using createCommand() to execute query and it was working successfully. But, my team members asked me to avoid createCommand() and use $model->save();
Now, I started cleaning my code and problem is $model->save(); not working for me. I don't know where i did mistake.
UsersController.php (Controller)
<?php
namespace app\modules\users\controllers;
use Yii;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\swiftmailer\Mailer;
use yii\filters\AccessControl;
use yii\web\Response;
use yii\widgets\ActiveForm;
use app\modules\users\models\Users;
use app\controllers\CommonController;
class UsersController extends CommonController
{
.
.
public function actionRegister() {
$model = new Users();
// For Ajax Email Exist Validation
if(Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())){
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
else if ($model->load(Yii::$app->request->post())) {
$post = Yii::$app->request->post('Users');
$CheckExistingUser = $model->findOne(['email' => $post['email']]);
// Ok. Email Doesn't Exist
if(!$CheckExistingUser) {
$auth_key = $model->getConfirmationLink();
$password = md5($post['password']);
$registration_ip = Yii::$app->getRequest()->getUserIP();
$created_at = date('Y-m-d h:i:s');
$model->auth_key = $auth_key;
$model->password = $password;
$model->registration_ip = $registration_ip;
$model->created_at = $created_at;
if($model->save()) {
print_r("asd");
}
}
}
}
.
.
}
Everything OK in this except $model->save(); Not printing 'asd' as i echoed it.
And, if i write
else if ($model->load(Yii::$app->request->post() && $model->validate()) {
}
It's not entering to this if condition.
And, if i write
if($model->save(false)) {
print_r("asd");
}
It insert NULL to all columns and print 'asd'
Users.php (model)
<?php
namespace app\modules\users\models;
use Yii;
use yii\base\Model;
use yii\db\ActiveRecord;
use yii\helpers\Security;
use yii\web\IdentityInterface;
use app\modules\users\models\UserType;
class Users extends ActiveRecord implements IdentityInterface
{
public $id;
public $first_name;
public $last_name;
public $email;
public $password;
public $rememberMe;
public $confirm_password;
public $user_type;
public $company_name;
public $status;
public $auth_key;
public $confirmed_at;
public $registration_ip;
public $verify_code;
public $created_at;
public $updated_at;
public $_user = false;
public static function tableName() {
return 'users';
}
public function rules() {
return [
//First Name
'FirstNameLength' => ['first_name', 'string', 'min' => 3, 'max' => 255],
'FirstNameTrim' => ['first_name', 'filter', 'filter' => 'trim'],
'FirstNameRequired' => ['first_name', 'required'],
//Last Name
'LastNameLength' => ['last_name', 'string', 'min' => 3, 'max' => 255],
'LastNameTrim' => ['last_name', 'filter', 'filter' => 'trim'],
'LastNameRequired' => ['last_name', 'required'],
//Email ID
'emailTrim' => ['email', 'filter', 'filter' => 'trim'],
'emailRequired' => ['email', 'required'],
'emailPattern' => ['email', 'email'],
'emailUnique' => ['email', 'unique', 'message' => 'Email already exists!'],
//Password
'passwordRequired' => ['password', 'required'],
'passwordLength' => ['password', 'string', 'min' => 6],
//Confirm Password
'ConfirmPasswordRequired' => ['confirm_password', 'required'],
'ConfirmPasswordLength' => ['confirm_password', 'string', 'min' => 6],
['confirm_password', 'compare', 'compareAttribute' => 'password'],
//Admin Type
['user_type', 'required'],
//company_name
['company_name', 'required', 'when' => function($model) {
return ($model->user_type == 2 ? true : false);
}, 'whenClient' => "function (attribute, value) {
return $('input[type=\"radio\"][name=\"Users[user_type]\"]:checked').val() == 2;
}"], #'enableClientValidation' => false
//Captcha
['verify_code', 'captcha'],
[['auth_key','registration_ip','created_at'],'safe']
];
}
public function attributeLabels() {
return [
'id' => 'ID',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'email' => 'Email',
'password' => 'Password',
'user_type' => 'User Type',
'company_name' => 'Company Name',
'status' => 'Status',
'auth_key' => 'Auth Key',
'confirmed_at' => 'Confirmed At',
'registration_ip' => 'Registration Ip',
'confirm_id' => 'Confirm ID',
'created_at' => 'Created At',
'updated_at' => 'Updated At',
'verify_code' => 'Verification Code',
];
}
//custom methods
public static function findIdentity($id) {
return static::findOne($id);
}
public static function instantiate($row) {
return new static($row);
}
public static function findIdentityByAccessToken($token, $type = null) {
throw new NotSupportedException('Method "' . __CLASS__ . '::' . __METHOD__ . '" is not implemented.');
}
public function getId() {
return $this->id;
}
public function getAuthKey() {
return $this->auth_key;
}
public function validateAuthKey($authKey) {
return $this->auth_key === $auth_key;
}
public function validatePassword($password) {
return $this->password === $password;
}
public function getFirstName() {
return $this->first_name;
}
public function getLastName() {
return $this->last_name;
}
public function getEmail() {
return $this->email;
}
public function getCompanyName() {
return $this->company_name;
}
public function getUserType() {
return $this->user_type;
}
public function getStatus() {
return $this->status;
}
public function getUserTypeValue() {
$UserType = $this->user_type;
$UserTypeValue = UserType::find()->select(['type'])->where(['id' => $UserType])->one();
return $UserTypeValue['type'];
}
public function getCreatedAtDate() {
$CreatedAtDate = $this->created_at;
$CreatedAtDate = date('d-m-Y h:i:s A', strtotime($CreatedAtDate));
return $CreatedAtDate;
}
public function getLastUpdatedDate() {
$UpdatedDate = $this->updated_at;
if ($UpdatedDate != 0) {
$UpdatedDate = date('d-m-Y h:i:s A', strtotime($UpdatedDate));
return $UpdatedDate;
} else {
return '';
}
}
public function register() {
if ($this->validate()) {
return true;
}
return false;
}
public static function findByEmailAndPassword($email, $password) {
$password = md5($password);
$model = Yii::$app->db->createCommand("SELECT * FROM users WHERE email ='{$email}' AND password='{$password}' AND status=1");
$users = $model->queryOne();
if (!empty($users)) {
return new Users($users);
} else {
return false;
}
}
public static function getConfirmationLink() {
$characters = 'abcedefghijklmnopqrstuvwxyzzyxwvutsrqponmlk';
$confirmLinkID = '';
for ($i = 0; $i < 10; $i++) {
$confirmLinkID .= $characters[rand(0, strlen($characters) - 1)];
}
return $confirmLinkID = md5($confirmLinkID);
}
}
Any help is appreciable. Please Help me.
It could be a problem related with your validation rules.
Try, as a test, to save the model without any validation in this way:
$model->save(false);
If the model is saved you have conflict with your validation rules. Try selectively removing your validation rule(s) to find the validation conflict.
If you have redefined the value present in active record you don't assign the value to the var for db but for this new var and then are not save.
Try removing the duplicated var.. (only the vars non mapped to db should be declared here.)
I guess $model->load() returns false, call $model->errors to see model's error.
$model->load();
$model->validate();
var_dump($model->errors);
Check model saving error like this :
if ($model->save()) {
} else {
echo "MODEL NOT SAVED";
print_r($model->getAttributes());
print_r($model->getErrors());
exit;
}
As #scaisEdge suggest, try removing all table related field in your Users class
class Users extends ActiveRecord implements IdentityInterface
{
/* removed because this properties is related in a table's field
public $first_name;
public $last_name;
public $email;
public $password;
public $user_type;
public $company_name;
public $status;
public $auth_key;
public $confirmed_at;
public $registration_ip;
public $verify_code;
public $created_at;
public $updated_at;
public $user_type;
public $company_name;
public $status;
public $auth_key;
public $confirmed_at;
public $registration_ip;
public $verify_code;
public $created_at;
public $updated_at;
*/
// this is properties that not related to users table
public $rememberMe;
public $confirm_password;
public $_user = false;
public static function tableName() {
return 'users';
}
/* ........... */
}
The other solution mentioned $model->save(false);. That is just a temporary workaround, and you should still find the actual reason why the save functionality is not working.
Here are additional steps to help diagnose the actual issue:
check that _form input field has the proper name, and
check that if you have added any dropdown functionality, then check whether it's working properly or not
And there maybe another reason of not saving model - you have property of your Users class and before saving from form its reset to NULL.
So, if you set $model->saveAttributes('favorite_book'=>$model->favorite_book), but at that time you declared in class Users public $favorite_book - you will get this field empty in DB.
You are doing all stuff correctly. I think you must add one line for confirm password validation
if(!$CheckExistingUser) {
$auth_key = $model->getConfirmationLink();
$password = md5($post['password']);
$registration_ip = Yii::$app->getRequest()->getUserIP();
$created_at = date('Y-m-d h:i:s');
$model->auth_key = $auth_key;
$model->password = $password;
$model->confirm_password= md5($post["confirm_password"]); /// add this line
$model->registration_ip = $registration_ip;
$model->created_at = $created_at;
And Also after this condition check model attributes and error like this :
if($model->save()) {
print_r("asd");
}else{
var_dump($model);exit;}
Try this:
$model->save(false);
and if thats working, check your model rules() and your form rules() if its
having the same rules. usually the cause is the required fields in your table.
if your column type in your table is "integer" and your data is "string" you may see tis error.You should check your data type and try again.
I suppose that your column type is integer, you should write the following code:
$model->created_at=time();//1499722038
$model->save();
but your column type is string, you should write the following code:
$model->created_at=date('d/m/Y');//11/07/2017
$model->save();
in your model i found First name , last name , email , password is required fields and in your controller you are updating or saving only
$model->auth_key = $auth_key;
$model->password = $password;
$model->confirm_password= md5($post["confirm_password"]); /// add this line
$model->registration_ip = $registration_ip;
$model->created_at = $created_at;
but first name and last name and email id are required so it will throw validation error , to check this error use
$model->load();
$model->validate();
var_dump($model->errors);
it will show you the error . correct that errors then model will get save.
you can solve that error using Scenario or
$model->saveAttributes('favorite_book'=>$model->favorite_book,'favorite_movie'=>$model->favorite_movie);
I hope it will help you.
in my site if email is registered in my database I would add a error
$this->addError('email' ,'This Email already registered');
but in Update form I do not want see this error
What is a simple way to solve my problem?
this is my users model:
<?php
/**
* This is the model class for table "users".
class Users extends CActiveRecord
{
// public $captcha;
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'users';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('username, email,password', 'required'),
array('roles_id', 'numerical', 'integerOnly'=>true),
array('username, password',
'length',
'max'=>255,
'min'=>4
),
array('email', 'comp_email'),
array('username', 'comp_username'),
array('DataCreated, LastUpdated', 'safe'),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, username, password, DataCreated, LastUpdated, roles_id', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'email'=>'Email',
'username' => 'Username',
'password' => 'Password',
'DataCreated' => 'Data Created',
'LastUpdated' => 'Last Updated',
'roles_id' => 'Roles',
);
}
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('username',$this->username,true);
$criteria->compare('password',$this->password,true);
$criteria->compare('DataCreated',$this->DataCreated,true);
$criteria->compare('LastUpdated',$this->LastUpdated,true);
$criteria->compare('roles_id',$this->roles_id);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Users the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function comp_username($attributes , $params)
{
$username = Yii::app()->db->createCommand()
->select('username')
->from('users')
->queryAll();
$y = (count($username));
for ($x=0;$x<$y;$x++)
{
$usernameE[$x] = $username[$x]['username'];
}
foreach ($usernameE as $u)
{
if($this->username == $u)
{
$this->addError('username' ,'This Username already registered');
break;
}
}
}
public function comp_email($attributes , $params)
{
$email = Yii::app()->db->createCommand()
->select('email')
->from('users')
->queryAll();
$y = (count($email));
for ($x=0;$x<$y;$x++)
{
$emailE[$x] = $email[$x]['email'];
}
foreach ($emailE as $u)
{
if($this->email == $u)
{
$this->addError('email' ,'This Email already registered');
break;
}
}
}
public function getUsernameEmail($id)
{
$emailUsername = Yii::app()->db->createCommand()
->select('*')
->from('users')
->where('id=:id', array(':id'=>$id))
->queryAll();
return $emailUsername;
}
}
and this is my action Update in my controller:
public function actionUpdate($id)
{
$model=$this->loadModel($id);
// Uncomment the following line if AJAX validation is needed
$this->performAjaxValidation($model);
if(isset($_POST['Users']))
{
$model->attributes=$_POST['Users'];
$id=$model->id;
$useremail = Users::model()->getUsernameEmail($id);
$useremailX= $useremail[0]['username'];
$model->username=$useremailX;
$useremailX= $useremail[0]['email'];
$model->email=$useremailX;
$model->password= crypt($model->password,'salt');
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('update',array(
'model'=>$model,
));
}
You can achieve this by applying specific scenarios to your rules.
The Yii WIKI topic on the subject is a good reference.
In your rules, you can specify which scenarios to apply the rule to.
array('email', 'unique','message'=>'Email already exists!', 'on'=>'insert')
Please note that Yii automatically injects specific scenarios, depending on how the object is created.
insert
update
search
You can specify your own custom scenario.
$model = Customer::model()->findByPK($customerID);
$model->scenario = 'purchase';
this is how to validate, you can set error message to be empty.
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
//First parameter is your field name of table which has email value
array('email', 'email','message'=>"The email isn't correct"),
array('email', 'unique','message'=>'Email already exists!'),
);
}
https://stackoverflow.com/a/12778419/1727357
or you can make your own validator:
public function uniqueEmail($attribute, $params)
{
// Set $emailExist variable true or false by using your custom query on checking in database table if email exist or not.
// You can user $this->{$attribute} to get attribute value.
$emailExist = true;
if($emailExist)
{
//do what your want
$this->addError('email','Email already exists');
}
}
User this validation method in rules:
array('email', 'uniqueEmail','message'=>'Email already exists!'),
I created 2 mysql views, and has generated from them 2 model.
MostPopularCoupon
class MostPopularCoupon extends CActiveRecord
{
public function tableName()
{
return 'most_popular_coupon';
}
public function rules()
{
return array(
array('coupon_id', 'required'),
array('coupon_id', 'numerical', 'integerOnly'=>true),
array('left_coupons', 'length', 'max'=>22),
array('stopped_at', 'safe'),
array('left_coupons, coupon_id, stopped_at', 'safe', 'on'=>'search'),
);
}
public function relations()
{
return array(
);
}
public function attributeLabels()
{
return array(
'left_coupons' => 'Left Coupons',
'coupon_id' => 'Coupon',
'stopped_at' => 'Stopped At',
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('left_coupons',$this->left_coupons,true);
$criteria->compare('coupon_id',$this->coupon_id);
$criteria->compare('stopped_at',$this->stopped_at,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
MostActiveCity
class MostActiveCity extends CActiveRecord
{
public function tableName()
{
return 'most_active_city';
}
public function rules()
{
return array(
array('mines', 'length', 'max'=>21),
array('city', 'length', 'max'=>255),
array('mines, city', 'safe', 'on'=>'search'),
);
}
public function relations()
{
return array();
}
public function attributeLabels()
{
return array(
'mines' => 'Mines',
'city' => 'City',
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('mines',$this->mines,true);
$criteria->compare('city',$this->city,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
But due to no experience, don't know how to use them correctly. I need to substitute company_id in the query to get the data of the company belongs to the current user...
Please relock at your design. You would be better off having model classes of City{} and Coupon{}, then have functions for example MostPopularCoupons inside the Coupon class. You could then call them as functions of the class. For example.
In your model
class Coupon extends CActiveRecord
{
// NOTE: This is important for your alias column.
public $couponCount;
public function tableName()
{
return 'coupon';
}
...
public function MostPopularCoupons()
{
$Criteria = new CDbCriteria();
$Criteria->select = ' count(*) as couponCount ';
$lstCoupons = Coupon::model()->findAll($Criteria);
return $lstCoupons;
}
}
Then, in your controller
$coupon_id = 10;
$model1 = Coupon::model()->findByPK((int)$coupon_id);
$lstCouponCount = Coupon::MostPopularCoupons();
I am creating login action in the yii framework, but I have an error and I cannot fix it. Here is the error:
Property "AdminIdentity.user_name" is not defined. `$record=Admin::model()->findByAttributes(array('username'=>$this->user_name));`
This is my login module:
login.php
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'login_form',
'enableAjaxValidation'=>false,
'enableClientValidation' => true));
?>
<div class="row">
<?php echo $form->labelEx($model,'username'); ?>
<?php echo $form->textField($model,'username',array('size'=>60,'maxlength'=>100)); ?>
<?php echo $form->error($model,'username'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'password'); ?>
<?php echo $form->passwordField($model,'password',array('size'=>60,'maxlength'=>100)); ?>
<?php echo $form->error($model,'password'); ?>
</div>
<div id="lower">
<?php echo $form->Checkbox($model,'rememberMe'); ?>
<?php echo $form->labelEx($model,'rememberMe'); ?>
<input type="submit" value="Login"/>
</div>
<?php $this->endWidget(); ?>
AdminController and actionLogin
class AdminController extends Controller
{
public function actionLogin()
{
$this->layout = 'login';
$model=new LoginForm;
if(isset($_POST['ajax']) && $_POST['ajax']==='login_form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
if($model->validate() && $model->login()){
$this->redirect('/ktbeauty/index.php/categories/index');
}
}
$this->render('login',array(
'model'=>$model,
));
}
}
LoginForm
class LoginForm extends CFormModel{
public $username;
public $password;
public $rememberMe;
private $_identity;
public function rules()
{
return array(
// username and password are required
array('username, password', 'required','message'=>'input username requirement'),
// rememberMe needs to be a boolean
array('rememberMe', 'boolean'),
// password needs to be authenticated
array('password', 'authenticate','required','message'=>'input password requirement'),
);
}
public function attributeLabels()
{
return array(
'username'=>'User Name',
'rememberMe'=>'Remember me next time',
'password'=>'Password',
);
}
public function authenticate($attribute,$params)
{
if(!$this->hasErrors())
{
$this->_identity=new AdminIdentity($this->username,$this->password);
if(!$this->_identity->authenticate())
$this->addError('password','Incorrect username or password.');
}
}
public function login()
{
if($this->_identity===null)
{
$this->_identity=new AdminIdentity($this->username,$this->password);
$this->_identity->authenticate();
}
if($this->_identity->errorCode===UserIdentity::ERROR_NONE)
{
$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
Yii::app()->admin->login($this->_identity,$duration);
return true;
}
else
return false;
}
}
AdminIdentity class:
class AdminIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$record=Admin::model()->findByAttributes(array('username'=>$this->user_name));
var_dump($record);exit;
if($record===null)
{
$this->_id='user Null';
$this->errorCode=self::ERROR_USERNAME_INVALID;
}
else if($record->password!==$this->password)
{
$this->_id=$this->user_name;
$this->errorCode=self::ERROR_PASSWORD_INVALID;
}
else if($record['user_active']!=='1')
{
$err = "You have been Inactive by Admin.";
$this->errorCode = $err;
}
else
{
$this->_id=$record['ad_id'];
$this->setState('user_name', $record['user_name']);
$this->errorCode=self::ERROR_NONE;
}
return !$this->errorCode;
}
public function getId()
{
return $this->_id;
}
}
Admin Model class:
class Admin extends CActiveRecord
{
public function tableName()
{
return 'admin';
}
public function rules()
{
return array(
array('user_status','length', 'max'=>1),
array('user_active','length', 'max'=>1),
array('user_name, password, email', 'length', 'max'=>100),
array('phone, cellphone, name', 'length', 'max'=>45),
array('ad_id, user_name, password, email, phone, cellphone, name, user_status, user_active', 'safe', 'on'=>'search'),
);
}
public function relations()
{
return array(
);
}
public function attributeLabels()
{
return array(
'ad_id' => 'Ad',
'user_name' => 'User Name',
'password' => 'Password',
'email' => 'Email',
'phone' => 'Phone',
'cellphone' => 'Cellphone',
'name' => 'Name',
'user_status' => 'User Status',
'user_active' => 'User Active',
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('ad_id',$this->ad_id);
$criteria->compare('user_name',$this->user_name,true);
$criteria->compare('password',$this->password,true);
$criteria->compare('email',$this->email,true);
$criteria->compare('phone',$this->phone,true);
$criteria->compare('cellphone',$this->cellphone,true);
$criteria->compare('name',$this->name,true);
$criteria->compare('user_status',$this->user_status);
$criteria->compare('user_active',$this->user_active);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
class AdminIdentity extends CUserIdentity and in CUserIdentity there are 2 properties defined:
$username
$password
So you should either change
$record=Admin::model()->findByAttributes(array('username'=>$this->user_name));
to
$record=Admin::model()->findByAttributes(array('username'=>$this->username));
or
declare $user_name in your AdminIdentity class. If you choose to declare the new property make sure you set a value in the constructor (more changes will be needed)
plz i have some rules function that i dont want to change in its code (BaseModel from database)
and i make other rules function in the model , i want to change in it
the base one "dont ant to change"
public function rules() {
return array(
array('start_date, end_date, info, type_id', 'required'),
array('start_date, end_date, type_id', 'length', 'max'=>10),
}
and i want to change in other function in the model that inherit from the base model
here is its code
public function rules()
{
$rules = array(
array('start_date, end_date, type_id', 'length', 'max'=>16),
);
return array_merge($rules,parent::rules());
}
the problem that it uses max value as 10 , not 16
i want it 16
even when i chenge last line to
return array_merge(parent::rules(),$rules);
The reason it might not work is because the rule for 'max'=>10 still exists in rules() irrespective of the order. Replacing the rule works for me.
public function rules(){
$rules=parent::rules();
$rules[1]=array('start_date, end_date, type_id', 'length', 'max'=>16);
return $rules;
}
Edit
To replace the rule using 'start_date, end_date, type_id' as the "key" you need a recursive array search:
public function rules(){
$rules=parent::rules();
$index=0;//index of the rule
outer: foreach($rules as $rule){
if(array_search('start_date, end_date, type_id',$rule)!==false)
break outer;
$index++;
}
$rules[$index]=array('start_date, end_date, type_id', 'length', 'max'=>16);
return $rules;
}
This checks for the existing rule and if it doesn't exist adds the rule as the last element of $rules. This won't work if someone edits the first element in the base class e.g to add a new property/field to the rule.
Just completed the same task, created a merging helper function:
public function mergeRules($parent, $rules)
{
// creating curent rules map
$rulesMap = [];
foreach ($rules as $rule) {
$validator = $rule[1];
$attributes = array_map('trim', explode(',', $rule[0]));
if (!isset($rulesMap[$validator])) {
$rulesMap[$validator] = [];
}
$rulesMap[$validator] = CMap::mergeArray($rulesMap[$validator], $attributes);
}
// checking for attributes in parent rules against created rule map
if (!empty($rulesMap)) {
foreach ($parent as $i => $rule) {
$validator = $rule[1];
if (empty($rulesMap[$validator])) {
continue;
}
$attributes = array_map('trim', explode(',', $rule[0]));
foreach ($attributes as $k => $attribute) {
if (in_array($attribute, $rulesMap[$validator])) {
unset($attributes[$k]);
}
}
// unset if we got inherited rule of same validator
if (empty($attributes)) {
unset($parent[$i]);
} else {
$parent[$i][0] = implode(', ', $attributes);
}
}
}
return array_merge($parent, $rules);
}
Then in rules() function you just call:
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
$rules = array(
blablabla...
);
return $this->mergeRules(parent::rules(), $rules);
}
One way to do this is to give your rules a key.
From the docs
Note: It is handy to give names to rules i.e.
public function rules()
{
return [
// ...
'password' => [['password'], 'string', 'max' => 60],
];
}
You can use it in a child model:
public function rules()
{
$rules = parent::rules();
unset($rules['password']);
return $rules;
}
In your case you could do this in your parent class:-
public function rules() {
return array(
'requiredArray' => array('start_date, end_date, info, type_id', 'required'),
'maxLengthArray' => array('start_date, end_date, type_id', 'length', 'max'=>10),
}
and in your child class:-
public function rules()
{
$parent = parent::rules();
$rules = array(
'maxLengthArray' => array('start_date, end_date, type_id', 'length', 'max'=>16)
);
unset($parent['maxLengthArray']);
return array_merge($parent,$rules);
}
Edit:
Keeping in mind that if you want to update only 'one' attribute within the 'maxLengthArray'... the others will have to be re-applied after 'unset' from parent ( obviously :) ).
eg:-
Changing only type_id length... the child would look like:-
public function rules()
{
$parent = parent::rules();
$rules = array(
'maxLengthArray' => array('start_date, end_date', 'length', 'max'=>10),
'typeIdLength' => array('type_id', 'length', 'max'=>16),
);
unset($parent['maxLengthArray']);
return array_merge($parent,$rules);
}