From 78195944bee7bd130944b862c5654afa36a5c1f3 Mon Sep 17 00:00:00 2001 From: jackbravo Date: Sun, 9 Dec 2007 01:56:53 +0000 Subject: [PATCH] Added synchronizeWithArray method and unset functionality for relations The unset functionality is not working for foreignKey relations --- lib/Doctrine/Collection.php | 27 ++++++ lib/Doctrine/Record.php | 37 +++++++- tests/Record/SynchronizeTestCase.php | 121 +++++++++++++++++++++++++++ tests/run.php | 1 + 4 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 tests/Record/SynchronizeTestCase.php diff --git a/lib/Doctrine/Collection.php b/lib/Doctrine/Collection.php index c32a6fb60..2a35af632 100644 --- a/lib/Doctrine/Collection.php +++ b/lib/Doctrine/Collection.php @@ -678,6 +678,33 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator } } + /** + * synchronizeWithArray + * synchronizes a Doctrine_Collection with data from an array + * + * it expects an array representation of a Doctrine_Collection similar to the return + * value of the toArray() method. It will create Dectrine_Records that don't exist + * on the collection, update the ones that do and remove the ones missing in the $array + * + * @param array $array representation of a Doctrine_Collection + */ + public function synchronizeWithArray(array $array) + { + foreach ($this as $key => $record) { + if (isset($array[$key])) { + $record->synchronizeWithArray($array[$key]); + unset($array[$key]); + } else { + // remove records that don't exist in the array + $this->remove($key); + } + } + // create new records for each new row in the array + foreach ($array as $rowKey => $row) { + $this[$rowKey]->fromArray($row); + } + } + /** * exportTo * diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index 80fa567b1..c78cdb463 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -1000,7 +1000,14 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count if (isset($this->_data[$fieldName])) { $this->_data[$fieldName] = array(); } - // todo: what to do with references ? + if (isset($this->_references[$fieldName])) { + if ($this->_references[$fieldName] instanceof Doctrine_Record) { + // todo: delete related record when saving $this + $this->_references[$fieldName] = self::$_null; + } elseif ($this->_references[$fieldName] instanceof Doctrine_Collection) { + $this->_references[$fieldName]->setData(array()); + } + } } /** @@ -1256,6 +1263,34 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count } } + /** + * synchronizeWithArray + * synchronizes a Doctrine_Record and its relations with data from an array + * + * it expects an array representation of a Doctrine_Record similar to the return + * value of the toArray() method. If the array contains relations it will create + * those that don't exist, update the ones that do, and delete the ones missing + * on the array but available on the Doctrine_Record + * + * @param array $array representation of a Doctrine_Record + */ + public function synchronizeWithArray(array $array) + { + foreach ($array as $key => $value) { + if ($this->getTable()->hasRelation($key)) { + $this->get($key)->synchronizeWithArray($value); + } else if ($this->getTable()->hasColumn($key)) { + $this->set($key, $value); + } + } + // eliminate relationships missing in the $array + foreach ($this->_references as $name => $obj) { + if (!isset($array[$name])) { + unset($this->$name); + } + } + } + /** * exportTo * diff --git a/tests/Record/SynchronizeTestCase.php b/tests/Record/SynchronizeTestCase.php new file mode 100644 index 000000000..189909ace --- /dev/null +++ b/tests/Record/SynchronizeTestCase.php @@ -0,0 +1,121 @@ +. + */ + +/** + * Doctrine_Record_State_TestCase + * + * @package Doctrine + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + */ +class Doctrine_Record_Synchronize_TestCase extends Doctrine_UnitTestCase +{ + public function prepareTables() + { + parent::prepareTables(); + } + + public function prepareData() + { + $user = new User(); + $user->name = 'John'; + $user->Email->address = 'john@mail.com'; + $user->Phonenumber[0]->phonenumber = '555 123'; + $user->Phonenumber[1]->phonenumber = '555 448'; + $user->save(); + } + + public function testSynchronizeRecord() + { + $user = Doctrine_Query::create()->from('User u, u.Email, u.Phonenumber')->fetchOne(); + $userArray = $user->toArray(true); + $this->assertEqual($user->Phonenumber->count(), 2); + $this->assertEqual($user->Phonenumber[0]->phonenumber, '555 123'); + + // modify a Phonenumber + $userArray['Phonenumber'][0]['phonenumber'] = '555 321'; + + // delete a Phonenumber + array_pop($userArray['Phonenumber']); + + $user->synchronizeWithArray($userArray); + $this->assertEqual($user->Phonenumber->count(), 1); + $this->assertEqual($user->Phonenumber[0]->phonenumber, '555 321'); + + // change Email + $userArray['Email']['address'] = 'johndow@mail.com'; + $user->synchronizeWithArray($userArray); + $this->assertEqual($user->Email->address, 'johndow@mail.com'); + + $user->save(); + } + + public function testSynchronizeAfterSaveRecord() + { + $user = Doctrine_Query::create()->from('User u, u.Email, u.Phonenumber')->fetchOne(); + $this->assertEqual($user->Phonenumber->count(), 1); + $this->assertEqual($user->Phonenumber[0]->phonenumber, '555 321'); + $this->assertEqual($user->Email->address, 'johndow@mail.com'); + } + + public function testSynchronizeAddRecord() + { + $user = Doctrine_Query::create()->from('User u, u.Email, u.Phonenumber')->fetchOne(); + $userArray = $user->toArray(true); + $userArray['Phonenumber'][] = array('phonenumber' => '333 238'); + + $user->synchronizeWithArray($userArray); + $this->assertEqual($user->Phonenumber->count(), 2); + $this->assertEqual($user->Phonenumber[1]->phonenumber, '333 238'); + $user->save(); + } + + public function testSynchronizeAfterAddRecord() + { + $user = Doctrine_Query::create()->from('User u, u.Email, u.Phonenumber')->fetchOne(); + $this->assertEqual($user->Phonenumber->count(), 2); + $this->assertEqual($user->Phonenumber[1]->phonenumber, '333 238'); + } + + public function testSynchronizeRemoveRecord() + { + $user = Doctrine_Query::create()->from('User u, u.Email, u.Phonenumber')->fetchOne(); + $userArray = $user->toArray(true); + unset($userArray['Phonenumber']); + unset($userArray['Email']); + + $user->synchronizeWithArray($userArray); + $this->assertEqual($user->Phonenumber->count(), 0); + $this->assertTrue(!isset($user->Email)); + $user->save(); + } + + public function testSynchronizeAfterRemoveRecord() + { + $user = Doctrine_Query::create()->from('User u, u.Email, u.Phonenumber')->fetchOne(); + $this->assertEqual($user->Phonenumber->count(), 0); + $this->assertTrue(!isset($user->Email)); + } +} diff --git a/tests/run.php b/tests/run.php index 5bebfec4f..ca07f3f7a 100644 --- a/tests/run.php +++ b/tests/run.php @@ -218,6 +218,7 @@ $record->addTestCase(new Doctrine_Record_Lock_TestCase()); $record->addTestCase(new Doctrine_Record_ZeroValues_TestCase()); //$record->addTestCase(new Doctrine_Record_SaveBlankRecord_TestCase()); $record->addTestCase(new Doctrine_Record_Inheritance_TestCase()); +$record->addTestCase(new Doctrine_Record_Synchronize_TestCase()); $test->addTestCase($record); $test->addTestCase(new Doctrine_CustomPrimaryKey_TestCase());