Creation of a panel for the Web Debug Toolbar and usage of the Event Dispatcher

0 gravatar By Grégoire Marchal - 02/09/2011

Let's write a small tutorial today. We'll create a panel for the WDT (Web Debug Toolbar) that will display the list of the SOAP WebService requests (but feel free to adapt it to whatever) executed on the current page, in the style of the Doctrine/Propel panels displaying SQL queries. Its content will be fed by events managed by the Event Dispatcher.

For the creation of the panel skeleton of sfWebDebugPanelSoapClient, I let you follow the official tutorial. When it's done, we'll fill this panel using the Event Dispatcher, by generating events. So let's go to the MySoapClient class, my class that generates the things I want to log.

First I create the method that creates and dispatches the event:

  /**
   * Dispatch a 'soapclient.log' event (used by web debug panel)
   *
   * @param SoapCommand $oCommand  The executed command
   * @param int         $iDuration The duration of the soap call
   */
  protected function dispatchEvent($oCommand, $iDuration)
  {
    $this->context->getEventDispatcher()->notify(new sfEvent($this, 'soapclient.log', array(
      'command'  => $oCommand,
      'duration' => $iDuration,
    )));
  }

As you can see, I create an event which type is "soapclient.log", about the current object ($this), and I provide some additional parameters that I'll display later in my panel... Then I use the Event Dispatcher to notify the objects that listen the "soapclient.log" events that there's a new one!

Then we have to call this method. In my case, it's just after the WebService call.

    $iTime = microtime(true);
    // do your stuff...
    $this->dispatchEvent($oCommand, microtime(true) - $iTime);

Now let's go back to the sfWebDebugPanelSoapClient class, to tell it to listen to that kind of event. So we'll override its constructor to connect a method to that event.

  protected $aEvents = array();

  public function __construct(sfWebDebug $webDebug)
  {
    parent::__construct($webDebug);
    $this->webDebug->getEventDispatcher()->connect('soapclient.log', array($this, 'listenForSoapClientLogs'));
  }

  /**
   * Listens to soapclient.log event and record them
   *
   * @param sfEvent $event
   */
  public function listenForSoapClientLogs(sfEvent $event)
  {
    $this->aEvents[] = $event;
  }

In the constructor, we ask the Event Dispatcher to call the "listenForSoapClientLogs" method of our class as soon as it receive a "soapclient.log" event. In this method, we just store each event in an array of our class.

So we have everything we need now. We just have to display the informations in our panel.

  /**
   * Get the html content of the panel
   *
   * @return string $html
   */
  public function getPanelContent()
  {
    return '
    <div id="sfWebDebugSoapClientLogs">
      <ol>'.implode("\n", $this->getSoapClientLogs()).'</ol>
    </div>
    ';
  }

  /**
   * Retrieves events as html
   *
   * @return string
   */
  protected function getSoapClientLogs()
  {
    $aRet = array();
    $i = 1;
    foreach ($this->aEvents as $oEvent)
    {
      $aParams = $oEvent->getParameters();

      $oClient = $oEvent->getSubject();
      $oCommand = $aParams['command'];

      $sHtml = '
        <li>
          ' . get_class($oCommand) . ' (' . round(($aParams['duration'] * 1000), 2) . ' ms)
          ...
        </li>
      ';

      $aRet[] = $sHtml;
      $i++;
    }
    return $aRet;
  }

That's all folks! Now we have a smart panel to debug a SOAP client, or whatever you want!

Soap Debug Panel

Back home

Comments (0)

Comment