Issues

ZF-6130: Strongly typed objects when sent either from client side or server side do not work till we specify a classMapping

Description

We use gateway.php as endpoint for Remoting Calls from Flash player. In order to expose a php file as a service we need to include it in the gateway.php file. Strongly typed objects(class objects) when sent either from client side or server side do not work till we specify a classMapping on gateway.php Something similar to: $server->setClassMap('Entity', 'Entity');

Flex already has a remoteClass alias tag as a metadata on the client side classes which specifies its type on the server side. Example: package {
[RemoteClass(alias="Entity")] // this is server side type public class Entity { public var id:int; } }

This data is used while serializing and de-serializing the object. So, Zend should not be requiring this mapping on the server, as it is assumed that the client will always send the data with the same typing as on the server. If there is any other reason of keeping this mapping on gateway.php, at least the default behavior should be the one which is mentioned above for no mappings.

Also, otherwise, the $explicitType variable in php classes provide the information about the type on the server. This variable if not specified make the strong typed objects as generic objects when sent to the client. This should also default to the class name if it is not specified, and should work as strongly typed objects on either side.

Comments

I've changed the serializer methods so that they will return class name and not empty for unknown classes, unless the class is stdClass (which will be just Object). Wade, if you could add test for that (I'm not sure how it's best to do it) that'd be great.

Looks like a pretty test case for the new functionality. Thanks stas! I'll put it in after work and merge it into the next mini release.

wade

The fix provided is partial and works only if the function in php is not strongly typed like: function update($ item) { return "something"; }

and we pass a class A say : package { [RemoteClass(alias="A")] public class A { public var i:int = 2; public function A() {

    }
}

}

now since the class mapping is not done on the server, the php function receives a stdClass and works. But the issue is that when the php function is strongly types say: function update (A $item);

PHP starts complaining the passed argument is of type stdClass instead of A.

The fix for this can be achieved if the Deserializer figures out the type (specified by the remote class alias on the Actionscript class) and then instantiates the correct type on the server side.

The mapping works if the class in question (ARemote) exists or can be loaded. If it can not, then the mapping of course can not work. I tried your example and it worked for me just fine as soon as class ARemote is defined when server request is parsed. If you code does not work, please provide the full code.

Find the files in the attached zip file. The error that I receive is :


Catchable fatal error: Argument 1 passed to Srv::test() must be an instance of ARemoteClass, instance of stdClass given in C:\wamp\www\TestZend1-debug\services\Srv.php on line 6

In your example, ARemoteClass is loaded too late - since requests are parsed before they are executed, when parsing the incoming packet the definition of ARemote class is not available.

In your example, ARemoteClass is loaded too late Can you elaborate on this, like what is the right time to do this.

If this is not supported can you provide a workaround for this scenario. Also, just to mention, AMFPHP, Blazeds and several other amf libraries support this.

Seems to be still questions about it, so reopening it to keep on my radar screen.

It seems this is still an issue, i've exposed my objects via the autoloader and loading works fine, however the AMF server still casts them to stdClass when they are incomming.

It looks like it is the transfer object that you are having issues with and not the service. ZF-9809 should make this a lot easier.

I believe this is now fixed in trunk as of r24543 and in the 1.11 release branch with r24544.

One note: for typehinted arguments to get cast correctly, they must have an accompanying @param annotation in the docblock. As an example, this won't work:


class EmployeeService
{
    public function createEmployee(Employee $item)
    { ... }
}

However, this will:


class EmployeeService
{
    /**
     * @param Employee $item
     * @return int
     */
    public function createEmployee(Employee $item)
    { ... }
}

This is due to a limitation in the PHP engine's Reflection API. The Reflection API for parameters can only return if the value expected is an array -- and not arbitrary object types.