HelloWorld example with Flex and Symfony
15. April 2009 in General
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.


sophia said on 22. April 2009
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 said on 22. April 2009
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 said on 28. April 2009
I attempt to run this example and get a Client.Error.DeliveryInDoubt error. Any thoughts?
Thanks!
Justin said on 28. April 2009
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.
Timo Haberkern said on 30. April 2009
@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 said on 30. April 2009
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 said on 4. May 2009
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 said on 4. May 2009
It works for me too…
What about an example about using doctrine to load data from database to dataGrid?
Thx
raphox said on 10. May 2009
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 said on 10. May 2009
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 said on 10. May 2009
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.
Timo Haberkern said on 11. May 2009
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 said on 12. May 2009
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 said on 24. May 2009
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 said on 29. July 2009
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 said on 6. August 2009
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 said on 16. September 2009
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 said on 30. September 2009
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 said on 23. October 2009
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 said on 14. November 2009
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 said on 16. February 2010
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 said on 2. March 2010
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 said on 19. May 2010
hello friends,
Did you find an article about how to work with objects Or Arrays trasfer between symfony and flex?
chip said on 26. July 2010
HelloWorld example for thanx.
reen said on 8. September 2010
I had some problems to disalbe the security filter in SF 1.4. Each time i call the amf route SF gave me an error message that said: login required. So after a while i found a solution. The amfplugin overrides the security value in its own yaml file.
change it from
default:
security: off
to
default:
security: false
seems to be a bug or maybe i am wrong. Them please correct me.
Maria said on 2. November 2010
Lem: Where should I save my swf, because I put it in the web folder and I still got this message “cross-domain-policy”, when I put this address in the browser:
http://127.0.0.1:8080/frontend_dev.php/amfgateway
thanks a lot!
borga said on 5. April 2011
i am a symfony newbie and spent my 5 hours for the NetConnection.Call.BadVersion error.
but i found the solution.
the trick is to change the
default:
is_secure: false
to
all:
is_secure: false
in the security.yml
Andrea Rodriguez said on 26. August 2011
Hello,
I created my symfony project in a payment server(production server), but testing of the services the server gives me the error File does not exist: / home/xxx/public_html/500.shtml, referer: ?method=de.shiftup.flextest.HelloWorldService%3A%3AsayHello. Somebody wants to happen?
Albulescu Cosmin said on 6. October 2011
Hi, very nice post. Very usefull