[Howot] Attach Event Handler ?

Hi,

I want to preload a component , and i want this component to attachEventHandler.

the events i want to catch is: onBeforeRender

from the CAction component : http://www.yiiframework.com/doc/api/1.1/CViewAction

How can i do that ?

or if i am doing it wrong , whats the right way to catch this event ?

Thanks

I want to be able to catch event just before the action is rendered to decide what theme to render. :blink:

If you preload the component, any call you do from it is too early for controllers because at that point the controller has not been instantiated, therefore you can’t hook into it.

If yii 1.1 would have global events that wouldn’t need an object to attach to then it wouldn’t be a problem, but it doesn’t, therefore you cannot achieve this out-of-the-box.

What you can do instead, is to create your own component for attaching callbacks to your own handlers.

Here is a simple example to help you get started




class EventsManager extends CApplicationComponent 

{

    private $_events;


    protected function getEvents()

    {

        if (!($this->_events instanceof CMap)) {

            $this->_events = new CMap();    

        }    

        

        return $this->_events;

    }

    

    public function addEvent($tag, $callback)

    {

        if (empty($tag) || !is_callable($callback, true)) {

            return $this;

        }

        

        if (!$this->getEvents()->contains($tag)) {

            $this->getEvents()->add($tag, new CList());

        }

        

        $this->getEvents()->itemAt($tag)->add($callback);

        

        return $this;

    }

    

    public function triggerEvent($tag, $arg = null)

    {

        if (!$this->getEvents()->contains($tag)) {

            return $this;

        }

        

        $args = func_get_args();

        $args = array_slice($args, 2);

        array_unshift($args, $arg);

        

        $events = $this->getEvents()->itemAt($tag)->toArray();

        

        foreach ($events as $eventCallback) {

            call_user_func_array($eventCallback, $args);

        }

        

        return $this;

    }

}



This is a component, preload it as "eventsManager" for example.

Then, from your other components you will do something like:




public function anyComponentMethod()

{

    [...]

    // add the callback

    Yii::app()->eventsManager->addEvent('my_custom_event_name', array($this, 'myCallback'));

    [...]

}


// and add the callback

public function myCallback($controllerInstance) {

    // $controllerInstance is the controller instance, do whatever with it 

    $controllerInstance->themeName = 'bar'; 

}



then in your controllers you would have something like:




public $themeName = 'foo';

public function actionIndex()

{

    [...]

    Yii::app()->eventsManager->triggerEvent('my_custom_event_name', $this);

    [...]

    Yii::app()->theme = $this->themeName;

    $this->render('whatever');

}



And this way the controller would trigger a callback that you have registered earlier in the application.

This is the same approach that wordpress does with add_action().

Hope it helps.

Thanks :)

Hi Idan Hen

Yii has controller filters look at the beforeAction method there is also beforeRender()


// in your controller

public function beforeAction($action)

{

     echo "going to set a new theme ...";

     return parent::beforeAction($action);

}

How would he hook into that event from a component loaded before the controller ?

genius look at his second comment you read carefully before you reply

@alirz23 - he states, and i quote:

That’s the reason i have suggest that approach.

If he would want to hook from inside the controller, why would’ve he override beforeRender or beforeAction?

He would’ve add the code in controller so he could do it as well right before calling $this->render() in action.

Anyway, if i misunderstood, my bad :)

beforeAction and beforeRender use Yii’s built in events these methods just sugar .

Then maybe you can give an example on how one can hook from a preloaded component in these "events" without calling the component in controller ?

Hi,

alirz23:

Your answer could do the trick , but i want to develope this AB testing as a module or extension to be able to publish it in Yii extension. i think the framework could use a nice AB testing mechanism.

twisted1919:

Its a great idea to create my own Events handler to be able to use it from the preload. thats what stopped me from the first place.

in this way , the installation process of the AB testing can be simpler , i will try this way first.

@Idan you could always go with a behavior Most of the exts that I have used are using behaviors to hook in to the request