[2.X] xPDO::getMany/_getRelatedObjectsByFK hard-caches the first request
I don't know if this is by design, but we've stumbled upon a weird issue, one I did not expect from xPDO.
On line 1149, function xPDOObject::&getMany(), there is an instant protected call to xPDOObject::&_getRelatedObjectsByFK(). The default usage of getMany, as documented by various docs online, is a simple call on a Car with Wheels or a Box with Crayons.
$wheels = $car->getMany('Wheels');
Alright, seems simple enough. But hey, I'd only like the front wheels please.
$wheels = $car->getMany('Wheels', array('position' => 'front'));
Nice. Works fine as well. Now, I'd like to split them bad boys up and show both the front and the back wheels in one call, one script.
$wheels = array(
'front' => $car->getMany('Wheels', array('position' => 'front')),
'rear' => $car->getMany('Wheels', array('position' => 'rear'))
);
Now, the shit just hit the fan. I've got two identical arrays in there, both showing only the front wheels. What's goin' on here?! Ah, I see.
xPDOQuery::&_getRelatedObjectsByFK() at line #2223 through #2260.
/**
* Gets related objects by a foreign key and specified criteria.
*
* @access protected
* @param string $alias The alias representing the relationship.
* @param mixed An optional xPDO criteria expression.
* @param boolean|integer Indicates if the saved object(s) should
* be cached and optionally, by specifying an integer value, for how many
* seconds before expiring. Overrides the cacheFlag for the object.
* @return array A collection of objects matching the criteria.
*/
protected function & _getRelatedObjectsByFK($alias, $criteria= null, $cacheFlag= true) {
$collection= array ();
if (isset($this->_relatedObjects[$alias]) && (is_object($this->_relatedObjects[$alias]) || (is_array($this->_relatedObjects[$alias]) && !empty ($this->_relatedObjects[$alias])))) {
$collection= & $this->_relatedObjects[$alias];
} else {
/** $criteria logic **/
if ($collection= $this->xpdo->getCollection($fkMeta['class'], $criteria, $cacheFlag)) {
$this->_relatedObjects[$alias]= array_diff_key($this->_relatedObjects[$alias], $collection) + $collection;
}
}
return $collection;
}
As the first getMany iterated with absolutely stunning success, the second call simply jumps into the internal _relatedObjects stack, finds "Wheels" (e.g. $car->_relatedObjects['Wheels']) and returns that. So why is there a $criteria argument? Why is every call after the first ignored? Why is there an Composite ALIAS name cache in place instead of a xPDOQuery object cache of sorts?
I am at a loss of understanding this. Basically every usage after the first is redundant now. I will not accept this being the final code as this doesn't make any sense in terms of related object fetching which I know works a lot different in ORMs like Doctrine.
Copied from https://github.com/modxcms/revolution/issues/12331