Tag Archives: Remoting

Zend_Amf and Flash Remoting – Some things to note

Having done a little bit of work with Flash over the past several weeks there are a couple of things I've discovered as I've worked through some practical examples.  There's only really one thing signficant, but a couple of things that you need to be aware of when doing Flash remoting with Zend Framework.

Simple interface? Easy. Useful interface? Just a little harder.

In other words, with a simple architecture it's easy to do.  In a more useful architecture there are some things to be aware of.

When dealing with POPOs (Plain Old PHP Object) remoting is stupid simple.  What a POPO is is a PHP object that simply defines its properties as public and doesn't have much integration with the surrounding application. However, when you start trying to integrate within a larger framework, application or module (such as Zend_Db) then it gets a little more difficult.  Not horribly difficult, but you might need to add an extra line or two in your service class to properly translate things.

Introspection in Flash Builder

This is the key to working with Flash apps.  Flash Builder allows Flash developers to call remote objects and place the results in a native Flash object. Flash Builder can take a look at the return value of a remote call and automatically create a native object based off of that.  This is really great for POPOs, but…

Not as good for Zend_Db objects

But don't let that fool you into thinking that it's problematic.  Before I tell you why, let's go over some of the issues when you use a Zend_Db object.

Problem #1: The AMF Serializer does not properly serialize Zend_Db_Table_Row_Abstract objects as of ZF 1.10.4.  This will be changed in 1.10.5 with a very simple fix.  In fact, it's possible that by the time you're reading this it may not be an issue any more.

The reason for this is that the AMF serializer does a foreach loop over the objects that it's going to be serializing to write each property to the wire. What this does for a POPO (fun to say, isn't it?) is that it iterates over publicly defined properties of the object.  However, with a Zend_Db row object the data is stored in a protected array and not iterate-able.  The data does not have public accessibility. The change to make introspection work from front-end to backend is done by having the Zend_Db_Table_Row_Abstract class also implement IteratorAggregate and return the value of $this->_data.  Once this has been completed there will be front-to-back introspection.

Problem #2: New Zend_Db objects are not created using a constructor.  They are created by calling fetchNew() on a DB table object. But the AMF serializer will create the object using the contructor. The problem here is that when you try to save a Zend_Db_Table_Row_Abstract based object the table object will not have been defined.  The way around this is to actually use one of the hooks in the row class called init().

protected $_tableClass = 'Model_DbTable_Census';

public function init()
{
    if ($this->_getTable() == null) {
        $this->setTable(new $this->_tableClass());
    }
}

What this does is check to see if the table has been defined.  If it has not, the individual row object will create one for itself.  This could also technically be done in an overarching manner with an abstract model definition to handle it.

One question you might have is "whose fault is this?" Is it Zend_Db or Zend_Amf?  The actual answer is neither.  Both are operating fine within their own patterns.  What this is is a discongruency of patterns.  And so we need to handle that with the code in the init.  The other caveat is that with this functionality you cannot have a direct call to the save() method for both create and update operations.  For one of them you will need to get an instance of the class in the service object prior to calling the save operations.  In my third part of this series I will show you what I mean.

Using a service object

While it might seem reasonable to simply provide direct access to your individual models there are actually two reasons why this will not work or is not a good idea.

1) Flash Builder requires your data model class files to be located in the document root.  This does not work well with a proper Zend Framework application

2) Dependencies will be difficult to manage.  In other words, directly calling a class called User may work fine but any additional data, such as permissions, should have its logic defined on the server side.  Otherwise it will be waaayyy too easy to hack. 

Having a service object allows you to put a very thin class in the document root so Flash Builder can introspect it (I'm hoping this requirement will be removed at a later date) and it also limits the damage that an end user can do.

Conclusion

Having seen some of these issues am I concerned at all about integrating a native Flash and a native ZF application?  Not really.  Understanding the reasons why some of the problems existed took a little bit of time, however the implementations are actually really easy.  There was one bug and it will be fixed in ZF 1.10.5 with about 3 lines of code.  So all in all, now that I'm over the hurdle I am really looking forward to doing more ZF work with AMF and Flash.

Downloads.  Everyone wants downloads.  Once I have finished the third part of this series I will be making the fully functional application available for download as a Zend Studio/PDT project.

For the Flash developers – building your remote endpoint

While I am not a great Flash developer… OK I'm not even a good one, I have been recently been looking at ways of integrating Flash and PHP with the release of Flash Builder 4.  I think that PHP is a great way for Flash developers to access their backend systems.  This is not because I have anything against any other technologies that a Flash developer might connect with, but instead it is because PHP is a great language to use when another language is your forte.

What I mean by that is that if Flash is your primary programming language PHP is a good way to provide remote access to your data because it doesn't require you to be an expert.  You can throw PHP at the wall and it will stick.  So what we're going to do in this article is show how little of an expert you really need to be.

One of the ways you can get away without being an expert is to use a framework.  In this case, I will be using Zend Framework as the means to provide my data access layer.  In fact, this example is a great one because it shows the use-at-will architecture of Zend Framework.  I believe that this is one of the places where Zend Framework rises above the others.  If you're looking for stupid simple database access and basic application functionality then Zend Framework might not be right for you.  But if you want the ability to use the components you need to make your life easier, ZF is a good choice.

This article is going to end up being a two part article.  This first part is intended for the Flash developer who wants to be able to set up a basic CRUD application.  The CRUD application is one that Ryan Stewart or Kevin Hoyt (or someone else) wrote that was designed to showcase connecting to PHP with Flash.  However, the example was written from the point of view of a Flash developer and what I wanted to do was take that same functionality and "Framework-ize" it.  In other words, make it very testable and drastically simplify the code.  The application is a simple one that provides access to census data.

LayoutThe new backend will use Zend_Application for its bootstrapping and setup.  Thankfully, if you are using Zend Studio, you can quite easily set this project up.  Select the PHP Explorer and type CTRL-2 followed by "zf create project CService".  This will create a basic structure of an MVC application, though we will only be using the M (or Model) part of the MVC design pattern.  So, we're using the M pattern.  If you do not have Zend Studio you can do the same thing with Zend_Tool (wha?) or you could simply create a project structure that looks like what is on the right(oh).

I had mentioned bootstrapping.  What that does is set up the context for the request so you don't have to do it.  You see in the "application" directory a Bootstrap.php file.  This contains the class that Zend_Application will use to bootstrap a request and it looks like this.


class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    public function _initAutoload()
    {
        $al = new Zend_Application_Module_Autoloader(
            array(
                'namespace'        => '',
                'basePath'        => dirname(__FILE__)
            )
        );
    }
}

What this is doing is setting up the autoloader.  The autoloader is used to load files for individual classes that are required to execute an individual request.  This can get more complex, but likely you, as a Flash developer, will not need to run into the need for that.  Then in our configs directory we will need to spell out some basic database configuration settings.  I put it in a file called configs/application.ini.

[production]
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
resources.db.adapter = "pdo_mysql"
resources.db.params.host = "localhost"
resources.db.params.username = "root"
resources.db.params.password = ""
resources.db.params.dbname = "census"
resources.db.isDefaultTableAdapter = true

ModelsThe next thing we need to do is set up our data access layer.  This is not the layer that you will be calling.  This is the layer that the service layer will call to handle the database calls.  There are two files that you need to create.  One to represent the table and another to represent a row.  The one two represent the table is in the models/DbTable/Census.php file and its code looks like this.


class Model_DbTable_Census extends Zend_Db_Table_Abstract
{
    protected $_rowClass = 'Model_Census';
    protected $_name = 'census';
}

$_name is the name of the table as spelled in the database.  $_rowClass is the name of the class that represents the row.  Speaking of, that file is stored in models/Census.php and it looks like this.


class Model_Census extends Zend_Db_Table_Row_Abstract
{
    protected $_primary = 'id'; 
}

What this is doing is stating that the primary key is the column named "id".  Speaking of the table.  Here is the create statement.

CREATE TABLE `census` (
  `age` varchar(3) DEFAULT NULL,
  `classofworker` varchar(255) DEFAULT NULL,
  `education` varchar(255) DEFAULT NULL,
  `maritalstatus` varchar(255) DEFAULT NULL,
  `race` varchar(255) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf-8

Congratulations, you now have you model layer.

ServicesThe next layer you need to build is the service access layer.  This is done after you have created your PHP data service using the Flash Builder components.  There are plenty of places you can go to on information on that, or you could also look at my previous posting on Flash called Flex and Zend Framework – Part 1.  Once you have created the data access integration point in Flash Builder we can go back to PHP.  If you look at our first image you see that there is a directory called "public".  This is the directory that the service endpoint should be installed into.  In that service endpoint directory there is a file called amf_config.ini.  Here is where you need to set up the directory where your service class is going to be.  I simply named the directory "services".  The gateway.php file was put there by Flash Builder but the bootstrap.php was not.  We will look at bootstrap.php in just a bit.

The next thing we want to do is define our service class.  This is the class that will implement the functionality that we want to actually call.  It is placed in the "services" directory in a file called CensusService.php.  I won't put the whole class in, but from the example you should see what it's doing.


class CensusService
{

    public function getAllCensus()
    {
        $tbl = new Model_DbTable_Census();
        return $tbl->fetchAll()->toArray();
    }

    public function getCensusByID( $itemID )
    {    
        $tbl = new Model_DbTable_Census();
        return $tbl->find($itemID)->current();
    }

    public function createCensus( $item )
    {
        $tbl = new Model_DbTable_Census();
        $row = $tbl->fetchNew();
        $row->setFromArray((array)$item);
        $row->save();
        return $row->id;
    }
}

Notice the very few lines of code?  This is the benefit of using something like Zend Framework.  No database access or anything.  That has all been taken care of by Zend_Application and the configuration file that we wrote.  The only caveat is that the return value MUST be an array.  So we put toArray() at the end.

Well it's all working now, right?  Maybe.  To do that we need to now test it.  That is where Unit Testing comes in.  Using Unit Testing on the PHP side allows us to test to make sure that any changes made to the codebase don't break somewhere else.  To do the Unit Testing I am going to use PHPUnit integration in Zend Studio.  You could also use the regular PHPUnit if you like.

Remember that "tests" directory that we had created earlier on?  Well, in there you can create another directory called "services" and in that directory put a file called CensusServiceTest.php.  In that file is where you write all of your Unit Tests.  I have a video you can watch called "Unit Testing Zend Server PHP Job Queues" that goes over some of the basics.  The Unit Tests (with several of the tests removed for brevity) start with including the files to be tested, setting up the test and then calling the individual functions, comparing the results to what is expected.

require_once realpath(dirname(__FILE__).'/../application/bootstrap.php');
require_once realpath(dirname(__FILE__).'/../../public/AMFService/services/CensusService.php');

/**
 * CensusService test case.
 */
class CensusServiceTest extends PHPUnit_Framework_TestCase {
    
    /**
     * @var CensusService
     */
    private $CensusService;
    
    protected function setUp() {
        parent::setUp ();

        $this->CensusService = new CensusService();
    
    }
    
    /**
     * Tests CensusService->getAllCensus()
     */
    public function testGetAllCensus() {
       
        $ret = $this->CensusService->getAllCensus();
        $this->assertGreaterThan(
            0,
            count(
                $ret
            )
        );
        $this->assertType(
            'array',
            $ret
        );
    
    }
}

What we are doing is asserting that this code will return more than one census item.  Now for each piece of functionality you should add another function that starts with the word "test" and verify that the return values are what you would expect.  For our test on collections of information we want to assert both that the count is greater than zero and that the return type is an array, not a result set.

There is now one last thing we need to do before going on to the next part and integrating our front end Flash application.  That is to bootstrap the remoting requests.  That is done by adding a require call to the top of Flash Builder's gateway.php file.

require_once 'bootstrap.php';

ini_set("display_errors", 1);
// ..etc.

Then we need to actually create the file that does the bootstrapping.


// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../../library'),
    get_include_path(),
)));

/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap();

Most of what you see here is mostly not important as a Flash developer.  What this is basically doing is setting the application path directory, defining the environment as production, setting the include path to include a library path (which you could probably remove) and then loading and executing the Zend_Application class with the current configuration.  All this is really doing is setting up those database models that we had defined earlier on.  While for a simple example this is a fair amount of overkill, it actually makes your life much easier as you start to add database tables and service layers.

That takes us to the end of the backend part of building a CRUD Flash application with PHP.  Stay tuned for when we integrate the frontend.

The Zend Studio projects can be downloaded here.