From our previous post(link), we saw how events work in Yii. We learnt the meaning of event generators, event handlers and how registration of event handlers is done in Yii. What we did not talk about was how we can respond to events which our web applications may raise. In this post, we will discuss a pattern for handling generated events by event generators themselves.

If an event occurs on an object, the object will raise an event for event handlers to respond. The event handlers will not be separate objects that are interested in what has occurred but will be the event generators themselves.

In this pattern, the event handler is attached to the generator when it is constructed. It could be in the constructor function or a method that is called right after the object is created. For Active Records, the init() method is the right place to add the event handlers.

public function init(){
    $this->addEventHandler('onWithdraw',array($this,'withdrawLog'));
}

In the code above, we add the ‘onWithdraw’ event with its corresponding event handler called ‘withdrawLog ‘ in the init method of an active record say account.

The event will be called when a user withdraws some amount from their account.

public function withdraw($amount){
    $this->amount -= $amount;
    $event = new WithrawEvent($this,$amount,time());
    $this->raiseEvent('onWithdraw',$event);
}

//actual call
$model->withdraw(100);

The event that is raised is a derived class of CEvent. If you are not sure how you can create you own derived CEvent, you should read this post. The information encapsulated in this event includes the sender of the event, the amount which was withdrawn and the time the withdrawal occurred.

The implementation of the handler is very simple. It logs the time the money was withdrawn. It also logs the actual amount withdrawn and the current user’s balance. The following callback code is part of the model’s class.

public function withdrawLog($event){
    Yii::log("Amount withdrawn: {$event->amount}",'info');
    Yii::log("Time of withdrawal: {$event->time}",'info');
    Yii::log("Amount Left: {$event->sender->amount}",'info');
}

Below is a minimal implementation of the account model.

class Account extends CActiveRecord{

    public function init(){
        $this->addEventHandler('onWithdraw',array($this,'withdrawLog'));
    }

    public function withdraw($amount){
        $this->amount -= $amount;
        $event = new WithrawEvent($this,$amount,time());
        $this->raiseEvent('onWithdraw',$event);
    }
    public function withdrawLog($event){
        Yii::log("Amount withdrawn: {$event->amount}",'info');
        Yii::log("Time of withdrawal: {$event->time}",'info');
        Yii::log("Amount Left: {$event->sender->amount}",'info');
    }
}