From 1fe943d6f1814cd3756d71c035d2b69fc36ce066 Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Wed, 6 Aug 2014 06:49:04 +0900 Subject: [PATCH] Fix afterFind() called twice with belongsTo and hasOne relationships Refs #2268 --- lib/Cake/Model/Datasource/DboSource.php | 4 +- .../Case/Model/Datasource/DboSourceTest.php | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index face8b632..5aed9c991 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -1316,6 +1316,7 @@ class DboSource extends DataSource { foreach ($resultSet as &$row) { if ($type === 'hasOne' || $type === 'belongsTo' || $type === 'hasMany') { $assocResultSet = array(); + $prefetched = false; if ( ($type === 'hasOne' || $type === 'belongsTo') && @@ -1326,6 +1327,7 @@ class DboSource extends DataSource { if (!empty($joinedData)) { $assocResultSet[0] = array($LinkModel->alias => $row[$LinkModel->alias]); } + $prefetched = true; } else { $query = $this->insertQueryData($queryTemplate, $row, $association, $Model, $stack); if ($query !== false) { @@ -1376,7 +1378,7 @@ class DboSource extends DataSource { $this->_mergeAssociation($row, $assocResultSet, $association, $type, $selfJoin); } - if ($type !== 'hasAndBelongsToMany' && isset($row[$association])) { + if ($type !== 'hasAndBelongsToMany' && isset($row[$association]) && !$prefetched) { $row[$association] = $LinkModel->afterFind($row[$association], false); } diff --git a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php index 731b309ec..562e314d9 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php @@ -1456,4 +1456,51 @@ class DboSourceTest extends CakeTestCase { $result = $db->defaultConditions($Article, null); $this->assertFalse($result); } + +/** + * Test that count how many times is afterFind called + * + * @return void + */ + public function testCountAfterFindCalls() { + $this->loadFixtures('Article', 'User', 'Comment', 'Attachment', 'Tag', 'ArticlesTag'); + + // Use alias to make testing "primary = true" easy + $Primary = $this->getMock('Comment', array('afterFind'), array(array('alias' => 'Primary')), '', true); + $Primary->expects($this->any())->method('afterFind')->will($this->returnArgument(0)); + + $Article = $this->getMock('Article', array('afterFind'), array(), '', true); + $User = $this->getMock('User', array('afterFind'), array(), '', true); + $Comment = $this->getMock('Comment', array('afterFind'), array(), '', true); + $Tag = $this->getMock('Tag', array('afterFind'), array(), '', true); + $Attachment = $this->getMock('Attachment', array('afterFind'), array(), '', true); + + $Primary->Article = $Article; + $Primary->Article->User = $User; + $Primary->Article->Tag = $Tag; + $Primary->Article->Comment = $Comment; + $Primary->Attachment = $Attachment; + $Primary->Attachment->Comment = $Comment; + $Primary->User = $User; + + // primary = true + $Primary->expects($this->once()) + ->method('afterFind')->with($this->anything(), $this->isTrue())->will($this->returnArgument(0)); + + // primary = false + $Article->expects($this->once()) // Primary belongs to 1 Article + ->method('afterFind')->with($this->anything(), $this->isFalse())->will($this->returnArgument(0)); + $User->expects($this->exactly(2)) // Article belongs to 1 User and Primary belongs to 1 User + ->method('afterFind')->with($this->anything(), $this->isFalse())->will($this->returnArgument(0)); + $Tag->expects($this->exactly(2)) // Article has 2 Tags + ->method('afterFind')->with($this->anything(), $this->isFalse())->will($this->returnArgument(0)); + $Comment->expects($this->exactly(3)) // Article has 2 Comments and Attachment belongs to 1 Comment + ->method('afterFind')->with($this->anything(), $this->isFalse())->will($this->returnArgument(0)); + $Attachment->expects($this->once()) // Primary has 1 Attachment + ->method('afterFind')->with($this->anything(), $this->isFalse())->will($this->returnArgument(0)); + + $result = $Primary->find('first', array('conditions' => array('Primary.id' => 5), 'recursive' => 2)); + $this->assertCount(2, $result['Article']['Tag']); + $this->assertCount(2, $result['Article']['Comment']); + } }