Component event and component behavior

I’m reading Yii manual, but I don’t understand what component event and behavior are, and when to use them.

Can someone give an example on how to use them and why (examples in guide are not so clear).

Thanks

Danilo

They do mostly the same thing. You can attach behaviors and event handlers to components to modify the components’ behavior.

It is useful when you want to interrupt the normal application flow without extending the base classes.

For example, enabling gzip compression on the output could be done via extending CWebApplication. But because there are entry points for event handlers, one can do this:




Yii::app()->onBeginRequest = create_function('$event', 'return ob_start("ob_gzhandler");'),

Yii::app()->onEndRequest = create_function('$event', 'return ob_end_flush();'),



( http://www.yiiframework.com/doc/cookbook/39/ )

Hope this helped.

You can create an event handler – which is simply a method in some class with a specific signature – and attach it to the event of an object. You can add as many event handlers as you wish, from as many objects as you wish. If the event handler is, effectively static, then you can create the object as you assign it:




    $test_comp->onSomethingGoesOn = array(new SomeClass, 'eventHandler1');

    $test_comp->onSomethingGoesOn = array(new SomeOtherClass, 'eventHandler2');

    $test_comp->onSomethingGoesOn = array(new YetAnotherClass, 'eventHandler3');



As long as you have a handle on the object, then you can add an event handler to it.

At some point, you can then raise the event with something like one of these:




    $test_comp->onSomethingGoesOn(new CEvent($this));

    $test_comp->onSomethingGoesOn(new CEvent());



So, basically, it allows you build a list of function calls that can later be executed, in the order they were added. It can save you passing around a lot of object refs and building conditional code, since you can still raise the event, even if it doesn’t do anything.

Behaviors are simply a way of adding methods to an object. In an OO language like Ruby, it’s quite possible to start with an completely empty object and simply build its behavior as you go along. Yii provides this behavior with a little magic. The key is that the class you wish to add the behavior from must extend CBehavior.




class SomeClass extends CBehavior {

    public function add($x, $y) { return $x + $y; }

}



Then use with:




    $test_comp = new TestComponent(); 

    $test_comp->attachBehavior('blah', new SomeClass);

    $test_comp->add(2, 5);



So, in this case, you are extending the functionality of an object with functionality of another object.

May I use your post to create a cookbook page to answer this very general question?

Of course. It was you that helped me understand events and behaviors in the first place :)

It’s probably worth adding something about using objects that are not new’d in the assigments. All the examples I used use new objects.

Also, behaviors don’t have to extend CBehavior, but only have to implement IBehavior. I didn’t say that originally to keep things simple.

http://www.yiiframework.com/doc/cookbook/44/

Here you go. I didn’t have much work with it as you produced the biggest part of it. :) Thank you very much!

If anything crosses your mind, feel free to modify the article.

Very nice writeup! Thanks!

thanks for your efforts :)

I hope to create an Yii powered application ASAP!

Could you explain practical uses for event handlers and behaviors?

Maybe examples more intuitive than


$test_comp->onSomethingGoesOn = array(new YetAnotherClass, 'eventHandler3');

Thank you!

For “behaviors”, perhaps the best way would be to study Ruby mixins. Think of a class with no behaviour – methods, if you like. Yii “behaviors” allow you to add behaviour. The “behavior” is independent of the class. An object’s original class is irrelevant. In Ruby, I often use “blank” objects and build them with appropriate behaviour. Yii’s “behaviors” aren’t as flexible – they aren’t a language construct – but it’s great to have them.

If this seems odd, you are in good company. Many folk think of classes as having fixed behaviour – ignoring patterns like strategy and so on, which you have to build, they aren’t inherent behaviour of classes. This is a very limited view, and doesn’t hold in many languages.

Also take a look at duck-typing.

Event handlers are completely different. They are a way of deferring applying behaviour until a certain event.

For example, say you are processing an order and want to do a bunch of things, but only after payment has been confirmed. It’s a lot easier to build this “list” of activities while processing the order, and simply activate it after payment, than post-process the order.

I read cookbook 44, and I reread the entire component page, but the part with events is still unclear. I’m not certain where the event hook is placed or where/how the event attachment is processed from.

If I have a component, and it has a number of methods, if I want to place event hooks in them, all those methods need to begin with "onXXX"?

For example, when building an application, if there are some modules that are going to modify some event, when/where do they attach to the event?

Also, once the event is called, what data does it have access to? Are all the variables that existed in the method it was raised in available? Do they need to be returned? What if I want event hooks at the beginning and end of a method?

Lots of questions, I know.

Thanks in advance :lol:

I wrote a guide about events but it’s currently only in Russian: http://yiiframework.ru/doc/cookbook/ru/core.events

There is a one more example of using behaviors & events: http://www.yiiframework.com/doc/cookbook/63/

Another behavior example. Let’s assume you have different content types (eg articles and reviews). Now you want to track the views for each content type. First, take a look at this:




class Article extends CActiveRecord

{


   public function behaviors()

   {

      return array(

         'viewable' => array(

            'class' => 'ViewableBehavior',

         ),

      );

   }


}


class Review extends CActiveRecord

{


   public function behaviors()

   {

      return array(

         'viewable' => array(

            'class' => 'ViewableBehavior',

         ),

      );

   }


}


class ViewableBehavior extends CActiveRecordBehavior

{


   public function trackView()

   {

      $this->owner->views++;

      $this->owner->update(array('views'));

   }


}


class ArticleController

{


   public function actionView()

   {

    

      $article = Article::model()->findByPk(1);


      $article->trackView();


      $this->render('view', array('article' => $article));


   }


}




As you can see, we can simply do $model->trackView() now. You might think "why a behavior? why not do $model->views++; within the controller?".

Of course this is a very simple example. But you can extend the behavior and do all this (if needed):

  • make sure there is a delay of x hours between each view of same client

  • don’t track view if client is a search engine

  • don’t track view for unauthorized users

  • keep track of all views (eg in order to sort by "most viewed last 24 hours")

  • and so on

So you save a lot of work by doing all the logic within a special behavior instead of doing the logic for each model. Also think about a rateable or commentable behavior :)

Excellent writeup, far superior to the others I’ve read. For my fellow English-speakers, I’ve attached a translated version as a PDF. Samdark, hopefully that’s ok…let me know if not.

Thanks for taking the time to put that together!

MB

848

Events - Recipes - YiiFramework.pdf

Thanks. Maybe I should translate this one and the rest of cookbook into English…