Browse Source

Merge pull request #4175 from chinpei215/master-issue2268-fix

Fix afterFind() called twice with belongsTo and hasOne relationships
José Lorenzo Rodríguez 11 years ago
parent
commit
64e74cbaac

+ 3 - 1
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);
 				}
 

+ 47 - 0
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']);
+	}
 }