Yii 1.1.16 中的观察者设计模式,附加事件处理程序和上升事件
Observer design pattern in Yii 1.1.16, attaching event handlers and rising events
在 Yii 1.1.16 Observer Design Pattern is implemented using events & behaivours (events can be shared between all components that extends CComponents)。我有以下型号:
- User.php (see below)
- Work.php (see below)
- Activity.php
我想要完成的是:
让我们说 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 = 'foo@example.com';
$user->username = 'example';
$user->password = '123';
//$user->attach( something ) invoke Event that should be handled only by Activity model
$user-> save();
}
?>
实际上我已经看到很多 Yii 做相关事情的例子,但到目前为止没有成功找到适合我需要的答案:(
- 这在 Yii 中可行吗?
- 我该如何实现?
- **是否有替代方案(除了在控制器操作中手动处理方法调用)? **
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.
}
?>
您的方案不需要观察者 class。
使用内置事件处理程序
Yii 模型 class 有一些内置函数,您可以在 class.
中覆盖这些函数
查看 CActiveRecord 的官方文档了解更多详情。
http://www.yiiframework.com/doc/api/1.1/CActiveRecord
提示:搜索 beforeXXXX、afterXXXX、onXXXXX
例如,这是我的用户模型的预持久处理程序。
/**
* 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();
}
请注意,在保存之前我拥有对记录的完全访问权限(即,在处理新记录时无法访问主键。
还要注意内置场景 'insert' 和 'update'。
另请注意,我在退出之前调用了父级 beforeSave 以在父级中级联事件。
使用自定义事件
您可以创建自定义事件。
创建一个事件class 例如。 protected/components/Newuser.php:
class NewUser extends CModelEvent{
public $userRecord;
}
然后在你的控制器中
$userModel->attachEventHandler('onNewUser',newuserEventHandler);
function newuserEventHandler($event){
// Add custom handling code here
do_some_things_here($event->new, $event->id);
}
在您的模型中,您需要引发事件
$event=new NewUserEvent;
// Add custom data to event.
$event->new=$this->isNewRecord;
$event->order=$this->id;
$this->raiseEvent('onNewUser',$event);
在 Yii 1.1.16 Observer Design Pattern is implemented using events & behaivours (events can be shared between all components that extends CComponents)。我有以下型号:
- User.php (see below)
- Work.php (see below)
- Activity.php
我想要完成的是: 让我们说 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 = 'foo@example.com';
$user->username = 'example';
$user->password = '123';
//$user->attach( something ) invoke Event that should be handled only by Activity model
$user-> save();
}
?>
实际上我已经看到很多 Yii 做相关事情的例子,但到目前为止没有成功找到适合我需要的答案:(
- 这在 Yii 中可行吗?
- 我该如何实现?
- **是否有替代方案(除了在控制器操作中手动处理方法调用)? **
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.
}
?>
您的方案不需要观察者 class。
使用内置事件处理程序 Yii 模型 class 有一些内置函数,您可以在 class.
中覆盖这些函数查看 CActiveRecord 的官方文档了解更多详情。 http://www.yiiframework.com/doc/api/1.1/CActiveRecord 提示:搜索 beforeXXXX、afterXXXX、onXXXXX
例如,这是我的用户模型的预持久处理程序。
/**
* 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();
}
请注意,在保存之前我拥有对记录的完全访问权限(即,在处理新记录时无法访问主键。
还要注意内置场景 'insert' 和 'update'。
另请注意,我在退出之前调用了父级 beforeSave 以在父级中级联事件。
使用自定义事件
您可以创建自定义事件。
创建一个事件class 例如。 protected/components/Newuser.php:
class NewUser extends CModelEvent{
public $userRecord;
}
然后在你的控制器中
$userModel->attachEventHandler('onNewUser',newuserEventHandler);
function newuserEventHandler($event){
// Add custom handling code here
do_some_things_here($event->new, $event->id);
}
在您的模型中,您需要引发事件
$event=new NewUserEvent;
// Add custom data to event.
$event->new=$this->isNewRecord;
$event->order=$this->id;
$this->raiseEvent('onNewUser',$event);