mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
ENHANCEMENT: Added support for dot syntax to DataObject::update()
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@63493 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
c5ed0c3c2e
commit
cba8e71170
@ -392,17 +392,40 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass a number of field changes in a map.
|
||||
* Doesn't write to the database. To write the data,
|
||||
* use the write() method.
|
||||
* Update a number of fields on this object, given a map of the desired changes.
|
||||
*
|
||||
* The field names can be simple names, or you can use a dot syntax to access relations.
|
||||
* For example, array("Author.FirstName" => "Jim") will set $this->Author()->FirstName to "Jim".
|
||||
*
|
||||
* update() doesn't write the main object, but if you use the dot syntax, it will write()
|
||||
* the related objects that it alters.
|
||||
*
|
||||
* @param array $data A map of field name to data values to update.
|
||||
*/
|
||||
public function update($data) {
|
||||
foreach($data as $k => $v) {
|
||||
// Implement dot syntax for updates
|
||||
if(strpos($k,'.') !== false) {
|
||||
$relations = explode('.', $k);
|
||||
$fieldName = array_pop($relations);
|
||||
$relObj = $this;
|
||||
foreach($relations as $i=>$relation) {
|
||||
$relObj = $relObj->$relation();
|
||||
// If the intermediate relationship objects have been created, then write them
|
||||
if($i<sizeof($relation)-1 && !$relObj->ID) $relObj->write();
|
||||
}
|
||||
if($relObj) {
|
||||
$relObj->$fieldName = $v;
|
||||
$relObj->write();
|
||||
$relObj->flushCache();
|
||||
} else {
|
||||
user_error("Couldn't follow dot syntax '$k' on '$this->class' object", E_USER_WARNING);
|
||||
}
|
||||
} else {
|
||||
$this->$k = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass changes as a map, and try to
|
||||
@ -1644,7 +1667,6 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
if(!isset($this->record[$fieldName]) || $this->record[$fieldName] !== $val) {
|
||||
// TODO Add check for php-level defaults which are not set in the db
|
||||
// TODO Add check for hidden input-fields (readonly) which are not set in the db
|
||||
|
||||
if(
|
||||
// Main non type-based check
|
||||
(isset($this->record[$fieldName]) && $this->record[$fieldName] != $val)
|
||||
|
@ -289,6 +289,17 @@ class DataObjectTest extends SapphireTest {
|
||||
$this->assertEquals(0, DB::query("SELECT CaptainID FROM DataObjectTest_Team WHERE ID = $existingTeam->ID")->value());
|
||||
}
|
||||
|
||||
function testCanAccessHasOneObjectsAsMethods() {
|
||||
/* If you have a has_one relation 'Captain' on $obj, and you set the $obj->CaptainID = (ID), then the object itself should
|
||||
* be accessible as $obj->Captain() */
|
||||
$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
|
||||
$captainID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
|
||||
|
||||
$team->CaptainID = $captainID;
|
||||
$this->assertNotNull($team->Captain());
|
||||
$this->assertEquals($captainID, $team->Captain()->ID);
|
||||
}
|
||||
|
||||
function testFieldNamesThatMatchMethodNamesWork() {
|
||||
/* Check that a field name that corresponds to a method on DataObject will still work */
|
||||
$obj = new DataObjectTest_FunnyFieldNames();
|
||||
@ -428,9 +439,38 @@ class DataObjectTest extends SapphireTest {
|
||||
'databaseFields() on subclass contains only fields defined on instance'
|
||||
);
|
||||
}
|
||||
|
||||
function testDataObjectUpdate() {
|
||||
/* 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 = $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);
|
||||
|
||||
/* Setting Captain.Email and Captain.FirstName will have updated DataObjectTest_Captain.captain1 in the database. Although update()
|
||||
* doesn't usually write, it does write related records automatically. */
|
||||
$captain1 = $this->objFromFixture('DataObjectTest_Player', 'captain1');
|
||||
$this->assertEquals('Jim', $captain1->FirstName);
|
||||
$this->assertEquals('jim@example.com', $captain1->Email);
|
||||
|
||||
/* Jim's favourite team is team 1; we need to reload the object to the the change that setting Captain.FavouriteTeam.Title made */
|
||||
$reloadedTeam1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
|
||||
$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
|
||||
}
|
||||
}
|
||||
|
||||
class DataObjectTest_Player extends Member implements TestOnly {
|
||||
static $has_one = array(
|
||||
'FavouriteTeam' => 'DataObjectTest_Team',
|
||||
);
|
||||
|
||||
static $belongs_many_many = array(
|
||||
'Teams' => 'DataObjectTest_Team'
|
||||
|
@ -42,6 +42,13 @@ DataObjectTest_Team:
|
||||
Title: Team 2
|
||||
|
||||
DataObjectTest_Player:
|
||||
captain1:
|
||||
FirstName: Captain 1
|
||||
FavouriteTeam: =>DataObjectTest_Team.team1
|
||||
Teams: =>DataObjectTest_Team.team1
|
||||
captain2:
|
||||
FirstName: Captain 2
|
||||
Teams: =>DataObjectTest_Team.team2
|
||||
player1:
|
||||
FirstName: Player 1
|
||||
player2:
|
||||
|
Loading…
Reference in New Issue
Block a user