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

18 comments
lparthad
lparthad

Great article but I can't create the data service, at the time of generate sample PHP service. Here is the error and looking for help:

 

Warning: Error parsing C:\Program Files (x86)\Apache Software Foundation\Apache2.2\htdocs\ZdrojakFlexPHP-debug/amf_config.ini on line 5 in C:\Program Files (x86)\Apache Software Foundation\Apache2.2\htdocs\ZdrojakFlexPHP-debug\gateway.php on line 12

 

Fatal error: Uncaught exception 'Zend_Config_Exception' with message 'Error parsing C:\Program Files (x86)\Apache Software Foundation\Apache2.2\htdocs\ZdrojakFlexPHP-debug/amf_config.ini on line 5' in C:\ZendFramework\library\Zend\Config\Ini.php:181Stack trace:#0 C:\ZendFramework\library\Zend\Config\Ini.php(201): Zend_Config_Ini->_parseIniFile('C:\Program File...')#1 C:\ZendFramework\library\Zend\Config\Ini.php(125): Zend_Config_Ini->_loadIniFile('C:\Program File...')#2 C:\Program Files (x86)\Apache Software Foundation\Apache2.2\htdocs\ZdrojakFlexPHP-debug\gateway.php(31): Zend_Config_Ini->__construct('C:\Program File...', 'zendamf')#3 {main} thrown in C:\ZendFramework\library\Zend\Config\Ini.php on line 181

 

Thanks.

Kevin Remisoski
Kevin Remisoski

Hi Kevin. Just wanted to thank you for your great articles and also ask if you might be able to point me in the right direction here.

The problem is I have been trying to integrate Flash with Wordpress. I have succeeded in doing so and it runs just fine locally. In fact it runs just fine in production as well minus one small problem. For some strange reason the post_content column in the wp_posts table displays fine locally, but not in production so I am left with a DataGroup that displays the date, title, and no content. I know this may be beyond the scope of what you might be able to help me with, but I was hoping you might know of some resources or have an idea of why this is happening since I have been searching google relentlessly for answers and have come up with nothing.

Ryan
Ryan

Just for anyone that had trouble actually getting the _serviceControl.endpoint to work when changing to the controller'd version... this was the fix:

public function timeAction()
{
///// this was the magic powder that made it grab the amf file!
$this->getHelper('ViewRenderer')->setNoRender();

require_once APPLICATION_PATH . '/models/Time.php';
$srv = new Zend_Amf_Server();
$srv->setClass('Model_Time', 'Time');
echo $srv->handle();
}

Kumar Sekhar
Kumar Sekhar

Hi Kevin,

Thank you for starting such good article! I am PHP developer and a big fan of Zend Framework. Almost in all of my application I am using Zend only. I am interested to use Zend_AMF in my upcoming project. But I don't have idea about the Flex. My skills are currently just like a hard code developer who works on LAMP (PHP/PERL) projects only.
What do you think to learn about Flex, will that need lot of potential and effort to learn? If you can share some basic articles links to start with Flex to use in php project that will be helpful for me. Really looking forward to doing the series of tutorials for Flex.

Kevin
Kevin

Jadd,
First, I'm not a fan of code generation, ever. It's fine for generating stubs, but I usually leave it at that.

I don't have any specific best practices, but I will be speaking at Adobe MAX later this month and I will come up with a list for Flex developers.

jadd
jadd

Hi Kevin.
I'm a Flex dev and I'm spending/investing a lot of time trying to do a proper the Flex 4/Zend-amf integration. Flex4 php code introspection/generation is cool but I guess for development proposal only. On the other side the "quick start zend framework" and all the "zf creatioan" I guess is too much for Flex development omly! Do have you some kind of "best practise template" on the zend part you could share?.
Thanks a lot, roberto.
Thanks

George
George

Kevin, Thanks for responding so quickly. You're right. I need to spend some time on the Zend config process and will take your advice. To be honest, I've been spending time on FBuilder, AS3, Flash, and MXML. I am impressed with MXML and it's integration with AS3. It was unrealistic to think I could add Zend without some work. BTW, I'm a computer scientist (20 yrs...BS CS & MS Software Engineering) so I really appreciated your screening method with the binary test. It actually made me think on the bit level, which I haven't done for awhile. Very clever. Best regards and have a good day. I'll send you some links when I can. Geo.

George
George

I seemed to have exceeded the word limit. Here's the rest of my comment: I found these two directories in zendDB under my docRoot. I assume this was generated, along with an amfphp directory by either FBuilder or the ZServer installation. My questions are: Should I ignore the FBuilder ZFramework and use the one under the ZServer root? Do I need to create the above mentioned directories, and if so, where? I haven't been able to figure out where to define the endpoint in your example successfully. I could go on but I don't want to exceed the limit again. Thank you again. Geo.

Kevin
Kevin

George,
Sorry for cutting off your comment. I'm going to increase the size of my comment field (and actually do length validation on it).

This example uses a Zend Framework MVC-based application which has those directories laid out. For information on this you can go to the Zend Framework MVC Quickstart. http://framework.zend.com/manual/en/zend.controller.quickstart.html

George
George

Hello. Thank you for writing this article. It's one of the few I've found that address the issue of using Zend AMF with Flash Builder. I have been working with Flex for a couple of months (I'm on my 56th day of the trial) and I plan to buy it. I have several websites in the works and a few months ago I decided to try Zend, with the hopes of gaining optimization and scalability. Needless to say, I'm having trouble getting AMF and the FBuilder working together. I installed the Zend Server first. It ended up outside of my documentRoot. I think this is okay and I'm not having trouble using it's PHP server. I also noted that the version of the Zend server I got has it's own copy of ZendFramework. As you pointed out, Flash Builder installed another copy of ZFramework under my documentRoot when I went to set up a PHP service. In working through your example Time service it is not clear to me where /application/models or /application/controllers are/should be located. The only place I've found these two directories a

Cynthia
Cynthia

Thank you! My attitude toward Flash was the same, so I enjoyed your opening comments. I'm just getting into this Flex and Flash, I think it has a lot of potential for my skills which are somewhere in-between graphic artist and web developer and not really a master of either or any. I wonder if it will appeal much to the pure PHP developers and coders. I'm really looking forward to doing the 5-Day series of tutorials for Flex.

Kevin Remisoski
Kevin Remisoski

If you delete that magic powder line and add an exit; as the last line, you'll have the same result.

If you delete the require_once statement and instead add the following to your bootstrap file you're even better off although I'm not sure if there's a better way of doing autoloading...

APPLICATION_PATH,
'namespace' => '',
'resourceTypes' => array(
'model' => array(
'path' => 'models/',
'namespace' => 'Model_'
)
)
));
}

}

ddimalen
ddimalen

hi Kevin,  Im a big fan of your articles but I really need help on a project wherein I am currently stuck.  I am building an air application and I want to be able to access a data services remotely using zend_amf.  I mean from your article above you were using php service type but it is access locally.  My projects needs to access the services from a remote server.  Is it possible? I have exhausted all resources but all failed to work. :)

Kevin Remisoski
Kevin Remisoski

Well, I wasn't getting my hopes up, but thanks anyway. I'd probably be better off coding a Zend Framework CMS anyway.

Kevin Remisoski
Kevin Remisoski

ok that didn't format right at all but i'm guessing it was because i added the opening php tag? anyway let's see if this works:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
public function _initAutoLoad()
{
$autoLoader = Zend_Loader_Autoloader::getInstance();
$resourceLoader = new Zend_Loader_Autoloader_Resource(array(
'basePath' => APPLICATION_PATH,
'namespace' => '',
'resourceTypes' => array(
'model' => array(
'path' => 'models/',
'namespace' => 'Model_'
)
)
));
}

}

kschroeder
kschroeder moderator

 @ddimalen The examples are local but they're all being done over TCP which basically means that there is not much difference between this and remote sessions.  So it should work.  Check your web server error logs and make sure that you're making a connection to the actual server that you intend to be connecting to.

Latest blog post: Looking for album reviewers

Post Navigation

Web Analytics