
|
If you were logged in you would be able to see more operations.
|
Google issue summary
|
|
|
Defining the environment
I recognised those two problems trying to send Doctrine-models via AMF.
On PHP-side i have typical doctrine-classes in a specified relation:
abstract class BaseArea extends Doctrine_Record
{
public function setTableDefinition()
{
$this->setTableName('area');
$this->hasColumn('id', 'integer', 4, array('type' => 'integer', 'primary' => true, 'autoincrement' => true, 'length' => '4'));
$this->hasColumn('content_id', 'integer', 4, array('type' => 'integer', 'length' => '4'));
$this->hasColumn('followed_by', 'integer', 4, array('type' => 'integer', 'length' => '4'));
}
public function setUp()
{
$this->hasMany('Point as Points', array('local' => 'id',
'foreign' => 'area_id'));
}
}
abstract class BasePoint extends Doctrine_Record
{
public function setTableDefinition()
{
$this->setTableName('point');
$this->hasColumn('id', 'integer', 4, array('type' => 'integer', 'primary' => true, 'autoincrement' => true, 'length' => '4'));
$this->hasColumn('top', 'integer', 4, array('type' => 'integer', 'length' => '4'));
$this->hasColumn('left', 'integer', 4, array('type' => 'integer', 'length' => '4'));
$this->hasColumn('area_id', 'integer', 4, array('type' => 'integer', 'length' => '4'));
}
public function setUp()
{
$this->hasOne('Area', array('local' => 'area_id',
'foreign' => 'id'));
}
}
Normal access to depending objects (in this case Points) works like this in PHP:
$result = Doctrine::getTable('Area')->findAll();
foreach($result[0]->Points as $point) {
}
Points is a Doctrine_Collection implementing ArrayAccess.
First problem
Fetching an $area-instance from the db and sending it via AMF does not serialize the Points.
This happens because Zend_AMF does not know that there is a "hidden" property called "Points" as it is only handled via the magic functions __get and __set (see doctrine source code for this). Now thinking about how to solve this i think i know, that AMF cannot be changed to use a configuration parameter like "concernMagicProperties":
$server = new Zend_AMF_Server();
$server->concernMagicProperties = true;
Well. I think this is not possible (and maybe also not practical for all occasions). So i made the following change. Doctrine supports adding kind of "unused" fields like this:
$area->mapValue('_hiddenFields', array('Points'));
This makes sure Doctrine continues to work (and does not complain about integrity with the database) and Zend_AMF can access this property to find out which hidden fields should be serialized. In a normal environment with the same problem (not using Doctrine) this could be reached by an public property _hiddenFields which will not be serialized or, maybe more beautiful (this idea just comes to my mind), implementing a Zend_AMF_Value_MagicBehaviour:
interface Zend_AMF_Value_MagicBehaviour {
/** @return array ***/
public function getHiddenFields();
}
Second Problem
After changing Zend_AMF to implement the first behaviour (using the public property _hiddenFields) i recognised the second problem:
AMF serializes the Doctrine_Collection as a named object - which is entirely correct, but the problem is, that there must be a matching AS-class which would have required me to implement sort of my own AS-Doctrine-Collection with the big problem, that the property names are unknown at the time of compilation (the properties are called 1 2 3 4 5...) and as AS has no possibility to handle this - or i don't know it (no magic __set or so) - the only possibility was to change Zend_AMF so that this class gets serialized as an Array. AS has enough ways to change this array and send the list back.
To solve this i made a dirty hack in Zend_AMF to check whether the given object is an instance of Doctrine_Collection and handle it as array. More beautiful would be a similar behaviour as mentioned above:
interface Zend_AMF_Value_HandleAsArray {}
If a class implements this Interface, Zend_AMF should handle the object as an array (not only if it IS an array).
Summarizing there are two problems to solve:
- How can magic "hidden" properties be serialized
- How can classes that implement ArrrayAccess or extend ArrayObject be serialized as an Array
I documented my specific changes in a patch which might not be the best, but it was a fix for me to use Doctrine.
I would like to hear your opinion on this topic, also if there is another way of design.
(offtopic: btw: why doesn't zend framework trac has codeformatting for php? )
|
|
Description
|
Defining the environment
I recognised those two problems trying to send Doctrine-models via AMF.
On PHP-side i have typical doctrine-classes in a specified relation:
abstract class BaseArea extends Doctrine_Record
{
public function setTableDefinition()
{
$this->setTableName('area');
$this->hasColumn('id', 'integer', 4, array('type' => 'integer', 'primary' => true, 'autoincrement' => true, 'length' => '4'));
$this->hasColumn('content_id', 'integer', 4, array('type' => 'integer', 'length' => '4'));
$this->hasColumn('followed_by', 'integer', 4, array('type' => 'integer', 'length' => '4'));
}
public function setUp()
{
$this->hasMany('Point as Points', array('local' => 'id',
'foreign' => 'area_id'));
}
}
abstract class BasePoint extends Doctrine_Record
{
public function setTableDefinition()
{
$this->setTableName('point');
$this->hasColumn('id', 'integer', 4, array('type' => 'integer', 'primary' => true, 'autoincrement' => true, 'length' => '4'));
$this->hasColumn('top', 'integer', 4, array('type' => 'integer', 'length' => '4'));
$this->hasColumn('left', 'integer', 4, array('type' => 'integer', 'length' => '4'));
$this->hasColumn('area_id', 'integer', 4, array('type' => 'integer', 'length' => '4'));
}
public function setUp()
{
$this->hasOne('Area', array('local' => 'area_id',
'foreign' => 'id'));
}
}
Normal access to depending objects (in this case Points) works like this in PHP:
$result = Doctrine::getTable('Area')->findAll();
foreach($result[0]->Points as $point) {
}
Points is a Doctrine_Collection implementing ArrayAccess.
First problem
Fetching an $area-instance from the db and sending it via AMF does not serialize the Points.
This happens because Zend_AMF does not know that there is a "hidden" property called "Points" as it is only handled via the magic functions __get and __set (see doctrine source code for this). Now thinking about how to solve this i think i know, that AMF cannot be changed to use a configuration parameter like "concernMagicProperties":
$server = new Zend_AMF_Server();
$server->concernMagicProperties = true;
Well. I think this is not possible (and maybe also not practical for all occasions). So i made the following change. Doctrine supports adding kind of "unused" fields like this:
$area->mapValue('_hiddenFields', array('Points'));
This makes sure Doctrine continues to work (and does not complain about integrity with the database) and Zend_AMF can access this property to find out which hidden fields should be serialized. In a normal environment with the same problem (not using Doctrine) this could be reached by an public property _hiddenFields which will not be serialized or, maybe more beautiful (this idea just comes to my mind), implementing a Zend_AMF_Value_MagicBehaviour:
interface Zend_AMF_Value_MagicBehaviour {
/** @return array ***/
public function getHiddenFields();
}
Second Problem
After changing Zend_AMF to implement the first behaviour (using the public property _hiddenFields) i recognised the second problem:
AMF serializes the Doctrine_Collection as a named object - which is entirely correct, but the problem is, that there must be a matching AS-class which would have required me to implement sort of my own AS-Doctrine-Collection with the big problem, that the property names are unknown at the time of compilation (the properties are called 1 2 3 4 5...) and as AS has no possibility to handle this - or i don't know it (no magic __set or so) - the only possibility was to change Zend_AMF so that this class gets serialized as an Array. AS has enough ways to change this array and send the list back.
To solve this i made a dirty hack in Zend_AMF to check whether the given object is an instance of Doctrine_Collection and handle it as array. More beautiful would be a similar behaviour as mentioned above:
interface Zend_AMF_Value_HandleAsArray {}
If a class implements this Interface, Zend_AMF should handle the object as an array (not only if it IS an array).
Summarizing there are two problems to solve:
- How can magic "hidden" properties be serialized
- How can classes that implement ArrrayAccess or extend ArrayObject be serialized as an Array
I documented my specific changes in a patch which might not be the best, but it was a fix for me to use Doctrine.
I would like to hear your opinion on this topic, also if there is another way of design.
(offtopic: btw: why doesn't zend framework trac has codeformatting for php?  ) |
Show » |
Sort Order:
|
Here's a hack I wrote to send Doctrine models via AMF: http://cesaric.com/?p=303
. It'll get all the nested collections of a data graph and convert them to standard objects and ActionScript ArrayCollections.
On a similar note, any luck going the other way around in trying to send ActionScript objects over AMF to the corresponding Doctrine model object?
I can't seem to get ActionScript classes to map to the respective Doctrine model classes. I'm using the $server->setClassMap(); method and it works fine as long as I'm not mapping to a php class that extends "Doctrine_Record" (my BaseContact class below does extend Doctrine_Record). If I comment out "extends BaseContact" below, Zend_Amf type casts it just fine.
class Contact extends BaseContact
{
public function construct(){ $this->mapValue("_explicitType","com.example.vo.ContactVO"); }
}
Any suggestions? Btw, great work on Zend_Amf. It's coming along nicely!