Fix orphaned records when running update

When DataObject::update() is run with relation fields and the relationship
is new the relationship ID was not set on the DataObject. This patch fixes
this. Fixes issue 6195 in open.silverstripe.org.
This commit is contained in:
Marcus Dalgren 2013-05-09 01:45:25 +02:00
parent c1d25d17ce
commit 7f871fa18b
2 changed files with 34 additions and 4 deletions

View File

@ -772,10 +772,15 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
// no support for has_many or many_many relationships,
// as the updater wouldn't know which object to write to (or create)
if($relObj->$relation() instanceof DataObject) {
$parentObj = $relObj;
$relObj = $relObj->$relation();
// If the intermediate relationship objects have been created, then write them
if($i<sizeof($relation)-1 && !$relObj->ID) $relObj->write();
if($i<sizeof($relation)-1 && !$relObj->ID || (!$relObj->ID && $parentObj != $this)) {
$relObj->write();
$relatedFieldName = $relation."ID";
$parentObj->$relatedFieldName = $relObj->ID;
$parentObj->write();
}
} else {
user_error(
"DataObject::update(): Can't traverse relationship '$relation'," .
@ -791,6 +796,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
if($relObj) {
$relObj->$fieldName = $v;
$relObj->write();
$relatedFieldName = $relation."ID";
$this->$relatedFieldName = $relObj->ID;
$relObj->flushCache();
} else {
user_error("Couldn't follow dot syntax '$k' on '$this->class' object", E_USER_WARNING);

View File

@ -619,14 +619,14 @@ class DataObjectTest extends SapphireTest {
* objects */
$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
$team1->CaptainID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
$team1->update(array(
'DatabaseField' => 'Something',
'Captain.FirstName' => 'Jim',
'Captain.Email' => 'jim@example.com',
'Captain.FavouriteTeam.Title' => 'New and improved team 1',
));
/* Test the simple case of updating fields on the object itself */
$this->assertEquals('Something', $team1->DatabaseField);
@ -642,6 +642,29 @@ class DataObjectTest extends SapphireTest {
$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
}
public function testDataObjectUpdateNew() {
/* update() calls can use the dot syntax to reference has_one relations and other methods that return
* objects */
$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
$team1->CaptainID = 0;
$team1->update(array(
'Captain.FirstName' => 'Jim',
'Captain.FavouriteTeam.Title' => 'New and improved team 1',
));
/* Test that the captain ID has been updated */
$this->assertGreaterThan(0, $team1->CaptainID);
/* Fetch the newly created captain */
$captain1 = DataObjectTest_Player::get()->byID($team1->CaptainID);
$this->assertEquals('Jim', $captain1->FirstName);
/* Grab the favourite team and make sure it has the correct values */
$reloadedTeam1 = $captain1->FavouriteTeam();
$this->assertEquals($reloadedTeam1->ID, $captain1->FavouriteTeamID);
$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
}
public function testWritingInvalidDataObjectThrowsException() {
$validatedObject = new DataObjectTest_ValidatedObject();