New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.X] xPDO::getMany/_getRelatedObjectsByFK hard-caches the first request #60

ReSpawN opened this Issue Feb 6, 2015 · 0 comments


None yet
1 participant
Copy link

ReSpawN commented Feb 6, 2015

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 modxcms/revolution#12331

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment