Yii 1.1: event-interceptor

A component, that allows to intercept events raised by observed components.
8 followers

The EventInterceptor component allows you to observe another component, which we call "subject". The EventInterceptor will register to the events of the subject. Every time the subject raises an event, the interceptor will raise an InterceptionEvent. This InterceptionEvent contains the name of the event raised by subject, as well as the intercepted CEvent instance.

This general InterceptionEvent can be usefull, whenever you want to handle events in the same way. An example would be event logging (see Usage).

Requirements

  • Should work with any version of Yii
  • Requires PHP 5.3 or above due to the usage of closures

Usage

This is an example that shows, how the EventInterceptor could be used to log events.

First, we implement a behavior EventLoggerBehavior:

class EventLoggerBehavior extends CBehavior
{
  private $_eventInterceptor = null;
 
  public function attach($owner)
  {
    parent::attach( $owner );
 
    $this->_eventInterceptor = new EventInterceptor();
    $this->_eventInterceptor->initialize( $owner );
    $this->_eventInterceptor->onEventIntercepted = array( $this, 'logEvent' );
  }
 
  public function logEvent( InterceptionEvent $event )
  {
    $interceptedEvent = $event->getInterceptedEvent();
 
    $msg  = 'Component "' . get_class($interceptedEvent->sender) . "' ";
    $msg .= 'raised event "' . $event->getInterceptedEventName() . "'.";
    // maybe include $interceptedEvent->params...
 
    Yii::log( $msg );
  }
 
}

Now, we can attach the behavior to any component, to log it's events. In this example, we use a controller, which raises events whenever one of its actions are invoked:

class SiteController extends Controller
{
  public function behaviors()
  {
    return array(
      'eventLogger' => array(
        'class'   => 'alias.to.EventLoggerBehavior',
      ),
    );
  }
 
  public function onBeforeActionInvoked(CEvent $event)
  {
    $this->raiseEvent( 'onBeforeActionInvoked', $event );
  }
 
  public function onAfterActionInvoked(CEvent $event)
  {
    $this->raiseEvent( 'onAfterActionInvoked', $event );
  }
 
  public function actionIndex()
  {
    $this->onBeforeActionInvoked( new CEvent($this, array(
      'action' => 'index'
    )) );
 
    $this->render('index');
 
    $this->onAfterActionInvoked( new CEvent($this, array(
      'whatever' => ...,
    )) );
  }
 
}

So now, whenever the controllers index action is invoked, the EventInterceptor will intercept the two events and raise its onEventIntercepted event with the original events embedded. The behavior, which has registered to the interceptor will be notified and will log the events.

If you don't want to intercept all events raised by your subject, you can provide a second argument to EventInterceptor::initialize(). This second parameter must be an array, which contains the names of the events that shall be intercepted. It defaults to an array with one entry "*", which means "intercept all events". So for the example above, if you were only interested in the "onBeforeActionInvoked" events, you had to modify the following:

class EventLoggerBehavior extends CBehavior
{
  [...]
  public $events = array('*');
 
  public function attach($owner)
  {
    [...]
    $this->_eventInterceptor->initialize( $owner, $this->events );
    [...]
  }
 
  [...]
}
 
class SiteController extends Controller
{
  public function behaviors()
  {
    return array(
      'eventLogger' => array(
        'class'   => 'alias.to.EventLoggerBehavior',
        'events'  => array( 'onBeforeActionInvoked' ),
      ),
    );
  }
 
  [...]
}

Change Log

June 13, 2011

  • Initial release

Total 2 comments

#4205 report it
Ben at 2011/06/15 03:56pm
re: Nice

I don't see a way to catch the results of other handlers, but you can ask the observed subject for a list of attached handlers:

class EventLoggerBehavior extends CBehavior
{
  [...]
 
  public function logEvent( InterceptionEvent $event )
  {
    $interceptedEvent = $event->getInterceptedEvent();
    $subject = $interceptedEvent->sender;
 
    // get list of event handlers attached to the observed subject's event
    // (contains the callback to EventLoggerBehavior::logEvent)
    $attachedHandlers = $subject->getEventHandlers( $event->getInterceptedEventName() );
 
    [...]
  }
 
}
#4184 report it
intel352 at 2011/06/14 04:25pm
Nice

Could this be used to also log what other handlers were executed on an event, along with the results of each handler?

Leave a comment

Please to leave your comment.

Create extension
  • Yii Version: 1.1
  • License: New BSD License
  • Developed by: Ben
  • Category: Others
  • Votes: +3
  • Downloaded: 307 times
  • Created on: Jun 13, 2011
  • Last updated: never