Reputation: 35
In Yii 1.1.16 Observer Design Pattern is implemented using events & behaivours (events can be shared between all components that extends CComponents). I have following models:
- User.php (see below)
- Work.php (see below)
- Activity.php
what I want to accomplish is following: lets say in DefaultController:
<?php
public function actionExampleWork()
{
$work = new Work();
$work->description = 'some random description';
$work->created_at = new CDbException('NOW()');
$work->user_id = 1;
//$work->attach() INVOKE EVENT that will be handled by all models which listen to this event
$work->save();
}
public function actionExampleUser()
{
$user = new User();
$user->email = '[email protected]';
$user->username = 'example';
$user->password = '123';
//$user->attach( something ) invoke Event that should be handled only by Activity model
$user-> save();
}
?>
actually I have saw lot of examples Yii doing related things, but so far no success on finding answer that fit's my needs :(
User.php
<?php class User extends CActiveRecord
{
public function tableName()
{
//@return string the associated database table name
};
public function rules()
{
//@return array validation rules for model attributes.
};
public function relations()
{
return array(
'works' => [self::HAS_MANY, 'Works', 'user_id'],
);
}
public function attributeLabels()
{
//@return array customized attribute labels (name=>label)
}
public function search()
{
//@return CActiveDataProvider the data provider that can return the models
// based on the search/filter conditions.
}
public function updateLastActivity($user_id, $activity_type){
$user = $user->model()->findByPk($user_id);//find user
$user->activity_type = $activity_type;
$user->last_action = new CDbExpression('NOW()');//update DB column
$user->save; //save user
}
} ?>
Work.php
<?php
class Work extends CActiveRecord
{
public function tableName()
{
//@return string the associated database table name
}
public function rules()
{
//@return array validation rules for model attributes.
}
public function relations()
{
return array(
'user' => [self::BELONGS_TO, 'User', 'user_id'],
);
}
public function attributeLabels()
{
//@return array customized attribute labels (name=>label)
}
public function search()
{
//@return CActiveDataProvider the data provider that can return the models
// based on the search/filter conditions.
}
?>
Upvotes: 1
Views: 1046
Reputation: 6296
You don't need an observer class for your scenario.
Using Built in Event Handlers The Yii model class has a few built in functions that you can overwrite in your class.
Have a look at the official documentation for CActiveRecord for more detaiils. http://www.yiiframework.com/doc/api/1.1/CActiveRecord HINT: Search for beforeXXXX, afterXXXX, onXXXXX
As an example, here is my pre-persist handler for my user model.
/**
* Runs just before the models save method is invoked. It provides a change to
* ...further prepare the data for saving. The CActiveRecord (parent class)
* ...beforeSave is called to process any raised events.
*
* @param <none> <none>
* @return boolean the decision to continue the save or not.
*
* @access public
*/
public function beforeSave() {
// /////////////////////////////////////////////////////////////////////
// Some scenarios only require certain fields to be updated. We handle
// ...this separately.
// /////////////////////////////////////////////////////////////////////
if ($this->scenario == self::SCENARIO_LOGIN)
{
/** Login scenario */
$this->last_login = new CDbExpression('NOW()');
}
if ($this->scenario == self::SCENARIO_ACTIVATION)
{
/** Account activation scenario */
if ($this->activation_status == 'activated')
{
$this->activation_code = '';
$this->status = 'active';
$this->activation_time = new CDbExpression('NOW()');
}
}
if ( ($this->scenario == self::SCENARIO_CHANGE_PASSWORD) ||
($this->scenario == self::SCENARIO_REGISTER) ||
($this->scenario == 'insert') ||
($this->scenario == 'update')
)
{
/** Password change scenario */
// /////////////////////////////////////////////////////////////////////
// Encrypt the password. Only do this if the password is set
// /////////////////////////////////////////////////////////////////////
if (isset($this->password) && (!empty($this->password)))
{
$this->password = CPasswordHelper::hashPassword($this->password);
}
}
/** All other scenarios */
// /////////////////////////////////////////////////////////////////////
// Set the create time and user for new records
// /////////////////////////////////////////////////////////////////////
if ($this->isNewRecord) {
$this->created_time = new CDbExpression('NOW()');
$this->created_by = '1'; // Special case for not logged in user
$this->modified_by = '1';
}
else
{
$this->modified_by = isset(Yii::app()->user->id)?Yii::app()->user->id:1;
}
// /////////////////////////////////////////////////////////////////////
// The modified log details is set for record creation and update
// /////////////////////////////////////////////////////////////////////
$this->modified_time = new CDbExpression('NOW()');
return parent::beforeSave();
}
Notice that I have full access to the record BEFORE the save happens (ie. no access to primary-key when a new record is being processed.
Look out also for built in scenarios 'insert' and 'update'.
Note also that I invoke the parent beforeSave before exiting to cascade events in the parents.
Using Custom Events
You can create custom events.
Create an event class eg. protected/components/Newuser.php:
class NewUser extends CModelEvent{
public $userRecord;
}
Then in your controller
$userModel->attachEventHandler('onNewUser',newuserEventHandler);
function newuserEventHandler($event){
// Add custom handling code here
do_some_things_here($event->new, $event->id);
}
In your model, you need to raise the event
$event=new NewUserEvent;
// Add custom data to event.
$event->new=$this->isNewRecord;
$event->order=$this->id;
$this->raiseEvent('onNewUser',$event);
Upvotes: 1