Zend Framework: Zend_Amf Component Proposal
| Proposed Component Name | Zend_Amf |
|---|---|
| Developer Notes | http://framework.zend.com/wiki/display/ZFDEV/Zend_Amf |
| Proposers | Wade Arnold |
| Zend Liaison | Stanislav Malyshev |
| Revision | 1.0 - 1 January 2008: Initial Draft. (wiki revision: 22) |
Table of Contents
1. Overview
Zend_Amf_Server provides Action Message Format (AMF3) support for the Zend Framework that is compatible with the Flash Player 9 and above. The Adobe Integrated Runtime (AIR) and Flash Player uses AMF to communicate between an application and a remote server. AMF encodes remote procedure calls (RPC) into a compact binary representation that can be transferred over HTTP/HTTPS protocol. Objects and data values are serialized into this binary format, which increases performance as the AMF serialization is a highly optimized procedure in the Flash Player. Zend_Amf_Server will act as an AMF gateway to the Zend Framework by exposing through introspection custom class objects and functions that will respond as callbacks through the Zend_Amf_Server gateway.
2. References
3. Component Requirements, Constraints, and Acceptance Criteria
*PHP5
**PHP5 Reflection extension
*Zend Framework
**Zend_Amf_Value family of classes
**Zend class
4. Dependencies on Other Framework Components
- Zend_Server_Interface
- Zend_Server_Reflection
- Zend_Server_Reflection_Function_abstract
- Zend_Server_Reflection_Method
5. Theory of Operation
Zend_Amf_Server is composed of several components, ranging from the server itself to request, response, encoding, decoding, and fault objects.
To implement Zend_Amf_Server, the developer must attach one or more classes or functions to the server instantiation, via the setClass() and addFunction() methods.
The Zend_Amf_Server will decode request objects that are received via php://input and deserialized the request and check for an existing instantiated session. Zend_Amf_Request will check the AMF header for the matching name space of the requested remote object to be called. The remote object will be instantiated and the result of the method call will be serialized via Zend_Amf_Vaslue and returned to the requested http connection via Zend_Amf_Response.
| ActionScript | PHP |
|---|---|
| undefined | null |
| null | null |
| int | integer |
| number | float |
| boolean | boolean |
| String | string |
| Array | array |
| Object | Associative array |
| xml | DomDocument |
| Date | Date |
| RemoteClass | class mapped object |
| uint | ? |
| ByteArray | Zend_Amf_Value_AMF3_ByteArray |
6. Milestones / Tasks
7. Class Index
- Zend_Amf_Fault
- Zend_Amf_Request
- Zend_Amf_Request_Http
- Zend_Amf_Response
- Zend_Amf_Server
- Zend_Amf_Server_Exception
- Zend_Amf_Server_Fault
- Zend_Amf_Util_BinaryStream
- Zend_Amf_Value
- Zend_Amf_Value_Number
- Zend_Amf_Value_Boolean
- Zend_Amf_Value_String
- Zend_Amf_Value_Object
- Zend_Amf_Value_Null
- Zend_Amf_Value_Undefined
- Zend_Amf_Value_Refrence
- Zend_Amf_Value_MixedArray
- Zend_Amf_Value_Array
- Zend_Amf_Value_Date
- Zend_Amf_Value_Xml
- Zend_Amf_Value_TypedObject
- Zend_Amf_Value_Amf3_Intiger
- Zend_Amf_Value_Amf3_Date
- Zend_Amf_Value_Amf3_String
- Zend_Amf_Value_Amf3_Xml
- Zend_Amf_Value_Amf3_ByteArray
- Zend_Amf_Value_Amf3_Array
- Zend_Amf_Value_Amf3_Object
8. Use Cases
9. Class Skeletons
A couple things to note – you may be moving in these directions already, but better to make sure early. ![]()
First, use request/response objects in the design. This will facilitate unit testing, as well as provide an easy point of customization for end-user developers. Additionally, this leaves the server handling only the details of dispatching the request; the request can handle deserializing the request payload, and the response can serialize the response payload.
This leads to my second point: naming. Do not include the protocol version in the component name. Instead, this can be handled in the request and response objects: Zend_Amf_Request_Version3, etc. Alternately, the request/response objects can auto-detect the version based on the request provided; this latter method is used by Zend_Json_Server in detecting JSON-RPC request versions (see the implementation in the current incubator for an example).
I agree on the protocol version in the name comments. Note that in order to correctly support an AMF request from the Flash Player that you must implement both AMF 0 and AMF 3 as all requests start out in AMF 0 and only switch to AMF 3 on the first complex object encountered for a header value or message body.
I'm not familiar with the magic referred to in the spec, but it would be nice to see some guesses at what the complete API will look like to users for this module.
The type mapping table would be clearer if shown in a formatted table with columns. I didn't see integer and double types mentioned in the list but I'd say they're mandatory.
Do you have any thoughts on what you'll do with IExternalizable types in PHP?
I think more detail is needed on how users will opt-in to which classes (and potentially methods) will be accessible via this component. There are hints as to usages of setClass() and addFunction()... does this mean one Zend_AMF_Server instance per class to be exposed as a service?
Will users be able to write custom serializers/deserializers for future versions of AMF? Perhaps even supporting AMFX (an XML representation of AMF used by Flex/BlazeDS's HTTPChannel)?
Speaking of BlazeDS considerations, will Zend understand and return BlazeDS "Messages" to the client or will it be simpler Flash Remoting style client libraries that will communicate with this kind of server?
This may be covered by another Zend module, but more information on how a Flash client authenticates would be useful. Can you apply roles based security to restrict who can call a particular remote object?
What about logging/debugging? Will you be able to enable debug logging to try and figure out what raw AMF data is being received/sent?
Peter,
To conform more with the way other Zend frameworks have been implemented I am using the Value and Value types for all marker types.
I do not have any idea how to deal with IExternalizable. I have seen how people have done it in Java and Python and could probably work from there.
I have added example instantiation code. I am having issues with just adding name spaces but have a question out the mailing list.
The goal is there is enough architecture in the Zend_Amf/Value.php class that people can add there own marker type handlers in as long as we know the byte definition for the marker type.
I have little to know documentation for how to implement messaging. I am not even sure where in the AMF stack it says that it is a "message"
Authentication from the AMF header needs to then run against Zend_Acl for authorization. I going to have to familiarise myself with Zend_Acl but it is where I was going to go as soon as I had all the serializers completed.
I am using Zend_Log right now for debugging. It is a pretty slick API. However I had no intentions of adding the functionality for raw AMF package, header, Body inspection. Is this something that you think would be useful. It is basically required for doing development on this addition to the framework but I am not sure Flex developers would find it useful. Most people use charles or service capture for debugging but I would like to know your thoughts?
Support for IExternalizable via AMF 3 is an absolute requirement. If there isn't an equivalent in PHP, can you establish a convention that people's classes implement a readExternal and writeExternal function and you pass access to the binary stream so that they can read off the required bytes for their type?
As for BlazeDS "messages" - these are simply strongly typed ActionScript classes that are used to formalize client and server communication for RPC or Publish/Subscribe requests sent through the BlazeDS "message broker". For basic RPC calls for RemoteObject, this would involve at least understanding the types LoginMessage, RemotingMessage, AcknowledgeMessage, and ErrorMessage. See the classes in this package for rpc.swc in Flex 3:
The equivalent Java classes that these map to are in BlazeDS:
As for debugging... Charles only helps debug what was sent from either the client or the server, it doesn't help you debug what the server actually thinks it received (i.e. it doesn't help debug an error in the Zend deserializers).
Peter thanks for the links. I will look into them right away. Also let me do some investigation on IExternalizable.
Peter,
Please don't beat me up. After reading through the live docs I can't think of when I would use IExternalizable that I would not just use the meta data tag [Transient]. Any chance you have a URL to a use case so that I can better understand it. I always love learning new things about Flex!
I will look through some of the blazeDS code to see where they are doing logging and construct something similar.
No prob - IExternalizable is usually a fall back when custom serialization is not possible any other way... if you were only interested in removing particular ActionScript properties from a VO then sure, perhaps [Transient] could be used. But there are other custom serialization scenarios - such as including read only or static properties (not a great pattern, but people have requested it as a feature and we've suggested IExternalizable as a compromise), or a more useful scenario of reducing the size of your VO by only sending the values and not the property names as you can control the property value order. Yet another scenario is to protect yourself from changes to the API by providing a flexible but predictable serialization mechanism.
The logging thing isn't as a high priority, but trust me, it will save you a lot of time in the future if you implement it now for when people log bugs against the implementation.
What we'd like to see here added:
1. More use-cases, explaining how you talk to AMF - including passing data both ways and calling methods.
2. Detailed explanation on data type handling - how types are mapped into PHP and from PHP to AMF, especially dealing with higher-order types like Date that may or may not have PHP classes representing them. E.g., do we store Date as AMF_Date, DateTime or timestamp, how we create date value to send to AMF, etc.
3. What are AMF3 types - how they are different, is there any reason for the PHP user to distinguish them and if yes, when? Is there any automatic way to handle them so PHP programmer wouldn't be concerned about them too much if he doesn't need to?
Hi wade,
The code block in the use cases section looks good. It looks a lot like other service classes, so that should keep the learning curve down : )
A few questions, suggestions:
- What are the specific requirements for this component? What must it be able to do and what not?
- Could you give an use-case where this component is integrated in the MVC structure?
- What about AMF0 support?
As for the mapping of AS -> PHP; The uint would probably become a regular PHP integer.
An Object could probably become a stdClass or ArrayObject instead of an associative array.
- Jurriƫn
ZF Home Page
Code Browser
Wiki Dashboard
Obviously more details would be helpful, but I'll forward this to Matthew so he can look at the general approach and make sure it's consistent with the rest of the framework.
2 items about naming:
This would result in the component name 'Zend_Amf'.
Thanks.
,Wil