Archive for the ‘CakePHP’ Category

AMFPHP Cake constructor arguments causing NetConnection.Call.BadVersion

Saturday, October 10th, 2009

So… you’re seeing “NetConnection.Call.BadVersion” from Flash while attempting to talk to CPAMF or AMFPHP.
Well my friend, there’s a good probability that something is wrong.
Here are some suggestions:

  1. Fatal Error
  2. Redirect

What I tracked my problem down to was the fact that the following happens when AMFPHP receives a Flash remote object (using remoting):

  1. AMFPHP receives an AMF stream
  2. AMFPHP inteprets the stream byte by byte
  3. AMFPHP decides what sort of “thing” that Flash has attempted to send back
  4. AMFPHP attempts to “find” the relevant PHP class, defined by the class alias that has been sent in Flash.
    e.g. Flash object is "com.org.my.namespace.path.MyClass"
    and interprets that as com/org/my/namespace/path/MyClass.php (or MyClass.class.php) based on the base classMappingPath you sent in the service gateway, $gateway->setClassMappingsPath( '/absolute/path/to/vo/models' );
    attempts to include it, and instantiate an object of MyClass (therefore your filename MUST match your class name).
    i.e. $clazz = new $classname;

So I realised a problem. Constructors, both in Flash and PHP MUST at all costs have default values for them, i.e. the constructor variables are optional, because AMFPHP and Flash don’t use the sent objects, they literally convert them to their relevant objects on each side.

Further info on problems and debugging NetConnection.Call.BedVersion in Flash and AMFPHP can be found by google of course.

Cpamf accepting VO objects in service calls as parameters

Monday, October 5th, 2009

Here’s the status:
Cake implementation of AMFPHP via the plugin cpamf appears to be lacking some particular documentation regarding “accepting” flash objects in calls.
i.e.
Flash -> PHP object conversion.

Sure you can send back flash objects no problem, and there are plenty of documented places that tell you how to send flash objects back from PHP using class mapping and there was even some information on the reverse using AMFPHP on how to map VO’s from Flex to PHP using AMFPHP, but what seemed to be lacking was some particular documentation on how to get CPAMF, cake’s own brand of AMFPHP working with Flex VO to PHP. Begin investigation:

I am indeed hoping that I can get my controllers to accept objects instead of parameters or arrays. Allowing the flash app to pass through an object instead of having to decide what parameters or format it should be returning each time.

e.g.
Controller | Method | Parameter
TestController->test(StandardVO $vo)

As cake does; it likes to have controllers and models for everything it does. Aren’t you a nice cake! *grumble*
So it’s written it’s own CakeGateway.php class to extend the PHPAMF Gateway class, overriding action calls for the gateway. Aside from overriding them all and not calling the parent::registerActionChain() that seems to be fine.
A little hunt through the documentation/notes and general settings in globals.php seems to indicate that you can set the directory for controllers and vo classes. Great I think; changing these values should resolve my problem. If only!

The CakeGateway class appears to initialise the gateway with it’s own set of parameters for the controllers, sensibly (for a change) reading cake’s default controllers folder. Thus, all appears to be working within the /cpamf/browser , but still without the ability to pass objects, DOH!
The voPath mapping that appears to be set from the original globals file points to “services/vo”, i’m assuming this is supposed to indicate the current directory is the base and the services/vo folder is the one containing the vo’s. Thus, following some logical thinking I begin to stuck some classes in various folders that cake might just be reading.
In goes a StandardVo class, in the models/ directory and also inside the plugins/cpamf/vendors/amfphp/services/vo directory, try again. Nope still not recognising my object.
Ok, I know Cake’s naming convention is totally crap, lets try naming the file standard_vo.php instead of StandardVo.php . Still nothing, despite being implemented in both directories.

A few hours later, and after a fair amount of digging around in AMFPHP I came across what looked like some form of include()’ing. Having managed to stop the flash from doing it’s thing an instead die()’ing in certain places, I realised that this part here was responsible for loading in the PHP class to map to (lines 351-396 of /plugins/cpamf/vendors/amfphp/core/amf/io/AMFBaseDeserializer.php). Stepping through the logic I saw it: “$mappedClass = str_replace(’.', ‘/’, $typeIdentifier);”
The mapClass() function was doing the magic; interpreting the type of the flash object (which seemed to resolve to a full package name) into an include. AH HAH! It was also resolving it relative to the customMappingsPath which we saw earlier was set in CakeGateway class (cake_gateway.php).
So it would seem that AMFPHP was expecting to see a full package naming convention for all the Flash Objects it was going to receive.

I headed back to the CakeGateway class and amended the setCllassMappingPath() to

// This is the path to the Vo models!
$gateway->setClassMappingsPath( MODELS . 'vo' );

I then created a “vo” directory inside the cake models directory, and further proceeded to mimic the flash namespace package path.
models/vo/com/test/StandardVo.php , et VOILA! Problem resolved; cpamf now knows which object it is receiving and fills it with the data received from the flash object.

Now back to pulling out some hair over other issues.

CakePHP doesn’t like autoload() with vendor app import!

Tuesday, September 22nd, 2009

So, it would seem that if you decide that you want your vendor plugin to work nicely with cake, by having it conform to Pear folder directory structure and naming convention, and then right yourself a nice autoload() function to register with php (via spl_autoload_register()), you CANNOT use the App::import alongside this.
Why? Because Cake’s lovely App::import does a require() not a require_once()… Go figure!

So here is the problem:
You have App::import()’d your vendor plugin. It registers itself as an autoloader.
You have your 2nd vendor plugin, (which conforms to a Pear style structure also).
You explicitly App::import(’vendor’,'2nd item’,array(’file’=>’path/to/vendor/file.php’));
Cake has a fit and dies saying you “cannot redeclare “.
Brilliant Cake well done! Another reason to use Zend Framework…

As a solution I have altered the cake source code to make sure the require() is in fact a require_once(). I have yet to see the impact of such a change on any other import()’s. See below for alteration:
File: cake/libs/configure.php
Line: 975
Previous: “require($file);”
Change: “require_once($file);”