Skip to content
Permalink
Browse files

Implemented eager loading for HasMany and multiple foreignKeys

  • Loading branch information...
lorenzo committed Jan 12, 2014
1 parent cd086e8 commit 75ab7776a47cc9d41fe9bc7b9b28b473b0cdaa30
@@ -17,6 +17,7 @@
namespace Cake\ORM\Association;
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\TupleComparison;
use Cake\ORM\Query;
use Cake\Utility\Inflector;
@@ -164,8 +165,13 @@ protected function _resultInjector($fetchQuery, $resultMap) {
$sourceKeys[] = key($fetchQuery->aliasField($key, $sAlias));
}
$sourceKey = implode(';', $sourceKeys);
$nestKey = $tAlias . '__' . $tAlias;
if (count($sourceKeys) > 1) {
return $this->_multiKeysInjector($resultMap, $sourceKeys, $nestKey);
}
$sourceKey = $sourceKeys[0];
return function($row) use ($resultMap, $sourceKey, $nestKey) {
if (isset($resultMap[$row[$sourceKey]])) {
$row[$nestKey] = $resultMap[$row[$sourceKey]];
@@ -174,6 +180,21 @@ protected function _resultInjector($fetchQuery, $resultMap) {
};
}
protected function _multiKeysInjector($resultMap, $sourceKeys, $nestKey) {
return function($row) use ($resultMap, $sourceKeys, $nestKey) {
$values = [];
foreach ($sourceKeys as $key) {
$values[] = $row[$key];
}
$key = implode(';', $values);
if (isset($resultMap[$key])) {
$row[$nestKey] = $resultMap[$key];
}
return $row;
};
}
/**
* Auxiliary function to construct a new Query object to return all the records
* in the target table that are associated to those specified in $options from
@@ -234,6 +255,10 @@ protected function _buildQuery($options) {
* @return \Cake\ORM\Query
*/
protected function _addFilteringCondition($query, $key, $filter) {
if (is_array($key)) {
$tuple = new TupleComparison($key, $filter, [], 'IN');
return $query->andWhere($tuple);
}
return $query->andWhere([$key . ' IN' => $filter]);
}
@@ -245,7 +270,18 @@ protected function _addFilteringCondition($query, $key, $filter) {
* @return string
*/
protected function _linkField($options) {
return sprintf('%s.%s', $this->name(), $options['foreignKey']);
$links = [];
$name = $this->name();
foreach ((array)$options['foreignKey'] as $key) {
$links[] = sprintf('%s.%s', $name, $key);
}
if (count($links) === 1) {
return $links[0];
}
return $links;
}
/**
@@ -91,9 +91,14 @@ public function eagerLoader(array $options) {
}
$resultMap = [];
$key = $options['foreignKey'];
$key = (array)$options['foreignKey'];
foreach ($fetchQuery->all() as $result) {
$resultMap[$result[$key]][] = $result;
$values = [];
foreach ($key as $k) {
$values[] = $result[$k];
}
$resultMap[implode(';', $values)][] = $result;
}
return $this->_resultInjector($fetchQuery, $resultMap);
@@ -414,6 +414,48 @@ public function testEagerLoaderWithQueryBuilder() {
$association->eagerLoader(compact('keys', 'query', 'queryBuilder'));
}
/**
* Test the eager loader method with no extra options
*
* @return void
*/
public function testEagerLoaderMultipleKeys() {
$config = [
'sourceTable' => $this->author,
'targetTable' => $this->article,
'strategy' => 'select',
'foreignKey' => ['author_id', 'site_id']
];
$this->author->primaryKey(['id', 'site_id']);
$association = new HasMany('Articles', $config);
$keys = [[1, 10], [2, 20], [3, 30], [4, 40]];
$query = $this->getMock('Cake\ORM\Query', ['all'], [null, null]);
$this->article->expects($this->once())->method('find')->with('all')
->will($this->returnValue($query));
$results = [
['id' => 1, 'title' => 'article 1', 'author_id' => 2, 'site_id' => 10],
['id' => 2, 'title' => 'article 2', 'author_id' => 1, 'site_id' => 20]
];
$query->expects($this->once())->method('all')
->will($this->returnValue($results));
$callable = $association->eagerLoader(compact('keys', 'query'));
$row = ['Authors__id' => 2, 'Authors__site_id' => 10, 'username' => 'author 1'];
$result = $callable($row);
$row['Articles__Articles'] = [
['id' => 1, 'title' => 'article 1', 'author_id' => 2, 'site_id' => 10]
];
$this->assertEquals($row, $result);
$row = ['Authors__id' => 1, 'username' => 'author 2', 'Authors__site_id' => 20];
$result = $callable($row);
$row['Articles__Articles'] = [
['id' => 2, 'title' => 'article 2', 'author_id' => 1, 'site_id' => 20]
];
$this->assertEquals($row, $result);
}
/**
* Tests that the correct join and fields are attached to a query depending on
* the association config

0 comments on commit 75ab777

Please sign in to comment.
You can’t perform that action at this time.