From 6624d41ecdc89df0f0a543b21c522ac89ff0d708 Mon Sep 17 00:00:00 2001 From: gwoo Date: Wed, 29 Oct 2008 07:19:26 +0000 Subject: [PATCH] updating habtm save handling, fixes #5579 git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@7795 3807eeeb-6ff5-0310-8944-8be069107fe0 --- cake/libs/model/model.php | 75 ++++++++++++---------- cake/tests/cases/libs/model/model.test.php | 48 +++++++++++--- 2 files changed, 79 insertions(+), 44 deletions(-) diff --git a/cake/libs/model/model.php b/cake/libs/model/model.php index c7e24b0be..d59684be4 100644 --- a/cake/libs/model/model.php +++ b/cake/libs/model/model.php @@ -1216,47 +1216,55 @@ class Model extends Overloadable { function __saveMulti($joined, $id) { $db =& ConnectionManager::getDataSource($this->useDbConfig); - foreach ($joined as $assoc => $value) { - $newValues = array(); - if (empty($value)) { - $value = array(); - } + foreach ($joined as $assoc => $data) { + if (isset($this->hasAndBelongsToMany[$assoc])) { list($join) = $this->joinModel($this->hasAndBelongsToMany[$assoc]['with']); - $conditions = array($join . '.' . $this->hasAndBelongsToMany[$assoc]['foreignKey'] => $id); - $links = array(); - if ($this->hasAndBelongsToMany[$assoc]['unique']) { - $this->{$join}->deleteAll($conditions); - } else { - list($recursive, $fields) = array(-1, $this->hasAndBelongsToMany[$assoc]['associationForeignKey']); - $links = Set::extract( - $this->{$join}->find('all', compact('conditions', 'recursive', 'fields')), - "{n}.{$join}." . $this->hasAndBelongsToMany[$assoc]['associationForeignKey'] - ); - } + $conditions = array($join . '.' . $this->hasAndBelongsToMany[$assoc]['foreignKey'] => $id); + + $links = $this->{$join}->find('all', array( + 'conditions' => $conditions, + 'recursive' => -1, + 'fields' => $this->hasAndBelongsToMany[$assoc]['associationForeignKey'] + )); $isUUID = !empty($this->{$join}->primaryKey) && (($this->{$join}->_schema[$this->{$join}->primaryKey]['type'] === 'string' && $this->{$join}->_schema[$this->{$join}->primaryKey]['length'] === 36) || ($this->{$join}->_schema[$this->{$join}->primaryKey]['type'] === 'binary' && $this->{$join}->_schema[$this->{$join}->primaryKey]['length'] === 16)); - foreach ($value as $update) { - if (!empty($update)) { - if (is_array($update)) { - $update[$this->hasAndBelongsToMany[$assoc]['foreignKey']] = $id; - $this->{$join}->create($update); - $this->{$join}->save(); - } elseif (!in_array($update, $links)) { - $values = array( - $db->value($id, $this->getColumnType($this->primaryKey)), - $db->value($update) - ); - if ($isUUID) { - $values[] = $db->value(String::uuid()); - } - $values = join(',', $values); - $newValues[] = "({$values})"; - unset($values); + $newData = $newValues = array(); + + foreach ($data as $row) { + if (($isUUID && (strlen($row) == 36 || strlen($row) == 16)) || is_numeric($row)) { + $values = array( + $db->value($id, $this->getColumnType($this->primaryKey)), + $db->value($row) + ); + if ($isUUID) { + $values[] = $db->value(String::uuid()); } + $values = join(',', $values); + $newValues[] = "({$values})"; + unset($values); + } else if (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) { + $newData[] = $row; + } + } + + if (!empty($newData)) { + foreach ($newData as $data) { + $data[$this->hasAndBelongsToMany[$assoc]['foreignKey']] = $id; + $this->{$join}->create($data); + $this->{$join}->save(); + } + } + + if (empty($newData) && $this->hasAndBelongsToMany[$assoc]['unique']) { + $associationForeignKey = "{$join}." . $this->hasAndBelongsToMany[$assoc]['associationForeignKey']; + $oldLinks = Set::extract($links, "{n}.{$associationForeignKey}"); + if (!empty($oldLinks)) { + $conditions[$associationForeignKey] = $oldLinks; + $db->delete($this->{$join}, $conditions); } } @@ -1265,7 +1273,6 @@ class Model extends Overloadable { $db->name($this->hasAndBelongsToMany[$assoc]['foreignKey']), $db->name($this->hasAndBelongsToMany[$assoc]['associationForeignKey']) ); - if ($isUUID) { $fields[] = $db->name($this->{$join}->primaryKey); } diff --git a/cake/tests/cases/libs/model/model.test.php b/cake/tests/cases/libs/model/model.test.php index 89229efca..3c53b73fa 100644 --- a/cake/tests/cases/libs/model/model.test.php +++ b/cake/tests/cases/libs/model/model.test.php @@ -2882,9 +2882,38 @@ class ModelTest extends CakeTestCase { function testHabtmSaveKeyResolution() { $this->loadFixtures('Apple', 'Device', 'ThePaperMonkies'); $ThePaper =& new ThePaper(); - $ThePaper->id = 1; + $ThePaper->id = 1; $ThePaper->save(array('Monkey' => array(2, 3))); + + $result = $ThePaper->findById(1); + $expected = array( + array('id' => '2', 'device_type_id' => '1', 'name' => 'Device 2', 'typ' => '1'), + array('id' => '3', 'device_type_id' => '1', 'name' => 'Device 3', 'typ' => '2') + ); + $this->assertEqual($result['Monkey'], $expected); + + $ThePaper->id = 2; + $ThePaper->save(array('Monkey' => array(1, 2, 3))); + + $result = $ThePaper->findById(2); + $expected = array( + array('id' => '1', 'device_type_id' => '1', 'name' => 'Device 1', 'typ' => '1'), + array('id' => '2', 'device_type_id' => '1', 'name' => 'Device 2', 'typ' => '1'), + array('id' => '3', 'device_type_id' => '1', 'name' => 'Device 3', 'typ' => '2'), + ); + $this->assertEqual($result['Monkey'], $expected); + + $ThePaper->id = 2; + $ThePaper->save(array('Monkey' => array(1, 3))); + + $result = $ThePaper->findById(2); + $expected = array( + array('id' => '3', 'device_type_id' => '1', 'name' => 'Device 3', 'typ' => '2'), + array('id' => '1', 'device_type_id' => '1', 'name' => 'Device 1', 'typ' => '1'), + ); + $this->assertEqual($result['Monkey'], $expected); + $result = $ThePaper->findById(1); $expected = array( array('id' => '2', 'device_type_id' => '1', 'name' => 'Device 2', 'typ' => '1'), @@ -2892,7 +2921,6 @@ class ModelTest extends CakeTestCase { ); $this->assertEqual($result['Monkey'], $expected); } - /** * test that Caches are getting cleared on save(). * ensure that both inflections of controller names are getting cleared @@ -2907,26 +2935,26 @@ class ModelTest extends CakeTestCase { ); Configure::write('Cache.check', true); Configure::write('Cache.disable', false); - + $this->loadFixtures('OverallFavorite'); $OverallFavorite =& new OverallFavorite(); - + touch(CACHE . 'views' . DS . 'some_dir_overallfavorites_index.php'); touch(CACHE . 'views' . DS . 'some_dir_overall_favorites_index.php'); - + $data = array( 'OverallFavorite' => array( - 'model_type' => '8-track', + 'model_type' => '8-track', 'model_id' => '3', 'priority' => '1' ) ); $OverallFavorite->create($data); $OverallFavorite->save(); - + $this->assertFalse(file_exists(CACHE . 'views' . DS . 'some_dir_overallfavorites_index.php')); $this->assertFalse(file_exists(CACHE . 'views' . DS . 'some_dir_overall_favorites_index.php')); - + Configure::write('Cache.check', $_back['check']); Configure::write('Cache.disable', $_back['disable']); } @@ -2996,7 +3024,7 @@ class ModelTest extends CakeTestCase { $expected = array('id' => '2', 'comment_id' => '7', 'attachment' => 'some_file.tgz', 'created' => $ts, 'updated' => $ts); $this->assertEqual($result[6]['Attachment'], $expected); } - + /** * Test SaveAll with Habtm relations * @@ -3020,7 +3048,7 @@ class ModelTest extends CakeTestCase { $Article =& new Article(); $result = $Article->saveAll($data); $this->assertTrue($result); - + $result = $Article->read(); $this->assertEqual(count($result['Tag']), 2); $this->assertEqual($result['Tag'][0]['tag'], 'tag1');