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.
No tags




Symfony-Zone » sfAmfPlugin 1.2.3 for Flex/Symfony released · 16. April 2009 at 10:56
[...] If you want more information about the plugin vistit the symfony plugin page or read the the HelloWorld example blog post. [...]
HelloWorld example with Flex and Symfony « DevEzine · 20. April 2009 at 12:04
[...] Read this article: HelloWorld example with Flex and Symfony [...]
sophia · 22. April 2009 at 08:31
Hi,
I am sorry to tell you that,after doing what you say above,when I run my project,I received an error message:
RFC Fault faultString=”send failed” faultCode=”client.error.MessageSend” faultDetail=”Channel.Security.Error error Error”.
Can you help me to fill the problem?
I have followed the steps above.
sophia · 22. April 2009 at 10:53
The newest error is:
[ RFC Fault faultString="Channel disconnected"
faultCode="Client.Error.DeliveryInDoubt"
faultDetail="Channel disconnected before an acknowledgement was received"]
Does anyone have the same problems?
Justin · 28. April 2009 at 15:53
I attempt to run this example and get a Client.Error.DeliveryInDoubt error. Any thoughts?
Thanks!
Justin · 28. April 2009 at 17:19
Aha sneaky.
Sophia, I don’t know if you had the same problem I had, but when I went to the apache logs I found the following error:
PHP Strict Standards: Only variables should be passed by reference in [Path_To_Symfony]\\sfAmfGateway.class.php on line 89
When I looked this up, I found the offending line had an array_pop command that was referencing an explode directly. Apparently, in php 5 this is now an error (http://the-stickman.com/web-development/php/php-505-fatal-error-only-variables-can-be-passed-by-reference/). I changed line 89 to the following 2 lines of code:
$tmpvariable=explode(“.”, $service_name);
$class_name = array_pop($tmpvariable);
And it worked for me. You may want to check your server logs to see if this is the error you get.
Symfony-Zone: HelloWorld example with Flex and Symfony : WebNetiques, LLC : Website Developers in Minneapolis, MN · 30. April 2009 at 06:47
[...] this article on the Symfony-Zone blog they show you how to use the sfAmfPlugin to let your framework application [...]
Symfony-Zone: HelloWorld example with Flex and Symfony : Dragonfly Networks · 30. April 2009 at 06:50
[...] this article on the Symfony-Zone blog they show you how to use the sfAmfPlugin to let your framework application [...]
Admin comment by thaberkern · 30. April 2009 at 08:00
@sophia: Please try to install the new plugin version 1.2.4 and take a look if this is fixing your problem. Justins fix is added to this version
Timo
Eric · 30. April 2009 at 21:01
If it helps anyone, I think in the code for the sayHello function, this line:
var remote:RemoteObject = new RemoteObject(“helloworld”);
should be changed to:
var remote:RemoteObject = new RemoteObject(“flextest-service”);
as that is the id of the service as defined in the services-config.xml file. This may be why a lot of the commenters are having trouble with the connection.
– Eric
Eric · 4. May 2009 at 02:03
Okay, I fought my way through this and here’s what I had to do to get this working:
1.) Copy the HelloWorldService.class.php file from lib/services/de/shiftup/flextest to lib/services.
2.) In the Flex mxml, change the line:
var remote:RemoteObject = new RemoteObject(“helloworld”);
To:
var remote:RemoteObject = new RemoteObject(“flextest”);
Because that’s the id of the destination in the services-config:
It works now after some major fiddling with the Flex files and the Apache setup.
Riza · 4. May 2009 at 06:27
It works for me too…
What about an example about using doctrine to load data from database to dataGrid?
Thx
raphox · 10. May 2009 at 00:38
Hi, i can receive simple string, array and other simples types, but I think that classService dont autoload all classes of Syfmonfy, because I dont declare my modules or modules of plugin in classService’s methods, and receive this message of error:
[RPC Fault faultString="Channel disconnected" faultCode="Client.Error.DeliveryInDoubt" faultDetail="Channel disconnected before an acknowledgement was received"]
I do my method return only this code:
return 1/0;
And receive identical error.
Why find this error?
raphox · 10. May 2009 at 20:30
Hi, I recomend you use the code in sfAmfService class file:
require_once sfConfig::get(‘sf_lib_dir’) . ‘/symfony/autoload/sfCoreAutoload.class.php’;
sfCoreAutoload::register();
With this all class autoinclude in your service class.
I’m trying applicate an exception treatment for be possible treat exception in service classes, because today inst possible.
raphox · 10. May 2009 at 21:00
sorry my friends, im wrong, the autoload code inst necessary.
But I saw that except tratement inst possible, so aplicate this code to sfAmfService class:
On top sfAmfService file I insert:
[php]
set_error_handler(array(‘sfAmfService’, ‘errorHandler’));
[/php]
In sfAmfService class I insert static function:
[php]
public static function errorHandler($errno, $errstr, $errfile, $errline) {
throw new Exception($errstr, $errno);
}
[/php]
Now, the wargin, notice and fatal erros be trater how Exception, whit this you dont receive “[RPC Fault faultString=”Channel disconnected” …” message. And now you can return message when you have an exception.
P.S.
Timo Haberkern, I think it’s good for you plugin.
Admin comment by thaberkern · 11. May 2009 at 17:10
Hi raphox
need to think about that. Sounds good but I will need to check if there are any problems with symfony if doing so
Timo
diamondustice · 12. May 2009 at 10:53
Hi
When I run the project I also encountered the error:
RFC Fault faultString=”send failed” faultCode=”client.error.MessageSend” faultDetail=”Channel.Security.Error error Error”.
I placed the crossdomain.xml configuration on the flextest/web/ and this solves the problem.
crossdomain link:
http://livedocs.adobe.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001621.html
miguel · 24. May 2009 at 19:10
Hi, I get this Error:
[RPC Fault faultString="[MessagingError message='Destination 'getLibros' either does not exist or the destination has no channels defined (and the application does not define any default channels.)']” faultCode=”InvokeFailed” faultDetail=”Couldn’t establish a connection to ‘getLibros’”]
I have crossdomain.xml configured, and i follow the tutorial for the rest.
What can be the problem?
Mahesh · 29. July 2009 at 16:49
Hi,
I was getting the following error.
“Channel disconnected before an acknowledgement was received”
I increased the max execution time value and the error is gone.
I’m interested in knowing the root cause of the issue. I would like to know in which all conditions above issue may appear.
Thank you
syca · 6. August 2009 at 17:24
Hi, I get the next error when trying to connect flex to symfony:
[RPC Fault faultString="Send failed" faultCode="Client.Error.MessageSend" faultDetail="Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Failed: url: 'http://flextest.bi/frontend_dev.php/amfgateway'"]
How can I solve it?, I need help urgent.
Thanks!!
Justin · 16. September 2009 at 08:02
I got the following error:
RPC Fault faultString=”Send failed” faultCode=”Client.Error.MessageSend” faultDetail=”Channel.Connect.Failed error NetConnection.Call.BadVersion:
any idea ?
These are the following test I did
-opening the gateway using a browser and I received “no valid AMF request received” on the error.log.
-tried to put the wrong <endpoint uri=”http://flextest/frontend_dev.php/amfgatewaylollolol” address and instead of BadVersion error I received a HTTP 404 error, so I am assuming the gateway is responding to my request.
So I am assuming the error happened in the PHP side and flash choked while interpreting this error and throws a BadVersion error. Is that correct ?
hendra1 · 30. September 2009 at 09:28
everthing work fine if u using sfAMFPlugin 1.4.2
and make a little change :
1.) Copy the HelloWorldService.class.php file from lib/services/de/shiftup/flextest to lib/services.
2.) In the Flex mxml, change the line:
var remote:RemoteObject = new RemoteObject(”helloworld”);
To:
var remote:RemoteObject = new RemoteObject(”flextest”);
Because that’s the id of the destination in the services-config
(thanks to @eric who post this issue)
have a try..
Lem · 23. October 2009 at 12:14
For those getting errors, you need to know that there are some security in FLEX which are not allowing you to make service links outside of your domain name.
So if your flex appl is accessible from http://myflexappclient/abc.html , and your symfony project from http://mysymf/ you’ll have an error.
Way to get it work is either copy your swf file in your symfony project and run it from there.
Or, use a crossdomain.xml (google it)
straffi · 14. November 2009 at 12:00
If you use FlashDevelop for Flex development, you have to include the path to the servies_config.xml:
-services src\services_config.xml
Works like a charm..
Ouled Sahel · 16. February 2010 at 16:20
I have this error:
[RPC Fault faultString="Send failed" faultCode="Client.Error.MessageSend" faultDetail="Channel.Security.Error error Error #2048 url: 'http://127.0.0.1/flextest/frontend_dev.php/amfgateway'"]
can anyone help me
Thanks
sergio · 2. March 2010 at 23:58
Friends.
all you have to do to make it work with sf 1.4 is to change the gateway module name “sfAmfPlugin” just create it with other name like “test”. its private because is the same name than the plug in module..
regards
god.. 4 hours to do that.
sergio · 19. May 2010 at 18:08
hello friends,
Did you find an article about how to work with objects Or Arrays trasfer between symfony and flex?
chip · 26. July 2010 at 16:48
HelloWorld example for thanx.