mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
ENHANCEMENT: DataObject and SiteTree duplicate now duplicate relations (except for has_many relations, as the object at the other end of such a relation has an existing relation to the original object and that should not be modified by the duplication)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@110845 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
94c93e64e7
commit
ed666b71b7
@ -379,7 +379,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a duplicate of this node.
|
* Create a duplicate of this node.
|
||||||
* Caution: Doesn't duplicate relations.
|
* Note: now also duplicates relations.
|
||||||
*
|
*
|
||||||
* @param $doWrite Perform a write() operation before returning the object. If this is true, it will create the duplicate in the database.
|
* @param $doWrite Perform a write() operation before returning the object. If this is true, it will create the duplicate in the database.
|
||||||
* @return DataObject A duplicate of this node. The exact type will be the type of this node.
|
* @return DataObject A duplicate of this node. The exact type will be the type of this node.
|
||||||
@ -388,10 +388,55 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
$className = $this->class;
|
$className = $this->class;
|
||||||
$clone = new $className( $this->record );
|
$clone = new $className( $this->record );
|
||||||
$clone->ID = 0;
|
$clone->ID = 0;
|
||||||
if($doWrite) $clone->write();
|
|
||||||
|
if($doWrite) {
|
||||||
|
$clone->write();
|
||||||
|
|
||||||
|
$this->duplicateManyManyRelations($this, $clone);
|
||||||
|
}
|
||||||
return $clone;
|
return $clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the many_many and belongs_many_many relations from one object to another instance of the name of object
|
||||||
|
* The destinationObject must be written to the database already and have an ID. Writing is performed automatically when adding the new relations.
|
||||||
|
* @return DataObject with the new many_many relations copied in */
|
||||||
|
protected function duplicateManyManyRelations($sourceObject, $destinationObject) {
|
||||||
|
if (!$destinationObject || $destinationObject->ID < 1) user_error("Can't duplicate relations for an object that has not been written to the database", E_USER_ERROR);
|
||||||
|
|
||||||
|
//duplicate complex relations
|
||||||
|
// DO NOT copy has_many relations, because copying the relation would result in us changing the has_one relation
|
||||||
|
// on the other side of this relation to point at the copy and no longer the original (being a has_one, it can
|
||||||
|
// only point at one thing at a time). So, all relations except has_many can and are copied
|
||||||
|
if ($sourceObject::$has_one) foreach($sourceObject::$has_one as $name => $type) {
|
||||||
|
$this->duplicateRelations($sourceObject, $destinationObject, $name);
|
||||||
|
}
|
||||||
|
if ($sourceObject::$many_many) foreach($sourceObject::$many_many as $name => $type) {
|
||||||
|
$this->duplicateRelations($sourceObject, $destinationObject, $name);
|
||||||
|
}
|
||||||
|
if ($sourceObject::$belongs_many_many) foreach($sourceObject::$belongs_many_many as $name => $type) {
|
||||||
|
$this->duplicateRelations($sourceObject, $destinationObject, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $destinationObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper function to duplicate relations from one object to another */
|
||||||
|
private function duplicateRelations($sourceObject, $destinationObject, $name) {
|
||||||
|
$relations = $sourceObject->$name();
|
||||||
|
if ($relations) {
|
||||||
|
if ($relations instanceOf ComponentSet) { //many-to-something relation
|
||||||
|
if ($relations->Count() > 0) { //with more than one thing it is related to
|
||||||
|
foreach($relations as $relation) {
|
||||||
|
$destinationObject->$name()->add($relation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { //one-to-one relation
|
||||||
|
$destinationObject->$name = $relations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the ClassName attribute. {@link $class} is also updated.
|
* Set the ClassName attribute. {@link $class} is also updated.
|
||||||
* Warning: This will produce an inconsistent record, as the object
|
* Warning: This will produce an inconsistent record, as the object
|
||||||
|
@ -538,6 +538,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
|
|||||||
|
|
||||||
if($doWrite) {
|
if($doWrite) {
|
||||||
$page->write();
|
$page->write();
|
||||||
|
|
||||||
|
$page = $this->duplicateManyManyRelations($this, $page);
|
||||||
}
|
}
|
||||||
$this->extend('onAfterDuplicate', $page);
|
$this->extend('onAfterDuplicate', $page);
|
||||||
|
|
||||||
|
101
tests/model/DataObjectDuplicationTest.php
Normal file
101
tests/model/DataObjectDuplicationTest.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class DataObjectDuplicationTest extends SapphireTest {
|
||||||
|
|
||||||
|
function testDuplicateManyManyClasses() {
|
||||||
|
//create new test classes below
|
||||||
|
$one = new DataObjectDuplicateTestClass1();
|
||||||
|
$two = new DataObjectDuplicateTestClass2();
|
||||||
|
$three = new DataObjectDuplicateTestClass3();
|
||||||
|
|
||||||
|
//set some simple fields
|
||||||
|
$text1 = "Test Text 1";
|
||||||
|
$text2 = "Test Text 2";
|
||||||
|
$text3 = "Test Text 3";
|
||||||
|
$one->text = $text1;
|
||||||
|
$two->text = $text2;
|
||||||
|
$three->text = $text3;
|
||||||
|
|
||||||
|
//write the to DB
|
||||||
|
$one->write();
|
||||||
|
$two->write();
|
||||||
|
$three->write();
|
||||||
|
|
||||||
|
//create relations
|
||||||
|
$one->twos()->add($two);
|
||||||
|
$one->threes()->add($three);
|
||||||
|
|
||||||
|
$one = DataObject::get_by_id("DataObjectDuplicateTestClass1", $one->ID);
|
||||||
|
$two = DataObject::get_by_id("DataObjectDuplicateTestClass2", $two->ID);
|
||||||
|
$three = DataObject::get_by_id("DataObjectDuplicateTestClass3", $three->ID);
|
||||||
|
|
||||||
|
//test duplication
|
||||||
|
$oneCopy = $one->duplicate();
|
||||||
|
$twoCopy = $two->duplicate();
|
||||||
|
$threeCopy = $three->duplicate();
|
||||||
|
|
||||||
|
$oneCopy = DataObject::get_by_id("DataObjectDuplicateTestClass1", $oneCopy->ID);
|
||||||
|
$twoCopy = DataObject::get_by_id("DataObjectDuplicateTestClass2", $twoCopy->ID);
|
||||||
|
$threeCopy = DataObject::get_by_id("DataObjectDuplicateTestClass3", $threeCopy->ID);
|
||||||
|
|
||||||
|
$this->assertNotNull($oneCopy, "Copy of 1 exists");
|
||||||
|
$this->assertNotNull($twoCopy, "Copy of 2 exists");
|
||||||
|
$this->assertNotNull($threeCopy, "Copy of 3 exists");
|
||||||
|
|
||||||
|
$this->assertEquals($text1, $oneCopy->text);
|
||||||
|
$this->assertEquals($text2, $twoCopy->text);
|
||||||
|
$this->assertEquals($text3, $threeCopy->text);
|
||||||
|
|
||||||
|
$this->assertNotEquals($one->twos()->Count(), $oneCopy->twos()->Count(), "Many-to-one relation not copied (has_many)");
|
||||||
|
$this->assertEquals($one->threes()->Count(), $oneCopy->threes()->Count(), "Object has the correct number of relations");
|
||||||
|
$this->assertEquals($three->ones()->Count(), $threeCopy->ones()->Count(), "Object has the correct number of relations");
|
||||||
|
|
||||||
|
$this->assertEquals($one->ID, $twoCopy->one()->ID, "Match between relation of copy and the original");
|
||||||
|
$this->assertEquals(0, $oneCopy->twos()->Count(), "Many-to-one relation not copied (has_many)");
|
||||||
|
$this->assertEquals($three->ID, $oneCopy->threes()->First()->ID, "Match between relation of copy and the original");
|
||||||
|
$this->assertEquals($one->ID, $threeCopy->ones()->First()->ID, "Match between relation of copy and the original");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DataObjectDuplicateTestClass1 extends SiteTree {
|
||||||
|
|
||||||
|
static $db = array(
|
||||||
|
'text' => 'Varchar'
|
||||||
|
);
|
||||||
|
|
||||||
|
static $has_many = array(
|
||||||
|
'twos' => 'DataObjectDuplicateTestClass2'
|
||||||
|
);
|
||||||
|
|
||||||
|
static $many_many = array(
|
||||||
|
'threes' => 'DataObjectDuplicateTestClass3'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataObjectDuplicateTestClass2 extends SiteTree {
|
||||||
|
|
||||||
|
static $db = array(
|
||||||
|
'text' => 'Varchar'
|
||||||
|
);
|
||||||
|
|
||||||
|
static $has_one = array(
|
||||||
|
'one' => 'DataObjectDuplicateTestClass1'
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataObjectDuplicateTestClass3 extends SiteTree {
|
||||||
|
|
||||||
|
static $db = array(
|
||||||
|
'text' => 'Varchar'
|
||||||
|
);
|
||||||
|
|
||||||
|
static $belongs_many_many = array(
|
||||||
|
'ones' => 'DataObjectDuplicateTestClass1'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
Loading…
x
Reference in New Issue
Block a user