Today I want to show you how to use the sfAmfPlugin to create a simple Hello World application with Symfony, Flex and the plugin. AMF is the most comfortable way to communicate between a backend technology and Flex. AMF allows RMI (Remote Mathod Invocation) from Flex to a backend server that is able to support AMF. The sfAmfPlugin for Symfony adds AMF-support to the PHP-Framework.
What do we want?
Keep it simple! In this small sample project we will create a Flex-Client with a text-field and a button. If the user clicks the button the content of the textfield will be sent to the backend via AMF (we call a service method) and the result from the backend is placed on the screen.
Symfony Project
First of all we need a Symfony project. We create one with the name “flexdemo” and an application called “frontend”
$> symfony generate:project flextest
$> symfony generate:app frontend
Now it is time to install the plugin. This can be done via the symfony commandline tool:
$> symfony plugin:install sfAmfPlugin
$> symfony cc
Now everything is in place to create our first AMF-Service. Therefore just use a commandline task that comes with the sfAmfPlugin:
$> symfony amf:create-service --package=de.shiftup.flextest HelloWorld
$> symfony cc
This commandline tasks creates a service class in the lib/services folder of your symfony-project. If you used the (optional) –package parameter sfAmfPlugin created a suitable directory-structure. In the case of our simple sample you will find the service-class under lib/services/de/shiftup/flextest/HelloWorldServcie.class.php. Open this file and change the content to the following sourcecode:
<?php
/**
* AMF enabled service class HelloWorldService
*
* Project: flextest
*
* @package de.shiftup.flextest
* @author Timo Haberkern
*
* @version SVN: $Id$
*/
class HelloWorldService extends sfAmfService {
public function sayHello($who) {
return "Hello ".$who;
}
}
The last thing we will need is a AMF-Gateway-Module that we can call via URL. You can create this module as any othe Symfony module:
$> symfony generate:module frontend amfgateway
Open the actions.class.php in apps/modules/amfgateway/actions and change the sourcecode to the following:
<?php
/**
* amfgateway actions.
*
* @package flextest
* @subpackage amfgateway
* @author Timo Haberkern <timo.haberkern@shift-up.de>
* @version SVN: $Id: actions.class.php 12 2009-04-14 07:12:25Z thaberkern $
*/
class amfgatewayActions extends sfActions {
/**
* Executes index action
*
* @param sfRequest $request A request object
*/
public function executeIndex(sfWebRequest $request) {
$this->setLayout(false);
$gateway = new sfAmfGateway();
$response = sfContext::GetInstance()->getResponse();
$response->setContent($gateway->service());
return sfView::NONE;
}
}
Thats it. This gateway action will check which Service class is called from flex and call the method in the class. Nothing more is needed on the Symfony side of life.
Flex-Client
On the Flex-Side of our small little project we need a project first. Just create a new one. As “Application server type” choose “None”. You can name the Flex project as you want. FlextTestClient will do for us at the moment.
To call AMF-Server-Services you need to configure them to use in a Flex application. This service definition is done in the file services-config.xml. Create this file directly in the src-directory. And add the following XML code to it:
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="flextest-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="flextest">
<channels>
<channel ref="flextest-channel"/>
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="flextest-channel"
class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://flextest/frontend_dev.php/amfgateway"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
</services-config>
Maybe you will need to change the endpoint-uri to the local URL of your Symfony project.
Now open the Project-Settings of your Flex Project (right click on the project icon->Properties) and select “Flex compiler”. Add the services-config.xml to the compiler options.
Now open the main applictaion file FlexTestClient.mxml. We need to add MXML markup for the Panel with the button and the text input field.
<mx:Panel x="120" y="42" width="281" height="194"
layout="absolute" title="SayHello">
<mx:TextInput id="username" x="90" y="10"/>
<mx:Label x="10" y="12" text="Your Name:" fontWeight="bold"/>
<mx:Button x="176" y="40" label="SayHello" click="sayHello()"/>
<mx:Text x="10" y="83" id="result" text="Result"
width="241" height="61" fontWeight="bold"
color="#FF0000"/>
</mx:Panel>
Nothing special here. As you can see we call the function sayHello on the click event of the button, so we will need a Script-Block with such a function:
<mx:Script>
<![CDATA[
private function sayHello():void {
}
]]>
</mx:Script>
Now we will do what we wanted to do just from the beginning: Callin our serverside Symfony service class and method. Therefore we will use the service definition we have done in the services-conf.xml. Add the following lines to the sayHello function:
var remote:RemoteObject = new RemoteObject("helloworld");
remote.source = "de.shiftup.flextest.HelloWorldService";
remote.sayHello(username.text);
What’s going on here? We initialize a new RemoteObject (given the ID of the service from the service-conf.xml) and define the Symfony-Service-class. Please keep in mind that you need write the full packagename of the Servcieclass (in our case de.shiftup.flextest.HelloWorldService). Now we can call the sayHello-Method of this Serverclass. But what to do with the return value of the Server-Service? AMF Services are assynchronous, so you can not do something like this:
result = remote.sayHello(username.text);
We need to define result event listeners to deal with the different result states (Success and Fault)
private function sayHello():void {
var remote:RemoteObject = new RemoteObject("helloworld");
remote.source = "HelloWorldService";
remote.addEventListener("result", function (event:ResultEvent):void {
result.text = event.result.toString();
});
remote.addEventListener("fault", function(event:FaultEvent):void {
Alert.show(event.fault.toString(), "Error");
});
remote.sayHello(username.text);
}
Your MXML should now look like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.rpc.remoting.RemoteObject;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
private function sayHello():void {
var remote:RemoteObject = new RemoteObject("helloworld");
remote.source = "HelloWorldService";
remote.addEventListener("result", function (event:ResultEvent):void {
result.text = event.result.toString();
});
remote.addEventListener("fault", function(event:FaultEvent):void {
Alert.show(event.fault.toString(), "Error");
});
remote.sayHello(username.text);
}
]]>
</mx:Script>
<mx:Panel x="120" y="42" width="281" height="194" layout="absolute" title="SayHello">
<mx:TextInput id="username" x="90" y="10"/>
<mx:Label x="10" y="12" text="Your Name:" fontWeight="bold"/>
<mx:Button x="176" y="40" label="SayHello" click="sayHello()"/>
<mx:Text x="10" y="83" id="result" text="Result"
width="241" height="61" fontWeight="bold"
color="#FF0000"/>
</mx:Panel>
</mx:Application>
Start your Flex-Application and have fun with your small Hello World application
More service classes
In a real-life project you will have more than one Service-class. But keep in mind: Regardless the amount of service-classes you will always need only one gateway module (amfgateway). This gateway can handle all Service-Classes.
Book Mark it-> | | | | | | | | | | | | |