Automatic AMF class mapping in Zend (Part 2)

see Part 1

Polishing off automatic mapping of objects to the correct class from PHP (Zend) back to ActionScript turned out to be easier than I thought.

In addition to the more commonly used $_explicitType class property, Zend also supports using a function called getASClassName. You can either paste this into each of your remote class stubs, or modify the getClassName method in Serializer to do it automatically.

public function getASClassName() 
{
 return ">" . str_replace("_", ".", get_class($this)); 
}

Clearly you'll need to avoid underscores appearing package and class names. That may be true regardless if you're planning to take advantage of Zend's automatic class loading.

On the Flash side, if you're not using the Flex compiler, you can use this to automatically register class aliases to the correct string.

function autoRegisterClassAlias (localClass:Class):void
{
registerClassAlias(">" + flash.utils.describeType(localClass).@name.split("::").join("."), localClass)
}

I've made it compatible with the Flex version. If the greater-than character is the cause of annoyance and confusion, feel free to remove it, but you'll need to do so on the PHP classes as well.

I'm sure this won't be our last post on this topic. If you've got lots of experience with AMF and Zend (I honestly don't) please post your thoughts in the comments.

Automatic AMF class mapping in Zend (Part 1)

First off, much thanks to Lee Coltrane for figuring this out. He's a bit busy at the moment, so I'm writing this up without the benefit of his input which I'm sure will be extremely valuable once our schedules mesh up.

A few caveats right off the bat. 1) We're still figuring out our best practices. 2) This is Flex only (see below)  3) We haven't (yet) written any code to automatically populate the $_explicitType variable going back to Flash from PHP.

If you're reading this, you've more than likely come across a Flex metatag like the one below:

[RemoteClass(alias="com.domain.FooBar")]

Personally, I found it annoying to have to populate the alias manually. The compiler knows the package name and the class name. Don't make me type it again! And, in fact, the compiler will accept the metatag without it:

[RemoteClass]

The only problem is getting Zend (in our case) to map it to the correct remote class. The Adobe engineers saw fit to prepend a greater-than character to the outgoing classname when using this syntax. So, if you omit the alias, ">com.domain.FooBar" will be sent instead.

To get ZendAmf to map this automatically, you'll need to make a slight modification to the Deserializer.php class. Mine is located in Zend/Amf/Parse/Amf3/Deserializer.php (Note: I haven't even looked at the Amf0 class yet, but my understanding is that custom class mapping isn't supported in AMF0) Insert the following code around line 315 in the readObject method after it has tried to determine the className but before it has assigned a return object.

// Allow and map automatic aliases via RemoteClass metatag & flex
if (strpos ($className, '>') === 0)
{
  $className = substr ($className, 1);
}
//translation: If the classname begins with '>' use the rest of the string instead.

This addition will deal with incoming class mapping. If you want to remove the alias parameter from all of your ActionScript RemoteClass metatags, you'll need to format your $_explicitType entries like this:

$_explicitType = ">com.domain.FooBar";

...which is what we'll look at in Part 2! 

NOTE: I said at the very beginning this is Flex only. Compiling with the Flash IDE does not support the RemoteClass metaTag, so you'll need to use registerRemoteClass as you've probably read about elsewhere. Perhaps in part 2 (or 3?) I'll write up an ActionScript class that can register classes against the correct package names automatically. Until then, I'll give you a hint: flash.utils.describeType.

Passing Custom-Classed Parameters to AMF (PHP)

I spent a day or two pulling my hair out and wondering if AMFPHP should be considered abandon-ware (no). I could get data to go back-and-forth. That part was pretty easy. But I wanted to pass a custom configuration object to the server as part of my request and couldn't get any further than it showing up in PHP as an anonymous array.

I gave up, installed the Zend framework (which now includes an AMF implementation), and had similar (although slightly different) issues. After resorting to Charles to figure out what might be going wrong, I found the problem in my remote service class. It turns out my PHP chops were coming up short.

There are a bunch of AMF examples and tutorials out there, and I feel like I looked at most of them ; ) Very few talk about sending custom-classed parameters to the server. Instead, they show you how to pass numbers and strings (if anything at all). The best of these test-your-gateway examples have you send your parameter object to the server as an array. In php, you'd access those (array) properties like this: $config['myParam'].

However, if you've got mapping between Actionscript and PHP classes properly configured, that syntax isn't going to work. Actionscript lets you access an object's child properties via either 'dot syntax' or 'array syntax', but PHP is more picky.

Once you get your custom class mapping working, you need to access (class) properties like this: $config->myParam. Simple to be sure.

So, I thought I'd tried this (and every other syntax combination), but apparently not while I had the class mapping setup correctly. PHP errors in your AMF service class can be notoriously hard to debug. Most of the time when something went wrong with mine, I simply never got a response. But, once I fixed my service class, I could use either Zend or AMFPHP. Rock on.