Yii 1.1.16中的观察者设计模式,附加事件处理程序和上升事件

时间:2015-04-14 20:45:10

标签: php yii yii-components

在Yii 1.1.16 Observer Design Pattern中使用 events& behaivours (事件可以在扩展CComponents)的所有组件之间共享。我有以下模型:

  
      
  1. User.php (见下文)
  2.   
  3. Work.php (见下文)
  4.   
  5. Activity.php
  6.   

我想要完成的是: 让我们说 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.
}


?>

1 个答案:

答案 0 :(得分:1)

您的方案不需要观察者类。

使用内置事件处理程序 Yii模型类有一些内置函数,可以在类中覆盖。

有关更多详细信息,请查看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();
}

请注意,在保存发生之前,我可以完全访问记录(即,在处理新记录时无法访问主键。

还要注意内置方案“插入”和“更新”。

另请注意,在退出父级中的级联事件之前,我会调用父之前的事件。

使用自定义事件

您可以创建自定义活动。

创建一个事件类,例如。保护/组件/ 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);