Details on building a Flex-based dashboard with a PHP backend

Yesterday (June 1st) I wrote a blog post on how to set up an example application that I did for a webinar with Adobe and building a Flash based dashboard application (I would suggest watching it) connecting into to PHP.  Today I would like to provide some of the details of how I did all that.  I was a bit pressed for time while building the example app, and I did my standard thing, taking the Mythbusters motto to it’s logical conclusion.  But in the end I think it worked out well.  The example is complicated but a dashboard is intended to aggregate data from multiple different places and so while it was complex I also think that the attendees were able to see how and why data was processed as it was.

The dashboard application was a Flex-based app that could get summary information and batched information from a Magento based e-commerce site.  It would display a traffic summary, slightly delayed sales information (which products were selling best) and realtime notification of sales that occurred.

The way it worked was that all of the information that was going to be displayed in the dashboard was sent into one of three message queues.  That’s right.  The PHP application did not use a database. Well, it did, later on, but the actual registering of data was not done in the standard PHP way of doing a database insert.

Heresy!  No, actually I think there are a lot of problems that PHP developers solve with SQL that should be solved with message queues.  In this case, there were three things that I wanted.  I wanted traffic information, notification of a sale and the details of that sale.  But I really didn’t need to keep that information once it was processed and I didn’t care about ACID compliance or anything like that.  I basically wanted to throw data somewhere where I could get it later.  That’s where the message queue came in.

I chose ActiveMQ as my message queue.  I tried RabbitMQ but I ran into authentication issues that I didn’t have time to solve.  It was quicker to install ActiveMQ.  ActiveMQ has a feature that it shares with RabbitMQ and that is the Stomp interface.  Most message queues have some kind of binary protocol that they use to initiate communication.  But Stomp is a text based protocol.  What that means is that it is a) easy to build adapters for, and b) very easy to hack if you need one built for you.

Zend Framework has a Stomp interface, which requires some messing around with, but it also has an ActiveMQ interface that uses Stomp.  What that means is that it uses the Stomp interface but makes sure that it’s working with ActiveMQ with any “special” things that needs to be done.  ActionScript, the Flash-based programming language, also has a Stomp based interface available via a third party.  What this meant is that I could connect to a message queue and both the front end and the back end were able to interact with it.

What I wanted to do was send data into the queue that I was either going to a) retrieve directly using the dashboard, or b) pass to a PHP job for batch processing.  Messages are simple unstructured text.  A) was simple because I was just passing a notification.  B) was more problematic because I wanted to pass structured data, i.e. a log object.  But wait!  A serialized object is unstructured text!  So passing the object was no problem.  To do this I created a logger class that understood a few different classes.  We’ll start with those.

First the LogItem class

1
2
3
4
5
6
7
8
namespace log;
 
class LogItem
{
public $title;
public $url;
public $timestamp;
}

Now let’s take a look at the Logger class. (I am omitting the sales portion)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace log;
 
class Logger
{
 
private static $queues = array();
 
public function getQueue($queue)
{
    if (!isset(self::$queues[$queue])) {
        $config = new \Zend_Config_Ini(__DIR__ . '/../../etc/config.ini');
        if (!isset($config->mq->$queue)) {
            throw new Exception('Undefined queue configuration');
        }
 
        $stomp = new \Zend_Queue_Adapter_Activemq(array());
        $stomp->setQueue(
            new \Zend_Queue(
                array(
                   'name'=> $config->mq->$queue->endpoint
                )
            )
        );
 
        self::$queues[$queue] = $stomp;
 
    }
    return self::$queues[$queue];
}
 
public function log($queue, LogItem $log)
{
    $this->getQueue($queue)->send(serialize($log));
}
}

 

This class works in conjunction with a config file like this

1
2
3
4
mq.traffic.endpoint = /queue/traffic
mq.traffic.scheme = tcp
mq.traffic.host = localhost
mq.traffic.port = 61613

The Logger object receives a request to log a LogItem object on a specific queue.  It then calls getQueue() which looks to see if a configuration exists for that queue.  If it does it creates a new ActiveMQ adapter object, sets its queue name and returns it.  Then the log() method serializes the $log object and passes it to the send() method of the ActiveMQ.

At this point the data is in the message queue and you’re done, right?

Nope.  Now you need to pull it out of the queue.  On the PHP side it is pretty much the same as queuing it.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$stomp = new \Zend_Queue_Adapter_Activemq(array());
$stomp->setQueue(
  new \Zend_Queue(
    array(
      'name'=> $config->mq->$queue->endpoint
    )
  )
);
 
while (true) {
  $msgs = $stomp->receive();
 
  foreach ($msgs as $msg) {
    /* @var $msg Zend_Queue_Message */
    $logItem = unserialize($msg->body);
    // Do your thing
  }
}

 

In here we create our connection to the queue daemon and state the queue name.  Then, in this loop, we state that we want to receive data from the queue by calling the receive() method.  Generally a message queue will allow a connection to sit idle indefinitely until there is data on the queue.  But for PHP, since most are not long running programs, you will want to have a timeout.  Leaving the first argument null on the receive() call will set the timeout to be the default, but you probably should set it relatively low.  The receive() method will return an object of Zend_Queue_Message_Iterator which implements Iterator which means it can be used in a foreach loop.  Each item in the object returned will be an instance of Zend_Queue_Message which contains your data along with some meta data.  I didn’t care about the meta data so all I did was unserialized the body of the message which then gives the instance of the object that I had passed in to the queue earlier.

That covers about 1/8th of what I still have left to talk about concerning the webinar I did with Adobe.  But one of the more interesting things I did was use a message queue to communicate between a front end PHP application, a back end PHP application and a front end Flex application (which I didn’t get to).  I personally think that PHP developers should spend a little time looking at asynchronous communication and examining whether their applications could use it.  Perhaps this will help you get on your way.

0 comments

Post Navigation

Web Analytics