How to implement an event and attach it in a behavior

This page explains how to implement an event and catch that event in a behavior.

To understand what happends you should know or have an idea of what behaviors and events are. If not just quicky read ["that wiki page."](http://www.yiiframework.com/wiki/44/behaviors-events#hh1 )

Let's begin!

We have a CActiveRecordModel named party . Users can register to a party.

What we want to do is create a behavior to send notification to the party manager. Because we don't want our party model to manage notifications we will separate party model and notification model ( we also know that the way we will deal with nofications can change and be complexe ). So what we can do is attach a behavior to party . That behavior will manage notifications. For example when a user register to a party.

Our model have a registerPlayer method :

public function registerPlayer($player_id = null)
    {
        if ($this->registrable)
        {
            $player_id = $player_id ? $player_id : yii::app()->user->id;
            if(UserPartyBridge::model()->add($this->id, $player_id))
            {
                return true;
            }
        }
        return false;
    }

So we will :

  • Create the Event :
  • declare an event : onAfterPlayerRegister
  • raise that event when a user register
  • Attach a behavior to the party model
  • implement the behavior :
  • declare the events the behavior will handle
  • implement the function to handle notification

Create the event

In party model we declare the event :

public function onAfterPlayerRegister($event)
    {
        echo "\n" . __CLASS__ . ' ' . __FUNCTION__; // this is just to test, we can also use yii::log()
        $this->raiseEvent('onAfterPlayerRegister', $event);
    }

That even needs to be raised at the right time, so we modify the registerPlayer method :

public function registerPlayer($player_id = null)
    {
        if ($this->registrable)
        {
            $player_id = $player_id ? $player_id : yii::app()->user->id;
            if(UserPartyBridge::model()->add($this->id, $player_id))
            {
                // raise 'onAfterPlayerRegister' 
                $this->onAfterPlayerRegister(new CEvent($this, array('player' => User::model()->findByPk($player_id))));
                return true;
            }
        }
        return false;
    }

We declared an event and raise it at the right time. The event won't be handle in our model but in the behavior. So we will now attach a behavior to party :

public function behaviors()
    {
        return array_merge(
                        parent::behaviors(), array(
                    'testEvent' => array(
                        'class' => 'ext.NotificationManager'
                    )
                        )
        );
    }

Our party model is now extended with our NotificationManager. Let's implement it :

class NotificationManager extends CActiveRecordBehavior // CModelBehavior
{
...
}

We must now declare that our behavior will handle the onAfterPlayerRegister event :

class NotificationManager extends CActiveRecordBehavior // CModelBehavior
{
    public function events()
    {
        return array_merge(parent::events(), array(
           'onAfterPlayerRegister' => 'afterPlayerRegistred'
        ));
    
    }
}

So when onAfterPlayerRegister event will be raised, our behavior will run the afterPlayerRegistred function (we can name it how we want).

Always merge the parent events otherwise you will disable other events handlers.

So We just just need to implement the afterPlayerRegistred function :

class testEvent extends CActiveRecordBehavior // CModelBehavior
{
    
    public function afterPlayerRegistred(CEvent $e)
    {
        // that's where we manage notification
        // we have the party object ($e->sender)
        // and the user object $e->params['player']
        echo "\n " . __CLASS__ . ' ' . __FUNCTION__;
        echo CVarDumper::dumpAsString($e->params['player']->nickname);
    }
    
    public function events()
    {
        return array_merge(parent::events(), array(
           'onAfterPlayerRegister' => 'afterPlayerRegistred'
        ));
    
    }

}

That's all.

This way we can extend/disable behaviors attached to party, just editing the behaviors() method of party.