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)。我有以下型号:

  1. User.php (see below)
  2. Work.php (see below)
  3. 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 做相关事情的例子,但到目前为止没有成功找到适合我需要的答案:(

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);