diff --git a/src/ORM/EagerLoader.php b/src/ORM/EagerLoader.php index 91fb707246d..38b34d54c90 100644 --- a/src/ORM/EagerLoader.php +++ b/src/ORM/EagerLoader.php @@ -104,7 +104,7 @@ public function contain($associations = []) { } $associations = $this->_reformatContain($associations, $this->_containments); - $this->_normalized = null; + $this->_normalized = $this->_loadExternal = null; return $this->_containments = $associations; } @@ -149,7 +149,7 @@ public function matching($assoc, callable $builder = null) { */ public function normalized(Table $repository) { if ($this->_normalized !== null || empty($this->_containments)) { - return $this->_normalized; + return (array)$this->_normalized; } $contain = []; @@ -169,20 +169,6 @@ public function normalized(Table $repository) { return $this->_normalized = $contain; } -/** - * Returns whether or not there are associations that need to be loaded by - * decorating results from a query and executing a separate one for injecting - * them. - * - * @param \Cake\ORM\Table $repository The table containing the associations described in - * the `contain` array - * @return boolean - */ - protected function _hasExternal(Table $repository) { - $this->normalized($repository); - return !empty($this->_loadExternal); - } - /** * Formats the containments array so that associations are always set as keys * in the array. This function merges the original associations array with @@ -276,6 +262,27 @@ public function attachableAssociations(Table $repository) { return $this->_resolveJoins($contain); } +/** + * Returns an array with the associations that need to be fetched using a + * separate query, each array value will contain the following keys: + * + * - instance: the association object instance + * - config: the options set for fetching such association + * + * @param \Cake\ORM\Table $repository The table containing the associations + * to be loaded + * @return array + */ + public function externalAssociations(Table $repository) { + if ($this->_loadExternal) { + return $this->_loadExternal; + } + + $contain = $this->normalized($repository); + $this->_resolveJoins($contain); + return $this->_loadExternal; + } + /** * Auxiliary function responsible for fully normalizing deep associations defined * using `contain()` @@ -329,7 +336,7 @@ protected function _resolveJoins($associations) { $result[$table] = $options; $result += $this->_resolveJoins($options['associations']); } else { - $this->_loadExternal[$table] = $options; + $this->_loadExternal[] = $options; } } return $result; @@ -345,13 +352,14 @@ protected function _resolveJoins($associations) { * @return CallbackStatement $statement modified statement with extra loaders */ public function loadExternal($query, $statement) { - if (!$this->_hasExternal($query->repository())) { + $external = $this->externalAssociations($query->repository()); + if (empty($external)) { return $statement; } $driver = $query->connection()->driver(); - list($collected, $statement) = $this->_collectKeys($query, $statement); - foreach ($this->_loadExternal as $meta) { + list($collected, $statement) = $this->_collectKeys($external, $query, $statement); + foreach ($external as $meta) { $contain = $meta['associations']; $alias = $meta['instance']->source()->alias(); $keys = isset($collected[$alias]) ? $collected[$alias] : null; @@ -368,13 +376,14 @@ public function loadExternal($query, $statement) { * Helper function used to return the keys from the query records that will be used * to eagerly load associations. * - * @param \Cake\ORM\Query $query + * @param array $external the list of external associations to be loaded + * @param \Cake\ORM\Query $query The query from which the results where generated * @param BufferedStatement $statement * @return array */ - protected function _collectKeys($query, $statement) { + protected function _collectKeys($external, $query, $statement) { $collectKeys = []; - foreach ($this->_loadExternal as $meta) { + foreach ($external as $meta) { $source = $meta['instance']->source(); if ($meta['instance']->requiresKeys($meta['config'])) { $alias = $source->alias();