Tag Archives: Flash

Passing typed ActionScript objects to Flex using PHP and a message queue

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.

Zend_Amf and Flash Remoting – Some things to note

Having done a little bit of work with Flash over the past several weeks there are a couple of things I've discovered as I've worked through some practical examples.  There's only really one thing signficant, but a couple of things that you need to be aware of when doing Flash remoting with Zend Framework.

Simple interface? Easy. Useful interface? Just a little harder.

In other words, with a simple architecture it's easy to do.  In a more useful architecture there are some things to be aware of.

When dealing with POPOs (Plain Old PHP Object) remoting is stupid simple.  What a POPO is is a PHP object that simply defines its properties as public and doesn't have much integration with the surrounding application. However, when you start trying to integrate within a larger framework, application or module (such as Zend_Db) then it gets a little more difficult.  Not horribly difficult, but you might need to add an extra line or two in your service class to properly translate things.

Introspection in Flash Builder

This is the key to working with Flash apps.  Flash Builder allows Flash developers to call remote objects and place the results in a native Flash object. Flash Builder can take a look at the return value of a remote call and automatically create a native object based off of that.  This is really great for POPOs, but…

Not as good for Zend_Db objects

But don't let that fool you into thinking that it's problematic.  Before I tell you why, let's go over some of the issues when you use a Zend_Db object.

Problem #1: The AMF Serializer does not properly serialize Zend_Db_Table_Row_Abstract objects as of ZF 1.10.4.  This will be changed in 1.10.5 with a very simple fix.  In fact, it's possible that by the time you're reading this it may not be an issue any more.

The reason for this is that the AMF serializer does a foreach loop over the objects that it's going to be serializing to write each property to the wire. What this does for a POPO (fun to say, isn't it?) is that it iterates over publicly defined properties of the object.  However, with a Zend_Db row object the data is stored in a protected array and not iterate-able.  The data does not have public accessibility. The change to make introspection work from front-end to backend is done by having the Zend_Db_Table_Row_Abstract class also implement IteratorAggregate and return the value of $this->_data.  Once this has been completed there will be front-to-back introspection.

Problem #2: New Zend_Db objects are not created using a constructor.  They are created by calling fetchNew() on a DB table object. But the AMF serializer will create the object using the contructor. The problem here is that when you try to save a Zend_Db_Table_Row_Abstract based object the table object will not have been defined.  The way around this is to actually use one of the hooks in the row class called init().

protected $_tableClass = 'Model_DbTable_Census';

public function init()
{
    if ($this->_getTable() == null) {
        $this->setTable(new $this->_tableClass());
    }
}

What this does is check to see if the table has been defined.  If it has not, the individual row object will create one for itself.  This could also technically be done in an overarching manner with an abstract model definition to handle it.

One question you might have is "whose fault is this?" Is it Zend_Db or Zend_Amf?  The actual answer is neither.  Both are operating fine within their own patterns.  What this is is a discongruency of patterns.  And so we need to handle that with the code in the init.  The other caveat is that with this functionality you cannot have a direct call to the save() method for both create and update operations.  For one of them you will need to get an instance of the class in the service object prior to calling the save operations.  In my third part of this series I will show you what I mean.

Using a service object

While it might seem reasonable to simply provide direct access to your individual models there are actually two reasons why this will not work or is not a good idea.

1) Flash Builder requires your data model class files to be located in the document root.  This does not work well with a proper Zend Framework application

2) Dependencies will be difficult to manage.  In other words, directly calling a class called User may work fine but any additional data, such as permissions, should have its logic defined on the server side.  Otherwise it will be waaayyy too easy to hack. 

Having a service object allows you to put a very thin class in the document root so Flash Builder can introspect it (I'm hoping this requirement will be removed at a later date) and it also limits the damage that an end user can do.

Conclusion

Having seen some of these issues am I concerned at all about integrating a native Flash and a native ZF application?  Not really.  Understanding the reasons why some of the problems existed took a little bit of time, however the implementations are actually really easy.  There was one bug and it will be fixed in ZF 1.10.5 with about 3 lines of code.  So all in all, now that I'm over the hurdle I am really looking forward to doing more ZF work with AMF and Flash.

Downloads.  Everyone wants downloads.  Once I have finished the third part of this series I will be making the fully functional application available for download as a Zend Studio/PDT project.

For the Flash developers – building your remote endpoint

While I am not a great Flash developer… OK I'm not even a good one, I have been recently been looking at ways of integrating Flash and PHP with the release of Flash Builder 4.  I think that PHP is a great way for Flash developers to access their backend systems.  This is not because I have anything against any other technologies that a Flash developer might connect with, but instead it is because PHP is a great language to use when another language is your forte.

What I mean by that is that if Flash is your primary programming language PHP is a good way to provide remote access to your data because it doesn't require you to be an expert.  You can throw PHP at the wall and it will stick.  So what we're going to do in this article is show how little of an expert you really need to be.

One of the ways you can get away without being an expert is to use a framework.  In this case, I will be using Zend Framework as the means to provide my data access layer.  In fact, this example is a great one because it shows the use-at-will architecture of Zend Framework.  I believe that this is one of the places where Zend Framework rises above the others.  If you're looking for stupid simple database access and basic application functionality then Zend Framework might not be right for you.  But if you want the ability to use the components you need to make your life easier, ZF is a good choice.

This article is going to end up being a two part article.  This first part is intended for the Flash developer who wants to be able to set up a basic CRUD application.  The CRUD application is one that Ryan Stewart or Kevin Hoyt (or someone else) wrote that was designed to showcase connecting to PHP with Flash.  However, the example was written from the point of view of a Flash developer and what I wanted to do was take that same functionality and "Framework-ize" it.  In other words, make it very testable and drastically simplify the code.  The application is a simple one that provides access to census data.

LayoutThe new backend will use Zend_Application for its bootstrapping and setup.  Thankfully, if you are using Zend Studio, you can quite easily set this project up.  Select the PHP Explorer and type CTRL-2 followed by "zf create project CService".  This will create a basic structure of an MVC application, though we will only be using the M (or Model) part of the MVC design pattern.  So, we're using the M pattern.  If you do not have Zend Studio you can do the same thing with Zend_Tool (wha?) or you could simply create a project structure that looks like what is on the right(oh).

I had mentioned bootstrapping.  What that does is set up the context for the request so you don't have to do it.  You see in the "application" directory a Bootstrap.php file.  This contains the class that Zend_Application will use to bootstrap a request and it looks like this.


class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    public function _initAutoload()
    {
        $al = new Zend_Application_Module_Autoloader(
            array(
                'namespace'        => '',
                'basePath'        => dirname(__FILE__)
            )
        );
    }
}

What this is doing is setting up the autoloader.  The autoloader is used to load files for individual classes that are required to execute an individual request.  This can get more complex, but likely you, as a Flash developer, will not need to run into the need for that.  Then in our configs directory we will need to spell out some basic database configuration settings.  I put it in a file called configs/application.ini.

[production]
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
resources.db.adapter = "pdo_mysql"
resources.db.params.host = "localhost"
resources.db.params.username = "root"
resources.db.params.password = ""
resources.db.params.dbname = "census"
resources.db.isDefaultTableAdapter = true

ModelsThe next thing we need to do is set up our data access layer.  This is not the layer that you will be calling.  This is the layer that the service layer will call to handle the database calls.  There are two files that you need to create.  One to represent the table and another to represent a row.  The one two represent the table is in the models/DbTable/Census.php file and its code looks like this.


class Model_DbTable_Census extends Zend_Db_Table_Abstract
{
    protected $_rowClass = 'Model_Census';
    protected $_name = 'census';
}

$_name is the name of the table as spelled in the database.  $_rowClass is the name of the class that represents the row.  Speaking of, that file is stored in models/Census.php and it looks like this.


class Model_Census extends Zend_Db_Table_Row_Abstract
{
    protected $_primary = 'id'; 
}

What this is doing is stating that the primary key is the column named "id".  Speaking of the table.  Here is the create statement.

CREATE TABLE `census` (
  `age` varchar(3) DEFAULT NULL,
  `classofworker` varchar(255) DEFAULT NULL,
  `education` varchar(255) DEFAULT NULL,
  `maritalstatus` varchar(255) DEFAULT NULL,
  `race` varchar(255) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf-8

Congratulations, you now have you model layer.

ServicesThe next layer you need to build is the service access layer.  This is done after you have created your PHP data service using the Flash Builder components.  There are plenty of places you can go to on information on that, or you could also look at my previous posting on Flash called Flex and Zend Framework – Part 1.  Once you have created the data access integration point in Flash Builder we can go back to PHP.  If you look at our first image you see that there is a directory called "public".  This is the directory that the service endpoint should be installed into.  In that service endpoint directory there is a file called amf_config.ini.  Here is where you need to set up the directory where your service class is going to be.  I simply named the directory "services".  The gateway.php file was put there by Flash Builder but the bootstrap.php was not.  We will look at bootstrap.php in just a bit.

The next thing we want to do is define our service class.  This is the class that will implement the functionality that we want to actually call.  It is placed in the "services" directory in a file called CensusService.php.  I won't put the whole class in, but from the example you should see what it's doing.


class CensusService
{

    public function getAllCensus()
    {
        $tbl = new Model_DbTable_Census();
        return $tbl->fetchAll()->toArray();
    }

    public function getCensusByID( $itemID )
    {    
        $tbl = new Model_DbTable_Census();
        return $tbl->find($itemID)->current();
    }

    public function createCensus( $item )
    {
        $tbl = new Model_DbTable_Census();
        $row = $tbl->fetchNew();
        $row->setFromArray((array)$item);
        $row->save();
        return $row->id;
    }
}

Notice the very few lines of code?  This is the benefit of using something like Zend Framework.  No database access or anything.  That has all been taken care of by Zend_Application and the configuration file that we wrote.  The only caveat is that the return value MUST be an array.  So we put toArray() at the end.

Well it's all working now, right?  Maybe.  To do that we need to now test it.  That is where Unit Testing comes in.  Using Unit Testing on the PHP side allows us to test to make sure that any changes made to the codebase don't break somewhere else.  To do the Unit Testing I am going to use PHPUnit integration in Zend Studio.  You could also use the regular PHPUnit if you like.

Remember that "tests" directory that we had created earlier on?  Well, in there you can create another directory called "services" and in that directory put a file called CensusServiceTest.php.  In that file is where you write all of your Unit Tests.  I have a video you can watch called "Unit Testing Zend Server PHP Job Queues" that goes over some of the basics.  The Unit Tests (with several of the tests removed for brevity) start with including the files to be tested, setting up the test and then calling the individual functions, comparing the results to what is expected.

require_once realpath(dirname(__FILE__).'/../application/bootstrap.php');
require_once realpath(dirname(__FILE__).'/../../public/AMFService/services/CensusService.php');

/**
 * CensusService test case.
 */
class CensusServiceTest extends PHPUnit_Framework_TestCase {
    
    /**
     * @var CensusService
     */
    private $CensusService;
    
    protected function setUp() {
        parent::setUp ();

        $this->CensusService = new CensusService();
    
    }
    
    /**
     * Tests CensusService->getAllCensus()
     */
    public function testGetAllCensus() {
       
        $ret = $this->CensusService->getAllCensus();
        $this->assertGreaterThan(
            0,
            count(
                $ret
            )
        );
        $this->assertType(
            'array',
            $ret
        );
    
    }
}

What we are doing is asserting that this code will return more than one census item.  Now for each piece of functionality you should add another function that starts with the word "test" and verify that the return values are what you would expect.  For our test on collections of information we want to assert both that the count is greater than zero and that the return type is an array, not a result set.

There is now one last thing we need to do before going on to the next part and integrating our front end Flash application.  That is to bootstrap the remoting requests.  That is done by adding a require call to the top of Flash Builder's gateway.php file.

require_once 'bootstrap.php';

ini_set("display_errors", 1);
// ..etc.

Then we need to actually create the file that does the bootstrapping.


// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../../library'),
    get_include_path(),
)));

/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap();

Most of what you see here is mostly not important as a Flash developer.  What this is basically doing is setting the application path directory, defining the environment as production, setting the include path to include a library path (which you could probably remove) and then loading and executing the Zend_Application class with the current configuration.  All this is really doing is setting up those database models that we had defined earlier on.  While for a simple example this is a fair amount of overkill, it actually makes your life much easier as you start to add database tables and service layers.

That takes us to the end of the backend part of building a CRUD Flash application with PHP.  Stay tuned for when we integrate the frontend.

The Zend Studio projects can be downloaded here.

Little Schrade asks about Flash and Zend Framework

Following closely on the heels of my previous blog posting on how to create a basic Hello World application using Flash RIA with Zend Framework based remoting I have created a video showing how to do exactly what I just did in the blog posting.  Additionally, I have a compressed copy of the workspace I used so you can download it and run it in your own copy of Zend Studio.  You will probably need to change a few settings to make it work in your IDE.  Be forewarned that you will likely also need the Flash Builder 4 plugin installed.  The 60 day trial should be more than enough to let you do that.

Flex and Zend Framework – Part 1

It would be a fair statement to say that I have not paid attention to Flash for several years.  Obviously I know that those awesome interfaces for movie web sites are made in flash, as are those annoying video ads that start screaming at you as soon as you load up a page, competing with Megadeth on Rhapsody, cranked out on the 700 watts of power I have in my office.  But the last time I really looked seriously at Flash was almost a decade ago and I was thrilled at tweening widgets from one place to another.  Unfortunately, there’s not really any benefit to tweening a text box. Cool? Yes. Practical? No.  So I never really picked it up.  Plus I was cheap.

That is the reason why I had not really been paying attention to Flash for the past several years.  I generally don’t look into something if it’s cool.  I look into something if it is practical.  Flash, generally, is meant to be, well, flashy.  And it is.  But for someone such as myself, I didn’t think I had much of a reason to pay attention.  Until now…

Given that Zend has had a professional relationship with Adobe for a while, I have been looking for the time to actually dive into what Flash was offering so I could make some kind of judgement call on it.  I realize that I am a little behind the times on it, but bear with me for a second.  A few weeks ago I decided that it was time for me to learn.  Partially it was because I wanted to learn it and partially it was because I needed to speak at Flash Camp Boston about integrating PHP and Flash.  There are few better motivators to learn something as when you are expected to be some kind of expert on it… or at least kinda know what you’re talking about.

With that in mind, I would like to talk about some introductory topics on what it would take to get a basic Flash/Flex application up and running.  This will be part 1 of an X part series.  I don’t know how many parts there will be, but I would expect that there would be a few.  We’ll probably keep on going until traffic to the postings starts to die down.  :-)

The first thing that you will want to do is get a copy of Flash Builder 4.  It was recently released and can be downloaded as a plugin for Zend Studio (technically, Eclipse).  You can download it from the Adobe website.  You can download it with a 60 day trial license.  That’s right.  60 days.   That is more than enough time to see if it’s something you want to do.  When I downloaded it, I did it as an Eclipse plugin on a fresh install of Zend Studio and it works like a breeze.

Once you’ve installed it, start up your instance of Zend Studio or PDT and switch to the new Flash perspective.  From there you can easily create a new Flash application by right clicking in your Package Explorer and selecting “New”.

New Flex ProjectWhen creating a new project using Flash Builder you will do so as a Flex Project.  The difference between Flex and Flash is kind of like the difference between Zend Framework and PHP.  Flex is a framework, Flash is the language/deployment platform.  Flex is the thing that really makes Flash practical as a more general front end. You can still make cool web sites for movies and recording artists, but it is Flex that really makes Flash worthwhile in my book because it adds a bunch of widgets that have practical business use… among other things.  So we create a Flex Project.

New Flex ProjectThe next step in the wizard is to set up some of the global options for your new Flex project.  The first two are self explanatory.  The next ones need a little explanation.

The first is the application type.  With Flash applications you have two different deployment platforms.  You can either run in the traditional web browser or you can also run it as a desktop application in Adobe AIR.  I don’t know exactly why it’s called AIR, but it seems eerily similar to Rich Internet Application.  Basically, that’s what it is.  It’s a desktop platform for Flash applications.  Apparently it is quite easy to move between the two.  I have not personally had a need to do that yet, so I don’t know exactly how it’s done.  But I have seen video of someone who took an AIR application and in about 15 seconds changed it to a mobile application.  Prett sweet.

I have personally built a web-based application using Flex and I’m in the middle of building one that is AIR based, both of which are used for this blog.  We’ll see if they end up being useful examples for PHP developers.

After the Application Type is the Server Technology.  This is where my primary interest lies. You can choose from ASP.NET, J2EE, Cold Fusion and PHP as your server technology.  Obviously, we are going to choose PHP.  What this means is that you can use Flash/Flex to create a very interactive front end for either your desktop or a browser while being able to keep your server side technology as PHP.

New Flex Project The PHP integration is done using the Zend Framework’s Zend_Amf components.  In order for Flash Builder to communicate with PHP it will install Zend Framework in a directory in your document root.  We can see that in the “Configure PHP Server” screen shot.  What it is doing is asking for the web root and the root URL so it can verify that it can reach its introspecter.

The introspecter is basically a Zend_Amf based gateway that can look at a certain class file and retrieve its class definition and create an AMF-based service which can then be worked with from within the Flash Builder IDE.  For applications that keep their class files in the document root of the web server this means that you can easily introspect those classes and interact with them in the IDE.  This is done via a file that the Flash Builder IDE installs in the Output Folder called gateway.php.  It contains a basic Zend_Amf_Server implementation.  However, if you have your code outside of the document root (which is generally recommended), the AMF remoting integration in the IDE can be a little problematic.  This is a bit of a problem as one of the really neat features of Flash Builder 4 is that you can take widgets that you place on the Flash canvas and inject data from your test environment in them.  You can kind of do this if your code is outside your document root or if you are using an MVC-based application but you need to hack up the generated code and Flash Builder likes to overwrite those hacks.  I will show you what you need to do, but first let’s do it the Flash Builder way.

MXML

No, not the number 2060 in Roman numerals.  Flash Builder uses an XML format to define its class structure, which I have to admit is kind of cool.  One of the benefits of this is that it seems to use XML validation to do syntax checking for the properties of various visual elements.  A basic MXML file will look something like this.

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:WindowedApplication>

As you can see; XML. But this is kind of useless. What we need is a label. The label will eventually be hooked up to an event that will cause it to look up the current time using an AMF service call. But before we set up the web service call let’s first set up our layout.

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
    <s:Label x="5" y="47" width="190" id="timeLabel"/>
</s:WindowedApplication>

You might be wondering how I knew to use s:Label.  It is because I dragged them from Components view in the IDE to the canvas.  Then I put the ID timeLabel in afterwards.  That will be important later on.  One of the really nice things about MXML is that its syntax very similar to HTML because of its relationship to XML, both of which are, of course, related to SGML.  What this means is that setting up the visual components to a Flex application is actually very easy for basic applications if you know how to use XML.

Remoting

The next step is to get the current time from the server.  To do that I will create a class called Time with a method called getTime() which will return a formated date/time string.  To make things easy for Flash Builder we will put it into the Output Folder which is C:workspaceBlogpublicEschradeReporting-debug for this application.

class Time
{
public function getTime()
{
return date('r');
}
}

Now we need to set up Flash Builder.  First we need to select the remote service type.

Selecting PHP

Then we need to introspect the class

Introspecting PHP

Next it will tell you which methods it has found.

Introspected method

At that point you are ready to use it.  You should be able to see it in the Data/Services view in Zend Studio.  You can right click on it and click Test Operation.  That will allow you to make sure that it’s working properly.

Testing the remoted object

As you can see, we were able to get a formatted response.  So now all that’s left is to bind this service to our label.  To do this we click on the getTime() service call and drag it on top of the empty label field.  When we do that we get a box like this.

Binding to the label

After you click OK, the IDE then adds a bunch of code to your file.

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:time="services.time.*">
    <fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.controls.Alert;

protected function timeLabel_creationCompleteHandler(event:FlexEvent):void
{
getTimeResult.token = time.getTime();
}

]]>
</fx:Script>
    <fx:Declarations>
<s:CallResponder id=”getTimeResult”/>
<time:Time id=”time” fault=”Alert.show (event.fault.faultString + ‘n’ + event.fault.faultDetail)” showBusyCursor=”true”/>

<!– Place non-visual elements (e.g., services, value objects) here –>
</fx:Declarations>
<s:Label x=”5″ y=”47″ width=”190″ id=”timeLabel” creationComplete=”timeLabel_creationCompleteHandler(event)” text=” {getTimeResult.lastResult}”/>
</s:WindowedApplication>

There are a couple of things to go over here.  First is fx:Script.  This is the ActionScript code that is actually executed to get the call.  However, what you might notice is that it is not the value of the getTime() call that is returned, but a token.  These calls are done asynchronously.  So rather than blocking and waiting for a result, a token is passed to a special declaration called a CallResponder.  The CallResponder is just a declaration that is an integration point for data.  It acts as the meeting place for the service call and whichever listener is listening on the CallResponder.  That listener is denoted by “{getTimeResult.lastResult}” on the label widget.  So here is the order of execution.

  1. timeLabel_creationCompleteHandler() is registered as the handler for the creationComplete event.
  2. The createComplete event is fired and timeLabel_creationCompleteHandler is called
  3. The time.getTime() method is called which returns a token (we’ll see this code in a bit)
  4. The async call to time.getTime() completes and the text property of timeLabel is updated to the value in the CallResponder getTimeResult.  lastResult is a property that contains the last service call result.

One last thing to note is the first thing you might have seen.  The time.getTime() method call has not been defined anywhere yet.  Or has it.  If we look at the s:WindowApplication element we see a new attribute called xmlns:time.  What this does is define the variable “time” to refer to services.time.*.  We will look at this code in just a bit.

When we run the Flash application in AIR we get the following output.

The final product

Working with ZF MVC

Now that we’ve done it the Flash Builder way we need to make some modifications to make it work with a Zend Framework MVC application.  Unfortunately, it won’t work out of the box.  Yes, Flash Builder installs Zend Framework, but it doesn’t do it in the context of an MVC application.  It also doesn’t seem to check if Zend Framework is currently installed and places its own instance of Zend Framework in its Output Folder.  This doesn’t affect your application, but you need to be aware of it so you can strip it out when you go to deploy your application.

In the earlier example we saw a reference to time.getTime().  That is defined in a java-like package, similar also to a PHP namespace.

The service

The actual code is defined in the _Super_Time.as file.  This is a pure ActionScript file whose syntax is very similar to Java.  In it is the code that actually makes the call.  There is a fair amount of autogenerated code in there.  I’ll display it but only one line of code is actually important from a Zend Framework perspective.

package services.time
{
import mx.rpc.AsyncToken;
import com.adobe.fiber.core.model_internal;
import mx.rpc.AbstractOperation;
import mx.collections.ItemResponder;
import mx.rpc.remoting.RemoteObject;
import mx.rpc.remoting.Operation;
import com.adobe.fiber.services.wrapper.RemoteObjectServiceWrapper;
import com.adobe.fiber.valueobjects.AvailablePropertyIterator;
import com.adobe.serializers.utility.TypeUtility;

[ExcludeClass]
internal class _Super_Time extends RemoteObjectServiceWrapper
{

// Constructor
public function _Super_Time()
{
// initialize service control
_serviceControl = new RemoteObject();

var operations:Object = new Object();
var operation:Operation;

operation = new Operation(null, “getTime”);
operation.resultType = String;
operations[“getTime”] = operation;

_serviceControl.operations = operations;
_serviceControl.convertResultHandler = TypeUtility.convertResultHandler;
_serviceControl.source = “Time”;
_serviceControl.endpoint = “http://eschrade/HelloWorldFlex-debug/gateway.php”;
_serviceControl.destination = “Time”;

model_internal::initialize();
}

public function getTime() : AsyncToken
{
var _internal_operation:AbstractOperation = _serviceControl.getOperation(“getTime”);
var _internal_token:AsyncToken = _internal_operation.send() ;

return _internal_token;
}

}

}

The _serviceControl.endpoint is the URL that the Flash app will go to get its information.  To make this work with a Zend Framework application we need to change it to where our Zend_Amf_Server implementation is.

First our model, in /application/models/Time.php

class Model_Time
{
public function getTime()
{
return date('r');
}
}

Then our controller in /application/controllers/ServiceController.php

class ServiceController extends Zend_Controller_Action
{
public function amfAction()
{
$srv = new Zend_Amf_Server();
$srv->setClass('Model_Time', 'Time');
echo $srv->handle();
}
}

Setting the alias “Time” for “Model_Time” is necessary because it matches the source and destination in our ActionScript file.  Then what we do is go back to our _Super_Time.as file and change the endpoint to

_serviceControl.endpoint = "http://eschrade/service/amf";

When we run it again, we get the same output.

Application Output

If our service endpoint defintion changes, meaning that our ZF model has some methods added or removed, then we need to re-introspect it.  To do that we will need to copy our model file to the Flash Output Folder directory and remove any pseudo-namespacing, such as Model_, reinstrospect it, delete it, and then go back in to the _Super_Time.as file and re-set the endpoint.  It’s a little annoying, but it does work and it’s not that big of a deal if you are working on classes whose public structure won’t change much after the first introspection.  But it is something to be aware of if you are using an MVC application as your endpoint or if your class is outside of the document root.  Zend_Amf allows it, as does the gateway.php file that Flash Builder adds to the document root.  But it is the wizard in Flash Builder seems to require that any introspected files need to be in the document root.

That said, I have been working with Flash/Flex for several weeks and I am quite intrigued by many of the possibilities.  Over the next little while I will be adding to this series as I have time and inspiration.  But hopefully, this is enough to get you started.

 

[UPDATE]

Now I have 1020 watts of power in my office

Web Analytics