Last week I wrote up a few blog posts (here, here and here) about creating a Flex based dashboard that utilized message queues to pass data. It was a really fun example to write but there was one thing I did not get to implement. What I wanted to do was use the sales notification mechanism to pass PHP objects to Flex using the message queue. But I could not get the unserialization mechanism to work and so I had to settle for passing a simple message that a sale had been made.
However, because you can pass typed objects back and forth between PHP and ActionScript over HTTP using Zend_Amf_Server I figured that there MUST be a way of doing it automatically. The first thing I did was create a valueObject class called Boogers (I descend into adolescence while trying new things) and called it in ActionScript so I could see the bytes that were created. The class Boogers had a property called “nutso” (again, adolescence) to which I assigned the value of “what?”. The code looked something like this
1 2 3 4 5 6 7 8 9 10 | var bgrs : Boogers = new Boogers; bgrs.nutso = "what?"; var baobj : ByteArray = new ByteArray; baobj.writeObject(bgrs); var ints2 : String = new String(); baobj.position = 0; for (var i : uint = 0; i < baobj.length; i++) { var b : uint = baobj.readByte(); ints2 += b + " " ; } |
This resulted in the bytes
1 | 10 19 41 118 97 108 117 101 79 98 106 101 99 116 115 46 66 111 111 103 101 114 115 11 110 117 116 115 111 6 11 119 104 97 116 63 |
Then I wrote some PHP code that created a PHP object called valueObjects\Boogers, serialize it and then output the bytes so I could compare it with the ActionScript output. Note that the class name follows the same namespace definition as the ActionScript class. I wanted to have direct 1:1 relationships between PHP and ActionScript.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace valueObjects; $b = new Boogers(); $b->nutso = "what?"; $stream = new \Zend_Amf_Parse_OutputStream(); $ser = new \Zend_Amf_Parse_Amf3_Serializer($stream); $ser->writeObject($b); $output = (string)$stream->getStream(); $a = ''; for ($i = 0; $i < strlen($output); $i++) { $a .= ord($output[$i]) . ' '; } echo $a; |
The end result were the bytes
1 | 19 41 118 97 108 117 101 79 98 106 101 99 116 115 92 66 111 111 103 101 114 115 11 110 117 116 115 111 6 11 119 104 97 116 63 |
It was missing char 10. But I found out that you needed to do a newline character for AMF to work properly, so I just prepended it to my output
1 | $output = "\n" . (string)$stream->getStream(); |
So the next thing I wanted to do was send it to a message queue where ActionScript could read it using Stomp.
1 2 3 | $stomp = new \Zend_Queue_Adapter_Activemq(array()); $stomp->setQueue(new \Zend_Queue(array('name' => '/queue/data'))); $stomp->send($output); |
I ran the code and it sent the message to the message queue. On the ActionScript side I set up a Stomp handler like I did in my webinar demo and was able to receive the message. Reading the message is done by creating a method that responds to a message event generated by the Stomp library.
1 2 3 | public function processMessage(msg : MessageEvent) : void { var obj : * = msg.message.body.readObject(); } |
But the problem I ran into was that the typing of obj was always a generic Object. So I proceeded to try and figure out how to get a properly typed object passed into ActionScript. I tried several different methods but the craziest was that I tried was trying to implement a sort of null RPC call that would call com.adobe.serializers.utility.TypeUtility.convertResultHandler to do the unserializing. But no matter what, none of the methods I tried would yield a properly type ActionScript object. So I looked at the text output of the PHP output.
1 | )valueObjects\Boogersnutsowhat? |
Oh.
Notice anything?
Yep. PHP namespace separator. What did ActionScript use? Yep, a period.
To solve it I added one line to the ActionScript processMessage() method.
1 2 3 4 | public function processMessage(msg : MessageEvent) : void { flash.net.registerClassAlias("valueObjects\\Boogers", valueObjects.Boogers); var obj : * = msg.message.body.readObject(); } |
Now when it is run I get a properly typed ActionScript object that I can work on in my Flex application.