BUG Ensure changes in class write to an instance of the new class, not the old one

Fixes #1210
Requires https://github.com/silverstripe/silverstripe-framework/pull/5950
This commit is contained in:
Damian Mooyman 2016-09-05 18:46:00 +12:00
parent 10759a5509
commit 9c48b93983
2 changed files with 47 additions and 6 deletions

View File

@ -1006,12 +1006,8 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
// Update the class instance if necessary // Update the class instance if necessary
if(isset($data['ClassName']) && $data['ClassName'] != $record->ClassName) { if(isset($data['ClassName']) && $data['ClassName'] != $record->ClassName) {
$newClassName = $record->ClassName; // Replace $record with a new instance of the new class
// The records originally saved attribute was overwritten by $form->saveInto($record) before. $newClassName = $data['ClassName'];
// This is necessary for newClassInstance() to work as expected, and trigger change detection
// on the ClassName attribute
$record->setClassName($data['ClassName']);
// Replace $record with a new instance
$record = $record->newClassInstance($newClassName); $record = $record->newClassInstance($newClassName);
} }

View File

@ -2,6 +2,7 @@
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\ValidationException;
use SilverStripe\ORM\Versioning\Versioned; use SilverStripe\ORM\Versioning\Versioned;
use SilverStripe\ORM\HiddenClass; use SilverStripe\ORM\HiddenClass;
use SilverStripe\CMS\Controllers\CMSMain; use SilverStripe\CMS\Controllers\CMSMain;
@ -540,14 +541,58 @@ class CMSMainTest extends FunctionalTest {
$this->assertContains("delete", $exemptActions); $this->assertContains("delete", $exemptActions);
$this->assertContains("unpublish", $exemptActions); $this->assertContains("unpublish", $exemptActions);
} }
/**
* Test that changed classes save with the correct class name
*/
public function testChangeClass() {
$this->logInWithPermission('ADMIN');
$cms = new CMSMain();
$page = new CMSMainTest_ClassA();
$page->Title = 'Class A';
$page->write();
$form = $cms->getEditForm($page->ID);
$form->loadDataFrom(['ClassName' => 'CMSMainTest_ClassB']);
$result = $cms->save([
'ID' => $page->ID,
'ClassName' => 'CMSMainTest_ClassB'
], $form);
$this->assertEquals(200, $result->getStatusCode());
$newPage = SiteTree::get()->byID($page->ID);
$this->assertInstanceOf('CMSMainTest_ClassB', $newPage);
$this->assertEquals('CMSMainTest_ClassB', $newPage->ClassName);
$this->assertEquals('Class A', $newPage->Title);
}
} }
class CMSMainTest_ClassA extends Page implements TestOnly { class CMSMainTest_ClassA extends Page implements TestOnly {
private static $allowed_children = array('CMSMainTest_ClassB'); private static $allowed_children = array('CMSMainTest_ClassB');
protected function onBeforeWrite()
{
parent::onBeforeWrite();
if ($this->ClassName !== __CLASS__) {
throw new ValidationException("Class saved with incorrect ClassName");
}
}
} }
class CMSMainTest_ClassB extends Page implements TestOnly { class CMSMainTest_ClassB extends Page implements TestOnly {
protected function onBeforeWrite()
{
parent::onBeforeWrite();
if ($this->ClassName !== __CLASS__) {
throw new ValidationException("Class saved with incorrect ClassName");
}
}
} }
class CMSMainTest_NotRoot extends Page implements TestOnly { class CMSMainTest_NotRoot extends Page implements TestOnly {