php - Observer design pattern in Yii 1.1.16, attaching event handlers and rising events -
in yii 1.1.16 observer design pattern implemented using events & behaivours (events can shared between components extends ccomponents). have following models:
- user.php (see below)
- work.php (see below)
- activity.php
what want accomplish following: lets 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 handled models listen event $work->save(); } public function actionexampleuser() { $user = new user(); $user->email = 'foo@example.com'; $user->username = 'example'; $user->password = '123'; //$user->attach( ) invoke event should handled activity model $user-> save(); } ?>
actually have saw lot of examples yii doing related things, far no success on finding answer fit's needs :(
- is possible in yii?
- how can implement this?
- **is there alternatives (except manually handling method calls in controller actions)? **
user.php
<?php class user extends cactiverecord { public function tablename() { //@return string associated database table name }; public function rules() { //@return array validation rules 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 data provider can return models // based on 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 associated database table name } public function rules() { //@return array validation rules 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 data provider can return models // based on search/filter conditions. } ?>
you don't need observer class scenario.
using built in event handlers yii model class has few built in functions can overwrite in class.
have @ official documentation cactiverecord more detaiils. http://www.yiiframework.com/doc/api/1.1/cactiverecord hint: search beforexxxx, afterxxxx, onxxxxx
as example, here pre-persist handler user model.
/** * runs before models save method invoked. provides change * ...further prepare data saving. cactiverecord (parent class) * ...beforesave called process raised events. * * @param <none> <none> * @return boolean decision continue save or not. * * @access public */ public function beforesave() { // ///////////////////////////////////////////////////////////////////// // scenarios require fields updated. 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 password. if password set // ///////////////////////////////////////////////////////////////////// if (isset($this->password) && (!empty($this->password))) { $this->password = cpasswordhelper::hashpassword($this->password); } } /** other scenarios */ // ///////////////////////////////////////////////////////////////////// // set create time , user new records // ///////////////////////////////////////////////////////////////////// if ($this->isnewrecord) { $this->created_time = new cdbexpression('now()'); $this->created_by = '1'; // special case not logged in user $this->modified_by = '1'; } else { $this->modified_by = isset(yii::app()->user->id)?yii::app()->user->id:1; } // ///////////////////////////////////////////////////////////////////// // modified log details set record creation , update // ///////////////////////////////////////////////////////////////////// $this->modified_time = new cdbexpression('now()'); return parent::beforesave(); }
notice have full access record before save happens (ie. no access primary-key when new record being processed.
look out built in scenarios 'insert' , 'update'.
note invoke parent beforesave before exiting cascade events in parents.
using custom events
you can create custom events.
create event class eg. protected/components/newuser.php:
class newuser extends cmodelevent{ public $userrecord; }
then in controller
$usermodel->attacheventhandler('onnewuser',newusereventhandler); function newusereventhandler($event){ // add custom handling code here do_some_things_here($event->new, $event->id); }
in model, need raise event
$event=new newuserevent; // add custom data event. $event->new=$this->isnewrecord; $event->order=$this->id; $this->raiseevent('onnewuser',$event);
Comments
Post a Comment