In my usual style I’ve jumped into the deep end without fully knowing what I’m doing!
I’m working away trying to represent some classes in a manner explained here:
http://www.agiledata.org/essays/mappingObjects.html#Figure9GenericDataSchema
This is a different style of persisting object data than I’ve seen in the xPDO examples and in discussion here. After reading through that essay I’ve come to realize that there are several valid strategies for persisting objects relationally, and I’m curious to see just how flexible xPDO really is. So far I have a good deal of faith in it.
What I’m hoping to accomplish using this approach is to be able to dynamically create objects, assign arbitrary attributes to them, persist them and to eventually describe the relationships between them.. all without requiring any change to the database schema. In terms of the php classes, I guess it’ll be like hand-coding them with a huge leg-up provided by xPDO-generated scaffolding.
To describe my problem in an abstract way, I:
- created an Object A1
- created an Object B1 and B2, and related them to Object A1 (many B’s can be related to an A)
- created Object C1 and related it to Object B1(many C’s can be related to a B)
- created Object C2 and C3 and related them to Object B2
- save()’d Object A1 and automagically persisted all objects described above (whoo hoo)
Then I wanted to load up the whole mess with as little code as I could, so I came across the hydrateGraphNode() function.
What I found was that I got Object A1 back, with related Objects B1 and B2, but no Object C’s.
I traced through the code and eventually found a place where the Object C’s were indeed being assigned to Object B’s.. but still weren’t making it back out into my Object A.
After looking at what was happening, I found that I had to make a couple of changes to the hydrateGraphNode() function.
This is my modified version of the function, commented where altered:
function hydrateGraphNode(& $row, & $instance, $alias, $relations) {
$relObj= null;
if ($relationMeta= $instance->getFKDefinition($alias)) {
if ($relObj= $this->xpdo->newObject($relationMeta['class'])) {
$prefix= $alias . '_';
$relObj->fromArray($row, $prefix, true);
$relObj->_new= false;
$relObj->_dirty= array ();
if (strtolower($relationMeta['cardinality']) == 'many') {
$instance->addMany($relObj, $alias);
}
else {
$instance->addOne($relObj, $alias);
}
}
}
if (!empty ($relations) && is_object($relObj)) {
// nP: when recursively calling hydrateGraphNode, we need $instance
// to be a reference to items just added via addMany or addOne, or else
// we end up adding the subrelations to copies that don't go anywhere
if(isset($relObj->_alias) && is_array($instance->_relatedObjects[$relObj->_alias])) {
$relKeys= array_keys($instance->_relatedObjects[$relObj->_alias]);
foreach($relKeys as $relKey) {
$refObj= & $instance->_relatedObjects[$relObj->_alias][$relKey];
foreach ($relations as $relationAlias => $subRelations) {
// nP: in some cases, the $subRelation array will be empty, but we'll still want to run hydrateGraphNode with the relation represented by relationAlias
if(is_array($subRelations) && count($subRelations) > 0) {
foreach ($subRelations as $subRelation) {
$this->hydrateGraphNode($row, $refObj, $relationAlias, $subRelation);
}
} else {
$this->hydrateGraphNode($row, $refObj, $relationAlias, null);
}
}
}
}
}
}
Now when I call
$myCategory = $xpdo->getObjectGraph('aliasA', array('aliasB'=>array('aliasC'=>array())));
I get the whole happy heap of objects back all nicely related inside $myCategory.
I am not familiar enough with xPDO yet to know whether this is a sane approach or if I even approached the problem-solving properly.