From 0ef028bc1f5c8bf67ee51aa17e22b0d5fba30944 Mon Sep 17 00:00:00 2001 From: phpnut Date: Wed, 26 Mar 2008 11:17:24 +0000 Subject: [PATCH] "Fixing self associated joins. Added additional test cases and correct one bad test case. Fixes #4364, !__mergeAssociation() in dbo_source fails to merge belongsTo properly" git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@6606 3807eeeb-6ff5-0310-8944-8be069107fe0 --- cake/libs/model/datasources/dbo_source.php | 21 +++++--- cake/tests/cases/libs/model/model.test.php | 60 ++++++++++++++++++---- cake/tests/cases/libs/model/models.php | 19 ++++++- cake/tests/fixtures/people_fixture.php | 53 +++++++++++++++++++ 4 files changed, 135 insertions(+), 18 deletions(-) create mode 100644 cake/tests/fixtures/people_fixture.php diff --git a/cake/libs/model/datasources/dbo_source.php b/cake/libs/model/datasources/dbo_source.php index ac55e07a5..62d5e5044 100644 --- a/cake/libs/model/datasources/dbo_source.php +++ b/cake/libs/model/datasources/dbo_source.php @@ -752,14 +752,19 @@ class DboSource extends DataSource { $fetch = null; } } + $selfJoin = false; + + if ($linkModel->name === $model->name) { + $selfJoin = true; + } if (!empty($fetch) && is_array($fetch)) { if ($recursive > 0) { foreach ($linkModel->__associations as $type1) { foreach ($linkModel->{$type1} as $assoc1 => $assocData1) { - $deepModel =& $linkModel->{$assoc1}; + if (($type1 === 'belongsTo') || ($deepModel->alias === $model->alias && $type === 'belongsTo') || ($deepModel->alias != $model->alias)) { $tmpStack = $stack; $tmpStack[] = $assoc1; @@ -795,13 +800,13 @@ class DboSource extends DataSource { $this->__mergeAssociation($resultSet[$i], $merge, $association, $type); } } else { - $this->__mergeAssociation($resultSet[$i], $fetch, $association, $type); + $this->__mergeAssociation($resultSet[$i], $fetch, $association, $type, $selfJoin); } $resultSet[$i][$association] = $linkModel->afterfind($resultSet[$i][$association]); } else { $tempArray[0][$association] = false; - $this->__mergeAssociation($resultSet[$i], $tempArray, $association, $type); + $this->__mergeAssociation($resultSet[$i], $tempArray, $association, $type, $selfJoin); } } } @@ -854,9 +859,9 @@ class DboSource extends DataSource { * @param unknown_type $merge * @param unknown_type $association * @param unknown_type $type + * @param boolean $selfJoin */ - function __mergeAssociation(&$data, $merge, $association, $type) { - + function __mergeAssociation(&$data, $merge, $association, $type, $selfJoin = false) { if (isset($merge[0]) && !isset($merge[0][$association])) { $association = Inflector::pluralize($association); } @@ -891,13 +896,17 @@ class DboSource extends DataSource { $mergeAssocTmp[$k] = $v; } } + $dataKeys = array_keys($data); + $mergeKeys = array_keys($merge[0]); - if (array_keys($merge[0]) === array_keys($data)) { + if ($mergeKeys[0] === $dataKeys[0] || $mergeKeys === $dataKeys) { $data[$association][$association] = $merge[0][$association]; } else { $diff = Set::diff($dataAssocTmp, $mergeAssocTmp); $data[$association] = array_merge($merge[0][$association], $diff); } + } elseif ($selfJoin && array_key_exists($association, $merge[0])) { + $data[$association] = array_merge($data[$association], array($association => array())); } } } diff --git a/cake/tests/cases/libs/model/model.test.php b/cake/tests/cases/libs/model/model.test.php index f2c3be293..94b519d70 100644 --- a/cake/tests/cases/libs/model/model.test.php +++ b/cake/tests/cases/libs/model/model.test.php @@ -48,7 +48,7 @@ class ModelTest extends CakeTestCase { 'core.syfile', 'core.image', 'core.device_type', 'core.device_type_category', 'core.feature_set', 'core.exterior_type_category', 'core.document', 'core.device', 'core.document_directory', 'core.primary_model', 'core.secondary_model', 'core.something', 'core.something_else', 'core.join_thing', 'core.join_a', 'core.join_b', 'core.join_c', 'core.join_a_b', 'core.join_a_c', - 'core.uuid', 'core.data_test', 'core.posts_tag', 'core.the_paper_monkies' + 'core.uuid', 'core.data_test', 'core.posts_tag', 'core.the_paper_monkies', 'core.people' ); function start() { @@ -375,6 +375,42 @@ class ModelTest extends CakeTestCase { $this->assertEqual($result, $expected); } + function testFindSelfAssociations() { + $this->loadFixtures('People'); + $this->model =& new Person(); + $this->model->recursive = 2; + $result = $this->model->read(null, 1); + $expected = array( + 'Person' => array('id' => 1, 'name' => 'person', 'mother_id' => 2, 'father_id' => 3), + 'Mother' => array('id' => 2, 'name' => 'mother', 'mother_id' => 4, 'father_id' => 5, + 'Mother' => array('id' => 4, 'name' => 'mother - grand mother', 'mother_id' => 0, 'father_id' => 0), + 'Father' => array('id' => 5, 'name' => 'mother - grand father', 'mother_id' => 0, 'father_id' => 0)), + 'Father' => array('id' => 3, 'name' => 'father', 'mother_id' => 6, 'father_id' => 7, + 'Father' => array('id' => 7, 'name' => 'father - grand father', 'mother_id' => 0, 'father_id' => 0), + 'Mother' => array('id' => 6, 'name' => 'father - grand mother', 'mother_id' => 0, 'father_id' => 0))); + $this->assertEqual($result, $expected); + + $this->model->recursive = 3; + $result = $this->model->read(null, 1); + $expected = array( + 'Person' => array('id' => 1, 'name' => 'person', 'mother_id' => 2, 'father_id' => 3), + 'Mother' => array('id' => 2, 'name' => 'mother', 'mother_id' => 4, 'father_id' => 5, + 'Mother' => array('id' => 4, 'name' => 'mother - grand mother', 'mother_id' => 0, 'father_id' => 0, + 'Mother' => array(), + 'Father' => array()), + 'Father' => array('id' => 5, 'name' => 'mother - grand father', 'mother_id' => 0, 'father_id' => 0, + 'Father' => array(), + 'Mother' => array())), + 'Father' => array('id' => 3, 'name' => 'father', 'mother_id' => 6, 'father_id' => 7, + 'Father' => array('id' => 7, 'name' => 'father - grand father', 'mother_id' => 0, 'father_id' => 0, + 'Father' => array(), + 'Mother' => array()), + 'Mother' => array('id' => 6, 'name' => 'father - grand mother', 'mother_id' => 0, 'father_id' => 0, + 'Mother' => array(), + 'Father' => array()))); + $this->assertEqual($result, $expected); + } + function testIdentity() { $this->model =& new Test(); $result = $this->model->alias; @@ -590,30 +626,34 @@ class ModelTest extends CakeTestCase { $this->db->fullDebug = true; $this->model->recursive = 6; $result = $this->model->findAll(null, null, 'CategoryThread.id ASC'); - $expected = array( array('CategoryThread' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'), - 'ParentCategory' => array('id' => null, 'parent_id' => null, 'name' => null, 'created' => null, 'updated' => null)), + 'ParentCategory' => array('id' => null, 'parent_id' => null, 'name' => null, 'created' => null, 'updated' => null, 'ParentCategory' => array())), array('CategoryThread' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'), - 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31')), + 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', + 'ParentCategory' => array())), array('CategoryThread' => array('id' => 3, 'parent_id' => 2, 'name' => 'Category 1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'), 'ParentCategory' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', - 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'))), + 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', + 'ParentCategory' => array()))), array('CategoryThread' => array('id' => 4, 'parent_id' => 3, 'name' => 'Category 1.1.2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'), 'ParentCategory' => array('id' => 3, 'parent_id' => 2, 'name' => 'Category 1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', 'ParentCategory' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', - 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31')))), + 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', + 'ParentCategory' => array())))), array('CategoryThread' => array('id' => 5, 'parent_id' => 4, 'name' => 'Category 1.1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'), 'ParentCategory' => array('id' => 4, 'parent_id' => 3, 'name' => 'Category 1.1.2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', 'ParentCategory' => array('id' => 3, 'parent_id' => 2, 'name' => 'Category 1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', 'ParentCategory' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', - 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'))))), + 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', + 'ParentCategory' => array()))))), array('CategoryThread' => array('id' => 6, 'parent_id' => 5, 'name' => 'Category 2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'), 'ParentCategory' => array('id' => 5, 'parent_id' => 4, 'name' => 'Category 1.1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', 'ParentCategory' => array('id' => 4, 'parent_id' => 3, 'name' => 'Category 1.1.2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', 'ParentCategory' => array('id' => 3, 'parent_id' => 2, 'name' => 'Category 1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', 'ParentCategory' => array('id' => 2, 'parent_id' => 1, 'name' => 'Category 1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', - 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31')))))), + 'ParentCategory' => array('id' => 1, 'parent_id' => 0, 'name' => 'Category 1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', + 'ParentCategory' => array())))))), array('CategoryThread' => array('id' => 7, 'parent_id' => 6, 'name' => 'Category 2.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31'), 'ParentCategory' => array('id' => 6, 'parent_id' => 5, 'name' => 'Category 2', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', 'ParentCategory' => array('id' => 5, 'parent_id' => 4, 'name' => 'Category 1.1.1.1', 'created' => '2007-03-18 15:30:23', 'updated' => '2007-03-18 15:32:31', @@ -812,7 +852,7 @@ class ModelTest extends CakeTestCase { function testFindUnique() { $this->loadFixtures('User'); $this->model =& new User(); - + $this->assertFalse($this->model->isUnique(array('user' => 'nate'))); $this->model->id = 2; $this->assertTrue($this->model->isUnique(array('user' => 'nate'))); @@ -3045,7 +3085,7 @@ class ModelTest extends CakeTestCase { } function testAfterFindAssociation() { - + } function testDeconstructFields() { diff --git a/cake/tests/cases/libs/model/models.php b/cake/tests/cases/libs/model/models.php index a497f4f87..12453606b 100644 --- a/cake/tests/cases/libs/model/models.php +++ b/cake/tests/cases/libs/model/models.php @@ -497,7 +497,7 @@ class AssociationTest2 extends CakeTestModel { * @subpackage cake.tests.cases.libs.model */ class Callback extends CakeTestModel { - + } /** * Short description for class. @@ -581,5 +581,20 @@ class ValidationTest2 extends CakeTestModel { return array(); } } - +/** + * Short description for class. + * + * @package cake.tests + * @subpackage cake.tests.cases.libs.model + */ +class Person extends AppModel { + var $name = 'Person'; + var $belongsTo = array( + 'Mother' => array( + 'className' => 'Person', + 'foreignKey' => 'mother_id'), + 'Father' => array( + 'className' => 'Person', + 'foreignKey' => 'father_id')); +} ?> \ No newline at end of file diff --git a/cake/tests/fixtures/people_fixture.php b/cake/tests/fixtures/people_fixture.php new file mode 100644 index 000000000..81a1828c8 --- /dev/null +++ b/cake/tests/fixtures/people_fixture.php @@ -0,0 +1,53 @@ + + * Copyright 2005-2008, Cake Software Foundation, Inc. + * 1785 E. Sahara Avenue, Suite 490-204 + * Las Vegas, Nevada 89104 + * + * Licensed under The Open Group Test Suite License + * Redistributions of files must retain the above copyright notice. + * + * @filesource + * @copyright Copyright 2005-2008, Cake Software Foundation, Inc. + * @link https://trac.cakephp.org/wiki/Developement/TestSuite CakePHP(tm) Tests + * @package cake.tests + * @subpackage cake.tests.fixtures + * @since CakePHP(tm) v 1.2.0.6700 + * @version $Revision$ + * @modifiedby $LastChangedBy$ + * @lastmodified $Date$ + * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License + */ +/** + * Short description for class. + * + * @package cake.tests + * @subpackage cake.tests.fixtures + */ +class PeopleFixture extends CakeTestFixture { + var $name = 'People'; + var $fields = array( + 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), + 'name' => array('type'=>'string', 'null' => false, 'length' => 32), + 'mother_id' => array('type'=>'integer', 'null' => false, 'key' => 'index'), + 'father_id' => array('type'=>'integer', 'null' => false), + 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'mother_id' => array('column' => array('mother_id', 'father_id'), 'unique' => 0))); + + var $records = array( + array('name' => 'person', 'mother_id' => 2, 'father_id' => 3), + array('name' => 'mother', 'mother_id' => 4, 'father_id' => 5), + array('name' => 'father', 'mother_id' => 6, 'father_id' => 7), + array('name' => 'mother - grand mother', 'mother_id' => 0, 'father_id' => 0), + array('name' => 'mother - grand father', 'mother_id' => 0, 'father_id' => 0), + array('name' => 'father - grand mother', 'mother_id' => 0, 'father_id' => 0), + array('name' => 'father - grand father', 'mother_id' => 0, 'father_id' => 0)); +} +?> \ No newline at end of file