Connecting PHP to ActionScript and Flex using Stomp

In yesterday’s post I talked a little bit about some of the details on how I used messaging to connect a front end on demand request to a back end scheduled data processing mechanism.  In this post we’re going to talk about how to send data from a web page to a running Flex application without using HTTP.  It is really quite easy.

First up you need a message queue that supports Stomp.  Stomp is a text-based message queue protocol that a good number of message queue applications support.  I chose ActiveMQ, mostly because of authentication issues I was running into with RabbitMQ that I didn’t have time to solve.  Stomp isn’t turned on automatically so you need to change some config settings.  I have details at my first post on how to do that.

In my demo I wanted to have real time notifications of when a sale came in from a Magento application.  So the first thing to do would be to create a queue endpoint in ActiveMQ that you can send the data to.  That’s the easy part.  Next I needed to create an observer that would be triggered when a sale is made.  Magento uses an event based system and so hooking in to that was relatively easy.  The observer looked like this:

 

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
use vo\SaleItem;
use vo\Sale;
use log\Logger;
 
class Zend_Dashboard_Model_Observer
{
 
  public function logSale(Varien_Event_Observer $observer)
  {
 
    $session = Mage::getSingleton('checkout/session');
    $orderId = $session->getLastOrderId();
    $order = Mage::getModel('sales/order')->load($orderId);
    $items = $order->getAllItems();
 
    $sale = new Sale();
    $sale->date = time();
    $sale->total = $order->getTotalDue();
    foreach ($items as $item) {
      $sItem = new SaleItem();
      $sItem->name = $item->getData('name');
      $sItem->price = $item->getData('price');
      $sItem->qty	 = $item->getData('qty_ordered');
      $sale->items[] = $sItem;
    }
    $logger = new Logger();
    $logger->registerSale($sale);
  }
}

 

The Logger class that it calls is where the messaging occurs.

 

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
namespace log;
 
use vo\Sale;
 
class Logger
{
 
  private static $queues = array();
 
  /**
  *
  * Retrieves a queue object based on the name
  * @param string $queue
  * @return \Zend_Queue_Adapter_Activemq
  * @throws Exception
  */
 
  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 registerSale(Sale $sale)
  {
    $queue = $this->getQueue('sales');
 
    $date = new \Zend_Date();
    $date->setTimestamp($sale->date);
 
    $output = sprintf(
      "%s Total: \$%s Items: %d",
      $date->toString(\Zend_Date::DATETIME_MEDIUM),
      $sale->total,
      count($sale->items)
    );
    // Send notification
    $queue->send($output);
  }
}

 

The workings of the logger and the configuration are described in yesterday’s post.  For this notification all I needed was a simple text message stating that a purchase was made and how much.  I want to figure out how to send an AMF serialized object to a Flash front end but I haven’t had time to do that yet.  So a simple text message will do.

Once the message is in the queue we now need to retrieve it in our Flex application.  I used AS3Stomp for the connection.  What I did was create a VGroup which could pretty much be inserted on any visual component. In there I created a list element that would be populated with the individual messages that were received from the queue.  The data provider for the list is a simple array of the individual messages which had been received.

<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    width="100%" height="100%" horizontalAlign="center"
    creationComplete="vgroup1_creationCompleteHandler(event)"
    xmlns:stomp="org.codehaus.stomp.*">
    <fx:Script>
    <![CDATA[
    import flashx.textLayout.elements.ListElement;
    import mx.events.FlexEvent;
    import org.codehaus.stomp.Stomp;
    import org.codehaus.stomp.event.MessageEvent;
    import valueObjects.Sale;
 
    protected function vgroup1_creationCompleteHandler( event : FlexEvent ) : void {
      stomp.connect();
      stomp.subscribe("/queue/sales");
    }
 
    protected function stomp_messageHandler( event : MessageEvent ) : void {
      var str : String = event.message.body.readUTFBytes(event.message.body.length);
      var data : Object = new Object;
      data.label = str;
      salesMessages.addItem(data);
    }
  ]]>
 
  </fx:Script>
  <fx:Declarations>
    <stomp:Stomp id="stomp" message="stomp_messageHandler(event)" />
    <s:ArrayCollection id="salesMessages" />
  </fx:Declarations>
 
  <s:Label text="Sales"/>
  <s:List id="saleList" width="100%" height="100%" color="#000000" dataProvider="{salesMessages}" fontSize="13"></s:List>
 
</s:VGroup>

The stomp object was provided as a declaration with a method associated with it’s “message” event which is thrown every time a new message comes in.  When a new message comes in the event is fired and the messageHandler() method is called where we read the message data into a string and attach it to an object with a label property.  Then we add it to the data provider at which point the list will update itself with the new value.

Easy.

0 comments

Post Navigation

Web Analytics