Hi guys, nice to meet you all. I’m new to YII and try to understand how the framework works. so i need your opinions along the way.
I have problem with this codes (see below), i have two classes, one called Identity and inherits CActiveRecord, and other called TheIdentity and inherits Identity.
"The Identity" is a class which inherits "Identity" class. I did this because i want to keep the "Identity" class untouched, and add codes to its child. Since PHP has no partial class feature like .NET Tech.
When i tried to insert using this short codes, it worked just fine. But when i tried to update, YII raised error duplicate record. Obviously this was because YII tried to insert not update the record. How CActiveRecord::save() actually works? it has been four days to get around this problem, please help. Thanks.
Identity Table’s codes
CREATE TABLE IF NOT EXISTS `IDENTITY` (
`id` INT NOT NULL,
`name` VARCHAR(50) NOT NULL,
`email` VARCHAR(100) NOT NULL,
`mobile` VARCHAR(20) NOT NULL,
`password` VARCHAR(50) NOT NULL,
`isEncrypted` TINYINT(1) NOT NULL DEFAULT false,
`currentAES` INT NOT NULL,
`futureAES` INT NULL,
PRIMARY KEY (`id`),
INDEX `fk_IDENTITY_AESKEY1_idx` (`currentAES` ASC),
INDEX `fk_IDENTITY_AESKEY2_idx` (`futureAES` ASC),
CONSTRAINT `fk_IDENTITY_AESKEY1`
FOREIGN KEY (`currentAES`)
REFERENCES `APLIKASIKU`.`AESKEY` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_IDENTITY_AESKEY2`
FOREIGN KEY (`futureAES`)
REFERENCES `APLIKASIKU`.`AESKEY` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
Identity Class’s codes
<?php
/**
* This is the model class for table "IDENTITY".
*
* The followings are the available columns in table 'IDENTITY':
* @property integer $id
* @property string $name
* @property string $email
* @property string $mobile
* @property string $password
* @property integer $isEncrypted
* @property integer $currentAES
* @property integer $futureAES
*
* The followings are the available model relations:
* @property AESKEY $currentAES0
* @property AESKEY $futureAES0
* @property NOTIFICATION[] $nOTIFICATIONs
* @property TRANSACTION[] $tRANSACTIONs
* @property UPDATE[] $uPDATEs
*/
class IDENTITY extends CActiveRecord
{
function __construct()
{
parent::__construct();
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return 'IDENTITY';
}
/**
* @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('id, name, email, mobile, password', 'required'),
array('id, isEncrypted', 'numerical', 'integerOnly'=>true),
array('password', 'length', 'min'=>5),
array('name, password', 'length', 'max'=>50),
array('email', 'length', 'max'=>100),
array('mobile', 'length', 'max'=>20),
// The following rule is used by search().
// @todo Please remove those attributes that should not be searched.
array('id, name, email, mobile, password, isEncrypted, currentAES, futureAES', 'safe', 'on'=>'search'),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'currentAES0' => array(self::BELONGS_TO, 'AESKEY', 'currentAES'),
'futureAES0' => array(self::BELONGS_TO, 'AESKEY', 'futureAES'),
'NOTIFICATIONs' => array(self::HAS_MANY, 'NOTIFICATION', 'IDENTITY_id'),
'TRANSACTIONs' => array(self::HAS_MANY, 'TRANSACTION', 'IDENTITY_id'),
'UPDATEs' => array(self::HAS_MANY, 'UPDATE', 'IDENTITY_id'),
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'name' => 'Name',
'email' => 'Email',
'mobile' => 'Mobile',
'password' => 'Password',
'isEncrypted' => 'Is Encrypted',
'currentAES' => 'Current Aes',
'futureAES' => 'Future Aes',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* @return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
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('name',$this->name,true);
$criteria->compare('email',$this->email,true);
$criteria->compare('mobile',$this->mobile,true);
$criteria->compare('password',$this->password,true);
$criteria->compare('isEncrypted',$this->isEncrypted);
$criteria->compare('currentAES',$this->currentAES);
$criteria->compare('futureAES',$this->futureAES);
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 IDENTITY the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
The Identity Class’s codes
<?php
class TheIdentity extends IDENTITY
{
function __construct()
{
parent::__construct();
$this->onBeforeSave = array($this, 'handleBeforeSave');
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
protected function handleBeforeSave($event)
{
if($this->isEncrypted == 0 || $this->isEncrypted == null)
{
$record = TheAESKey::model()->latest($this->tableName())->find();
if($record == null)
throw new Exception($this->tableName() . " is not associated with AESKEY");
else
{
$this->setEncryptedPassword($record->encrypt($this->password));
$this->setCurrentAES($record->id);
}
}
echo $this->isNewRecord;
$event->isValid = false;
}
public function setPassword($password)
{
$this->password = $password;
$this->isEncrypted = 0;
}
public function setEncryptedPassword($password)
{
$this->password = $password;
$this->isEncrypted = 1;
}
public function getPassword()
{
return $this->password;
}
public function setCurrentAES($currentAES)
{
$this->currentAES = $currentAES;
}
public function getCurrentAES()
{
return $this->currentAES;
}
}