Behaviors and events

I have a component called "BaseUrlManager" which extends CUrlManager and a behavior called "I18nBehavior" which is attached to my "BaseUrlManager". In my "I18nBehavior" I want to do some extra stuff for the "createUrl" method before the "createUrl" method of "BaseUrlManager" is called.

Can this be done with "events"?

Try to add something like this at the beginning of your method




if($this->hasEventHandler('onBeginYourEvent'))

	$this->raiseEvent('onBeginYourEvent',new CEvent($this));



then use something like




$this->onBeginYourEvent = array(new SomeClass, 'yourEventHandler');



Please note I didn’t test it.

hi ekerazha,

thanks for your reply. In which method should this be done, and what is "onBeginYourEvent"?

I’ve read all the articles about behaviors and events, but I don’t understand the usage of it all. It’s a bit confusing :(

EDIT: I want to "extend" the "createUrl" method of my "BaseUrlManager" with an "createUrl" method of the attached "I18nBehavior".

At the beginning of createUrl or before you call it. onBeginYourEvent is the name of the event you create.

Sorry, but it’s still unclear to me what the advantage of events is about. Where do I do the “raiseEvent”? All I want to do, I to “hook” from the behavior class into the “createUrl” function of the component class, because I have to add some extra stuff to the “params” array of the “createUrl” function.

Yeah, when you want to trigger the hook, you raise the event and it will invoke the methods you assigned as event handlers. Please note I didn’t test this but it is how I think it does work.

Ok, this sounds like it has to be something like this (in "BaseUrlManager"):

public function createUrl($route, $params = array(), $ampersand = ‘&’)

{

if ($this->hasEventHandler(‘onCreateUrl’))

$this->raiseEvent('onCreateUrl', new CEvent($this));

return parent::createUrl($route, $params, $ampersand);

}

but how do i get all the arguments to the "onCreateUrl" method of the "I18nBehavior"?

Note your "onCreateUrl" is the event name, not the handler name. You have to assign it like

$this->onCreateUrl = array(new SomeClass, ‘yourEventHandler’);

Well… I should try, I can’t go further with suppositions eh eh

OMG, too much confusion. "yourEventHandler" is the "onCreateUrl" function in my "I18nBehavior" class, right?

Ok, I’ve tried a little around. Seems like there has to be the following function in “BaseUrlManager” (if this function doens’t exist there will be an error):




public function onCreateUrl()

{

}



and in the attached "I18nBehavior" I have a function:




public function doParamManipulation($objEvent)

{

  CVarDumper::dump($objEvent,100,true);

}



and in the "attach" method of "I18nBehavior" I have to do:




public function attach($objOwner)

{

  $objOwner->attachEventHandler('onCreateUrl', array($this, 'doParamManipulation'));

}



the usage is then like this:




public function createUrl($route, $params = array(), $ampersand = '&')

{

  if ($this->hasEventHandler('onCreateUrl'))

    $this->raiseEvent('onCreateUrl', new CEvent($this));


  return parent::createUrl($route, $params, $ampersand);

}



do you think this is the right way? If this is correct, it does mean, that I have to create empty "onXYZ" functions in my component class, right?

That’s right. The existence of a method starting with “on” indicates that an event is available from that class. The implementation doesn’t really matter but it’s kind of convention to fire the according event inside that method. Check e.g. the source of CActiveRecord and onBeforeSave for examples.

Addition:

Of course the class that should provide an event needs to extend from CComponent (or its child classes) as it implements the event handling.

I tried to "compress" the code, if you look at some implementations inside Yii, it uses something like this




	if($this->hasEventHandler('onBeginRequest'))

		$this->onBeginRequest(new CEvent($this));






	public function onBeginRequest($event)

	{

		$this->raiseEvent('onBeginRequest',$event);

	}



I tried to merge the code in order to avoid an extra method but you’re saying it is needed, so just go this way.