Space of Flex/AIR technologies

Beyond Plain Old Html Objects

Zend_Amf with full Zend Framework

with 52 comments

There are many examples on the web how to use Zend_Amf as a standalone component but couldn’t find one that actually shows how you can run it with the rest of the Zend Framework. Main benefit of running it in a way I will demonstrate in this post is that requests to AMF service classes are automatically bootstrapped with configuration, database initialization and other Zend components.

Here is how I use Zend_Amf with the full framework. First we have to setup whole environment as it is in ZendFrameworkQuickstart (there is also already preconfigured archive available there).


It will give you above folders structure; don’t forget about .htaccess file (as described in the quickstart tutorial)!!!

Now we will add Zend_Config to have a proper place for our database configuration. To do so we can create new config folder under application directory and place there an app.ini file. Here is an example of ini file content with mySQL configuration:

[production]
database.adapter               =    "PDO_MYSQL"
database.params.dbname        =    "database_name"
database.params.host        =    "127.0.0.1"
database.params.username    =    "user"
database.params.password    =     "password"
 
[development : production]
 
[testing : production]

In this case I’m actually using same configuration for production, development and testing purposes, but probably in most cases you would have some overriding entries under [development : production] and [testing : production] fragments of ini file.

Once you have ini file in place we can now enter bootstrap.php to initialize Zend_Config. It can be done after front controller entries with following line:

$configuration = new Zend_Config_Ini(APPLICATION_PATH . '/config/app.ini', 
    APPLICATION_ENVIRONMENT);

As we have database configuration loaded into $cofiguration variable we can use it to instantiate and setup Zend_Db component. To do so add these lines in bootstrap.php:

$dbAdapter = Zend_Db::factory($configuration->database);
Zend_Db_Table_Abstract::setDefaultAdapter($dbAdapter);

For your convenience and also as a good practice you can have your $configuration and $dbAdapter variables stored in Zend_Registry. This allows the application to ensure that regardless of what
happens in the global scope, the registry will contain the objects it needs.

$registry = Zend_Registry::getInstance();
$registry->configuration = $configuration;
$registry->dbAdapter     = $dbAdapter;

And here is a complete listing of my bootstrap.php file:

<?php
// application/bootstrap.php
// 
// Step 1: APPLICATION CONSTANTS - Set the constants to use in this application.
// These constants are accessible throughout the application, even in ini 
// files. We optionally set APPLICATION_PATH here in case our entry point 
// isn't index.php (e.g., if required from our test suite or a script).
defined('APPLICATION_PATH')
    or define('APPLICATION_PATH', dirname(__FILE__));
 
defined('APPLICATION_ENVIRONMENT')
    or define('APPLICATION_ENVIRONMENT', 'development');
 
// Step 2: FRONT CONTROLLER - Get the front controller.
// The Zend_Front_Controller class implements the Singleton pattern, which is a
// design pattern used to ensure there is only one instance of
// Zend_Front_Controller created on each request.
$frontController = Zend_Controller_Front::getInstance();
 
// Step 3: CONTROLLER DIRECTORY SETUP - Point the front controller to your action
// controller directory.
$frontController->setControllerDirectory(APPLICATION_PATH . '/controllers');
 
// Step 4: APPLICATION ENVIRONMENT - Set the current environment.
// Set a variable in the front controller indicating the current environment --
// commonly one of development, staging, testing, production, but wholly
// dependent on your organization's and/or site's needs.
$frontController->setParam('env', APPLICATION_ENVIRONMENT);
 
// CONFIGURATION - Setup the configuration object
// The Zend_Config_Ini component will parse the ini file, and resolve all of
// the values for the given section.  Here we will be using the section name
// that corresponds to the APP's Environment
$configuration = new Zend_Config_Ini(APPLICATION_PATH . '/config/app.ini', APPLICATION_ENVIRONMENT);
 
// DATABASE ADAPTER - Setup the database adapter
// Zend_Db implements a factory interface that allows developers to pass in an
// adapter name and some parameters that will create an appropriate database
// adapter object.  In this instance, we will be using the values found in the
// "database" section of the configuration obj.
$dbAdapter = Zend_Db::factory($configuration->database);
 
// DATABASE TABLE SETUP - Setup the Database Table Adapter
// Since our application will be utilizing the Zend_Db_Table component, we need 
// to give it a default adapter that all table objects will be able to utilize 
// when sending queries to the db.
Zend_Db_Table_Abstract::setDefaultAdapter($dbAdapter);
 
// REGISTRY - setup the application registry
// An application registry allows the application to store application 
// necessary objects into a safe and consistent (non global) place for future 
// retrieval.  This allows the application to ensure that regardless of what 
// happends in the global scope, the registry will contain the objects it 
// needs.
$registry = Zend_Registry::getInstance();
$registry->configuration = $configuration;
$registry->dbAdapter     = $dbAdapter;
 
// Step 5: CLEANUP - Remove items from global scope.
// This will clear all our local boostrap variables from the global scope of 
// this script (and any scripts that called bootstrap).  This will enforce 
// object retrieval through the applications's registry.
unset($frontController, $configuration, $dbAdapter);

Now we are ready to create a Zend controller that will handle AMF requests. To be consistent with url that is used by BlazeDS or LiveCycle DS (http://host:port/messagebroker/amf) we create MessageBrokerController.php under application/controllers directory with following content:

<?php
class MessageBrokerController extends Zend_Controller_Action 
{ 
	public function init()
	{
		$this->_helper->layout()->disableLayout();
		$this->_helper->viewRenderer->setNoRender();
	}
 
	public function amfAction()
	{
		$server = new Zend_Amf_Server();
		$server->addDirectory(APPLICATION_PATH . '/services/');
		echo($server->handle());
	}
}

It is not obligatory but viewRenderer can be disabled in init method as it is above. Please be ware that all AMF service classes will be stored in application/services directory. This is achieved by this line: $server->addDirectory(APPLICATION_PATH . ‘/services/’); – it can be modified to fit the requirements also addDirectory method can be called multiple times for multiple directories where services are stored. If we try to access http://localhost/messagebroker/amf now, browser should display Zend Amf Endpoint message – this ensures that our whole configuration is correct.

Now we actually got to the point where we can start creating our AMF service classes. To do so we just create application/services and application/dtos (where we will store DTOs – Data Transfer Objects or as others prefare to call these VOs – Value Objects) folders. Under dtos lets create MyObjectDTO.php with following content:

<?php
class MyObjectDTO
{
	public $_explicitType = 'MyObject';
 
	public $myProperty = "My property value";
}

Important to note here is that we will be mapping our php DTO classes to Flex classes using $_explicitType variable. I prefer this approach over explicit mapping during Zend_Amf_Server instantiation. This way I don’t have to return to my MessageBrokerController and edit it every time I want to add new DTO class.

So the last thing we are missing is AMF service class. Create it under services/MyAmfService.php as following:

<?php
class MyAmfService
{ 
	public function myAction()
	{
		require_once APPLICATION_PATH . '/dtos/MyObjectDTO.php';
		return new MyObjectDTO();
	}
}

At the end my project folder structure looks like this:

To test it we can create simple Flex client like that:

<?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;
		]]>
	</mx:Script>
 
	<mx:RemoteObject id="zendRemoteObject" destination="zend" source="MyAmfService" 
		endpoint="http://localhost/messagebroker/amf" 
		result="Alert.show(event.result.myProperty)"/>
	<mx:Button label="Call service" click="zendRemoteObject.myAction()"/>
 
</mx:Application>

Written by Piotr Walczyszyn

January 5th, 2009 at 7:19 pm

Posted in Examples

Tagged with ,

52 Responses to 'Zend_Amf with full Zend Framework'

Subscribe to comments with RSS or TrackBack to 'Zend_Amf with full Zend Framework'.

  1. aahhh, this is great. Thanks.

    Alan

    5 Jan 09 at 8:42 pm

  2. [...] Tutorial niestety w języku angielskim jest dostępny pod tym adresem: http://www.riaspace.net/2009/01/zend_amf-with-full-zend-framework/ [...]

  3. Cześć,

    przede wszystkim dobrze, że poruszyłeś ten temat, przyznam, że
    bardzo inersujący.

    TAK trzymaj!

    Pozdrawiam miło
    Paweł

    guci0

    6 Jan 09 at 3:41 pm

  4. Witam. Bardzo przydatny tutorial. Proszę, zwróć jednak uwagę na różnice między oryginalnym plikiem bootstrap.php pochodzącym z ZendFrameworkQuickstart a Twoją wersją. Oryginalny plik tworzy jeszcze dwu-krokowy layout. W przypadku użycia Layoutu otrzymujemy błąd: “NetConnection.Call.BadVersion”

    Antoni Jakubiak

    8 Jan 09 at 6:10 pm

  5. Excellent tutorial! I suggested the same approach on my blog but didn’t provide all the code. So I think your post will be very helpful for people who are completely new to ZF.

  6. Bravissimo!

    At last a clear explanation and a working (!!!) example… I’ve spent the last two days trying to merge Zend_Amf and Zend Framework MVC with poor success.

    Thanks a lot for this post,
    B Marcello

    bmarcello

    26 Jan 09 at 4:49 pm

  7. Hi,
    referring to your example, where echo($server->handle()) should provide text/html “Zend Amf Endpoint message” does not work properly. At least in ZF version 1.7.3, Zend_Amf_Server::handle() -method should be used without echo(). Using echo(), the response is sent with application/x-amf headeres instaed of text/html.

    Echo() might also cause the “NetConnection.Call.BadVersion” exception, mentioned in Antoni’s comment, thrown back to Flex/Flash.

    Tero

    30 Jan 09 at 12:09 pm

  8. To refer my last comment, echo() needs to be invoked in all cases to response with the application/x-amf headers. When viewing the Amf end point in ZF-MVC with browser, echo() should be excluded.

    Thanks for the good tutorial Piotr, it helped me to port http://www.keithcraigo.com/archives/275 into ZF MVC model :)

    Tero

    30 Jan 09 at 6:58 pm

  9. Hi! I think is a good tutorial but i would like to see a more complete instructions when the flex client is created because i get lost and i can’t get it to work :-)

    I run the project but when i press on the button “Call Service”, nothing happens.

    Thanks,
    Fernando.

    Fernando

    1 Feb 09 at 9:11 am

  10. An interesting comparison between Zend AMF and the X2O framework:
    http://blog.x2oframework.com/2009/02/framework-battles-for-flash-platform.html

    Ka Wai

    6 Feb 09 at 7:23 am

  11. Beginning of this week I recorded video tutorial for Adobe Deve Connection on this ;) Stayed tunned in near future ;)

    Piotr

    8 Feb 09 at 11:57 pm

  12. I’ve a problem:
    I’ve put VOAuthor class into a package “business” (either AS3 and PHP) and if I use “$server->setClassMap(”VOAuthor”, “VOAuthor”);” (without specify package) then Zend work fine, while if I use “var $_explicitType =’VOAuthor’;” (into class) then Zend don’t work fine.

    I receive from PHP (php_error.log):

    PHP Fatal error: Uncaught exception ‘Zend_Amf_Exception’ with message ‘Unable to parse null body data VOAuthor mapped class is not defined’ in C:\wamp\www\provaZendAMF2\Zend\Amf\Request.php:174
    Stack trace:
    #0 C:\wamp\www\provaZendAMF2\Zend\Amf\Request.php(125): Zend_Amf_Request->readBody()
    #1 C:\wamp\www\provaZendAMF2\Zend\Amf\Request.php(93): Zend_Amf_Request->readMessage(Object(Zend_Amf_Parse_InputStream))
    #2 C:\wamp\www\provaZendAMF2\Zend\Amf\Request\Http.php(64): Zend_Amf_Request->initialize(’????????null??/…’)
    #3 C:\wamp\www\provaZendAMF2\Zend\Amf\Server.php(365): Zend_Amf_Request_Http->__construct()
    #4 C:\wamp\www\provaZendAMF2\Zend\Amf\Server.php(313): Zend_Amf_Server->getRequest()
    #5 C:\wamp\www\provaZendAMF2\ZendAMF\gateway.php(18): Zend_Amf_Server->handle()
    #6 {main}
    thrown in C:\wamp\www\provaZendAMF2\Zend\Amf\Request.php on line 174

    I prefer to write $_explicitType =’VOAuthor’; into every business class! Maybe Do it need the package?

    In add … why I can’t specify a package? So I can’t write 2 class with self name!

    for example I would write business.Utente and transition.Utente in PHP so in RemoteObject into Flex I can write source=”transition.Utente”

    Thanks

    oscaroxy

    9 Feb 09 at 5:57 pm

  13. I also prefer to use $_explicitType and I think is a way to go, it always worked for me… What variable modifier u are using?

    Piotr

    11 Feb 09 at 11:11 am

  14. [...] If you had any problems with steps above you may want to refer to one of my previous posts where I explained how to configure Zend_Amf with full Zend Framework. [...]

  15. Great tutorial, I like your approach better than the way I’ve been implementing the library.

    Keith

    Keith Craigo

    28 Feb 09 at 5:33 pm

  16. [...] Zend_Amf with full Zend Framework by Keith | Categories: Uncategorized | Enjoyed this article? Subscribe to the full RSS Feed [...]

  17. Thanks! This will come in handy. :)

    Paul

    9 Mar 09 at 12:58 am

  18. When I go to http://www.domain.com/messagebroker/amf I get this error page:

    Message: Invalid controller specified (messagebroker)

    Stack trace:

    #0 /home/www/mooscms.dk/zend_framework_test/library/Zend/Controller/Front.php(934): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
    #1 /home/www/mooscms.dk/zend_framework_test/public/index.php(41): Zend_Controller_Front->dispatch()
    #2 {main}
    Request Parameters:

    array(3) {
    ["controller"]=>
    string(13) “messagebroker”
    ["action"]=>
    string(3) “amf”
    ["module"]=>
    string(7) “default”
    }

    I have tried accessing just the index.php, that works fine.

    Anyone knows what might be causing this?

    Lasse

    22 Mar 09 at 8:45 pm

  19. Hi all.

    First of all I wanna appreciate for this tutorial.
    second I wanna point to some pitfall I had encountered pls follow theses:

    1.we must use of echo ($server->handle());

    2.I see many people encounter with Badversion error , I have spent 2 days to solve this problem ,another one of it’s symptom is when you click the Call Service button nothing happened right! you know it is …. you must clear empty line of MessageBrokerController even ?> mark , it is zend framework problem .

    for your reference I have put the newflexzend.rar in http://www.ria.webandishan.com/newflexzend.rar

    this is complete source code .

    again I appreciate .

    if you any comments pls let me know about it.

    BR
    farid valipour

    farid valipour

    26 Mar 09 at 10:41 am

  20. [...] It was just published on ADC, it’s a first recording of two part series. You can find more details on one of my previous blog posts: Zend_Amf with full Zend Framework [...]

  21. Thanks for posting this and the video. These are very helpful to understanding how to harness the full power of the Zend framework from within Flex.

    diamondTearz

    2 Apr 09 at 3:50 am

  22. Responding to Lasse question, change MessageBrokerController to single camel case for example RemotingController. I found same problem when posted my application on my hosting provider server. I guess there is something regarding case sensitive settings.

    p.

    Piotr

    6 Apr 09 at 10:48 pm

  23. After reading the article, I just feel that I really need more information on the topic. Could you suggest some resources please?

  24. Good thinking but you’ve made a mistake. If you apply Zend’s MVC you must never echo anything or send headers directly (header()). There’s a special object for all that – response. Otherwise you just lose the whole point.

    So here’s an example of correct controller script.

    _server = new Zend_Amf_Server();
    $this->_server->addDirectory(dirname(dirname(__FILE__)) . ‘/services/’);

    $this->_server->setProduction(false);

    // turn the fucking renderer the fuck off
    $this->_helper->viewRenderer->setNoRender();
    }

    public function postDispatch ()
    {
    // shut the layout the fuck off
    $this->_helper->layout->disableLayout();
    // set the correct header if no error or forwarding occurred during dispatch
    $this->_response->setHeader(‘Content-Type’, ‘application/x-amf’, true);
    }

    public function indexAction ()
    {
    // process the fucking request and set the fucking response
    $amfResponse = $this->_server->handle();
    $this->_response->setBody($amfResponse);
    }

    }

    Nikita

    16 Apr 09 at 8:23 pm

  25. Hmm, I can’t comment. If this works, then disregard it as a test.

    Lasse

    19 Apr 09 at 3:31 pm

  26. Okay, so that worked, I apparently can’t post code in here.

    @Piotr, thank you. Your suggestion worked (partially). I’m getting a new error. See this pastebin: http://pastebin.com/m62fa4d62

    Thank you.

    Lasse

    19 Apr 09 at 3:34 pm

  27. [...] also found a great post from Piotr Walczyszyn about how to merge the Zend_Amf package within the Zend Framework MVC [...]

  28. Alright so I found a solution, just remove:
    $this->_helper->layout()->disableLayout();

    In the init function. But why?

    Solution found here:
    http://gertonscorner.wordpress.com/2009/04/19/fileupload-using-zend-amf-remoteobject-and-flash-10/

    Lasse

    21 Apr 09 at 8:51 pm

  29. Piotr,
    In regards to the error posted by Lasse “See this pastebin: http://pastebin.com/m62fa4d62

    This seems to be due to

    Zend_Layout::startMvc(APPLICATION_PATH . ‘/layouts/scripts’);

    $view = Zend_Layout::getMvcInstance()->getView();
    $view->doctype(‘XHTML1_STRICT’);

    is not included in your bootstrap code above but is in bootstrap.php of the Quickstart download.

    I was getting the same error because _layout() is not a function within the helper but is part of Zend_Layout.

    Hope this helps.

    Keith Craigo

    22 Apr 09 at 2:09 am

  30. Right you are Keith! Thanks a lot!

    Lasse

    22 Apr 09 at 10:46 am

  31. tks dude.

    Fernando

    23 Apr 09 at 3:44 pm

  32. I’m getting the busy cursor and any response,

    I Haven’t any log error ( php, or apache ) and I can’t see perfectly Zend Amf Endpoint message.

    I checked the addDirectory path which is /application/services

    Any idea?

    Xavier Colomer

    10 May 09 at 12:54 am

  33. I’m getting the busy cursor and any response,

    I Haven’t any log error ( php, or apache ) and I CAN see perfectly Zend Amf Endpoint message.

    I checked the addDirectory path which is /application/services

    Any idea?

    Xavier Colomer

    10 May 09 at 2:02 am

  34. class MyAmfService
    {
    public function myAction()
    {
    require_once APPLICATION_PATH . ‘/dtos/MyObjectDTO.php’;
    return new MyObjectDTO();
    }
    }

    Zend uses Pear naming conventions so keep things consistent with Models, etc. Would it be better to use something like:

    return new Dtos_MyObject();

    would open file /dtos/MyObject.php

    HRW

    9 Jul 09 at 8:59 pm

  35. Just curious, why make a service? Why not call the zend_db_table object directly, its almost like you have two models, not to mention a third when it gets cloned into flex. Just asking if its possible?

    Rich Breton

    3 Aug 09 at 9:08 pm

  36. [...] zum Einsatz kommt, baute ich meine erste Flex-Applikation in Verbindung mit dem Zend_Amf_Server im eigenen Controller. Dabei war die Fehlerdiagnose anfangs nicht leicht, denn im amfFaultHandler bekommt man häufig [...]

  37. Hi Thanks much for this…

    I just had one last question…where do we put references to the finished flash component in the Zend Framework…is there a reccomend place for this?

    lux

    20 Aug 09 at 7:46 pm

  38. Hi,

    i’ve been using a working Zend MVC Environment where I added the controller and wanted to test it with the browser.

    But instead of the “Zend Amf Endpoint message”, as mentioned in the tut after creating the controller, I get the exception:

    Unknown Player Version 26210

    So, I don’t even tried to use a simple flex, but I expect to get Amf_Server to work without one. My bootstrap is working well for all other controllers.
    Did i miss something important?

    Regards

    fwap

    26 Oct 09 at 11:09 am

  39. forget my post, problem was using zend and facebook together…

    fwap

    26 Oct 09 at 1:15 pm

  40. Nice example, works great for me and I like having a true single point of entry – which this delivers nicely. :)

    Another thing that works well with this example is to deliver the swf into the embedded page, or further loaders down the line in the same fashion. – with a minor little adjustment, controllers can be added to return media files, including SWFs as well, so those can be stored anywhere you like them and the index.php entry point can deliver them to the client.

    Bryan

    19 Nov 09 at 4:30 am

  41. Hi Piotr ,
    If I understand , you use two servers applicaton ? the first is tomcat for blazeds and the second is the zend server ?
    Is it not possible tu use one only server ? For example to compile php script in tomcat of blazeds ?
    Thanks.
    kriss

    kriss

    14 Feb 10 at 12:56 am

  42. @kriss BlazeDS is Java server adapter. Zend_Amf on the contrary is PHP server adapter. So depending on your backend technology you would use either one of it. So yes you can and probably should in most cases use only one…

    Piotr Walczyszyn

    15 Feb 10 at 12:10 pm

  43. Hi Piotr ,
    So , i want to do like it’s explained in linux mag where blazeds is used for php back-end .
    this is the link : http://www.linux-mag.com/cache/7537/1.html .
    But it is not so clear for me because as you said , it’s 2 technology different used in one .
    Thanks
    kriss

    kriss

    19 Feb 10 at 7:16 pm

  44. Hurrah! Finally found a tutorial about integrating MVC with ZendAMF, and a really good tutorial at that.

    helloworlder

    16 Mar 10 at 1:37 pm

  45. i like this tutorial a lot. clear solution for my question. but, how can i handle objects in flex, if a i have an DTO like:

    class StationsDTO {
    public $_explicitType = ‘Stations’;
    public $myProperty = array();
    public function __construct()
    {
    $stations = new Application_Model_DbTable_Stations();
    $this->myProperty = $stations->fetchAll();
    }
    }

    i am not able get something out of the [object Object] how can i access this data ?

    picknick

    23 Mar 10 at 1:24 am

  46. i got it!, i got it!, i got it! thanks a lot for this tutorial! a hard weekend, but an staight foward solution for combining flex with amf zenf “full” framework…yiipiiihhh!!!

    picknick

    23 Mar 10 at 12:23 pm

  47. [...] ruben.savenne.be http://www.riaspace.net Big [...]

  48. I am new both to PHP and Flash world. There is some integration between a php app and a flash client to be done by me (using AMF) so I find this post most valuable.

    I have one doubt here. It looks like a new instance of Zend_AMF_Server is created every time amf action is invoked. Could you please explain if it is necessary? Can an instance be created once (say in init method) and reused in actions?

    carleak

    9 Aug 10 at 7:42 pm

  49. @carleak – this is the way to go with Zend_Amf, for each call you instantiate Zend_AMF_Server which is very lightweight.

    Piotr Walczyszyn

    11 Aug 10 at 9:15 am

  50. Piotr, thanks for the reply.

    On the web I’ve seen only examples of “standalone” (not dependent on anything) services.

    Could you please suggest how to use Zend goodies (zend session, registry, parts of zend application) inside the service?

    carleak

    12 Aug 10 at 11:51 am

  51. Ok, sorry to have bothered you. I found the answer: to use Zend components you just… use them :)
    I had a problem (my amf controller didn’t see the session – my bug) that made me think the whole thing was more complicated than it really was.

    carleak

    18 Aug 10 at 10:54 am

Leave a Reply

Switch to our mobile site