Zend Framwork

Flex and Zend Framework – Part 1

Cài này mình đang tìm hiểu nên lưu lại , bạn nào cần thì vào xem. Các bạn cố gắng đọc tiếng anh vậy , Vì thực ra nếu mà dịch lại tiếng việt post lên thì trông nó cùi quá . Để nguyên bản luôn đọc cho dể .

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 candownload 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 ProjectThe 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.

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.

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

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&#8221;;
_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 ourZend_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.

Bình luận về bài viết này