Merge branch '2.2-orm-queries' into 2.2

Fixes #2860
This commit is contained in:
mark_story 2012-05-27 20:44:46 -04:00
commit a5f278319d
2 changed files with 77 additions and 3 deletions

View file

@ -1080,6 +1080,7 @@ class DboSource extends DataSource {
$query = trim($this->generateAssociationQuery($model, null, null, null, null, $queryData, false, $null)); $query = trim($this->generateAssociationQuery($model, null, null, null, null, $queryData, false, $null));
$resultSet = $this->fetchAll($query, $model->cacheQueries); $resultSet = $this->fetchAll($query, $model->cacheQueries);
if ($resultSet === false) { if ($resultSet === false) {
$model->onError(); $model->onError();
return false; return false;
@ -1092,6 +1093,10 @@ class DboSource extends DataSource {
} }
if ($model->recursive > -1) { if ($model->recursive > -1) {
$joined = array();
if (isset($queryData['joins'][0]['alias'])) {
$joined[$model->alias] = (array)Hash::extract($queryData['joins'], '{n}.alias');
}
foreach ($_associations as $type) { foreach ($_associations as $type) {
foreach ($model->{$type} as $assoc => $assocData) { foreach ($model->{$type} as $assoc => $assocData) {
$linkModel = $model->{$assoc}; $linkModel = $model->{$assoc};
@ -1108,6 +1113,7 @@ class DboSource extends DataSource {
if (isset($db) && method_exists($db, 'queryAssociation')) { if (isset($db) && method_exists($db, 'queryAssociation')) {
$stack = array($assoc); $stack = array($assoc);
$stack['_joined'] = $joined;
$db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack); $db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack);
unset($db); unset($db);
@ -1176,6 +1182,11 @@ class DboSource extends DataSource {
* @throws CakeException when results cannot be created. * @throws CakeException when results cannot be created.
*/ */
public function queryAssociation(Model $model, &$linkModel, $type, $association, $assocData, &$queryData, $external, &$resultSet, $recursive, $stack) { public function queryAssociation(Model $model, &$linkModel, $type, $association, $assocData, &$queryData, $external, &$resultSet, $recursive, $stack) {
if (isset($stack['_joined'])) {
$joined = $stack['_joined'];
unset($stack['_joined']);
}
if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) { if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) {
if (!is_array($resultSet)) { if (!is_array($resultSet)) {
throw new CakeException(__d('cake_dev', 'Error in Model %s', get_class($model))); throw new CakeException(__d('cake_dev', 'Error in Model %s', get_class($model)));
@ -1251,10 +1262,17 @@ class DboSource extends DataSource {
foreach ($resultSet as &$row) { foreach ($resultSet as &$row) {
if ($type !== 'hasAndBelongsToMany') { if ($type !== 'hasAndBelongsToMany') {
$q = $this->insertQueryData($query, $row, $association, $assocData, $model, $linkModel, $stack); $q = $this->insertQueryData($query, $row, $association, $assocData, $model, $linkModel, $stack);
if ($q !== false) {
$fetch = $this->fetchAll($q, $model->cacheQueries);
} else {
$fetch = null; $fetch = null;
if ($q !== false) {
$joinedData = array();
if (($type === 'belongsTo' || $type === 'hasOne') && isset($row[$linkModel->alias], $joined[$model->alias]) && in_array($linkModel->alias, $joined[$model->alias])) {
$joinedData = Hash::filter($row[$linkModel->alias]);
if (!empty($joinedData)) {
$fetch[0] = array($linkModel->alias => $row[$linkModel->alias]);
}
} else {
$fetch = $this->fetchAll($q, $model->cacheQueries);
}
} }
} }
$selfJoin = $linkModel->name === $model->name; $selfJoin = $linkModel->name === $model->name;

View file

@ -767,6 +767,62 @@ class DboSourceTest extends CakeTestCase {
$this->assertTrue(is_array($result)); $this->assertTrue(is_array($result));
} }
/**
* test that queryAssociation() reuse already joined data for 'belongsTo' and 'hasOne' associations
* instead of running unneeded queries for each record
*
* @return void
*/
public function testQueryAssociationUnneededQueries() {
$this->loadFixtures('Article', 'User', 'Comment', 'Attachment', 'Tag', 'ArticlesTag');
$Comment = new Comment;
$fullDebug = $this->db->fullDebug;
$this->db->fullDebug = true;
$Comment->find('all', array('recursive' => 2)); // ensure Model descriptions are saved
$this->db->getLog();
// case: Comment belongsTo User and Article
$Comment->unbindModel(array(
'hasOne' => array('Attachment')
));
$Comment->Article->unbindModel(array(
'belongsTo' => array('User'),
'hasMany' => array('Comment'),
'hasAndBelongsToMany' => array('Tag')
));
$Comment->find('all', array('recursive' => 2));
$log = $this->db->getLog();
$this->assertEquals(1, count($log['log']));
// case: Comment belongsTo Article, Article belongsTo User
$Comment->unbindModel(array(
'belongsTo' => array('User'),
'hasOne' => array('Attachment')
));
$Comment->Article->unbindModel(array(
'hasMany' => array('Comment'),
'hasAndBelongsToMany' => array('Tag'),
));
$Comment->find('all', array('recursive' => 2));
$log = $this->db->getLog();
$this->assertEquals(7, count($log['log']));
// case: Comment hasOne Attachment
$Comment->unbindModel(array(
'belongsTo' => array('Article', 'User'),
));
$Comment->Attachment->unbindModel(array(
'belongsTo' => array('Comment'),
));
$Comment->find('all', array('recursive' => 2));
$log = $this->db->getLog();
$this->assertEquals(1, count($log['log']));
$this->db->fullDebug = $fullDebug;
}
/** /**
* test that fields() is using methodCache() * test that fields() is using methodCache()
* *