mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #5074 from tractorcow/pulls/3.2/fix-publish-version
BUG Correct behaviour of publish with $createNewVersion = true
This commit is contained in:
commit
caf0ec3c5f
@ -5,6 +5,8 @@
|
|||||||
* allowing you to rollback changes and view history. An example of this is
|
* allowing you to rollback changes and view history. An example of this is
|
||||||
* the pages used in the CMS.
|
* the pages used in the CMS.
|
||||||
*
|
*
|
||||||
|
* @property int $Version
|
||||||
|
*
|
||||||
* @package framework
|
* @package framework
|
||||||
* @subpackage model
|
* @subpackage model
|
||||||
*/
|
*/
|
||||||
@ -487,12 +489,12 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
|
|||||||
|
|
||||||
foreach($versionedTables as $child) {
|
foreach($versionedTables as $child) {
|
||||||
if($table === $child) break; // only need subclasses
|
if($table === $child) break; // only need subclasses
|
||||||
|
|
||||||
// Select all orphaned version records
|
// Select all orphaned version records
|
||||||
$orphanedQuery = SQLSelect::create()
|
$orphanedQuery = SQLSelect::create()
|
||||||
->selectField("\"{$table}_versions\".\"ID\"")
|
->selectField("\"{$table}_versions\".\"ID\"")
|
||||||
->setFrom("\"{$table}_versions\"");
|
->setFrom("\"{$table}_versions\"");
|
||||||
|
|
||||||
// If we have a parent table limit orphaned records
|
// If we have a parent table limit orphaned records
|
||||||
// to only those that exist in this
|
// to only those that exist in this
|
||||||
if(DB::get_schema()->hasTable("{$child}_versions")) {
|
if(DB::get_schema()->hasTable("{$child}_versions")) {
|
||||||
@ -568,7 +570,7 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
|
|||||||
*/
|
*/
|
||||||
protected function augmentWriteVersioned(&$manipulation, $table, $recordID) {
|
protected function augmentWriteVersioned(&$manipulation, $table, $recordID) {
|
||||||
$baseDataClass = ClassInfo::baseDataClass($table);
|
$baseDataClass = ClassInfo::baseDataClass($table);
|
||||||
|
|
||||||
// Set up a new entry in (table)_versions
|
// Set up a new entry in (table)_versions
|
||||||
$newManipulation = array(
|
$newManipulation = array(
|
||||||
"command" => "insert",
|
"command" => "insert",
|
||||||
@ -606,15 +608,17 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
|
|||||||
}
|
}
|
||||||
$nextVersion = $nextVersion ?: 1;
|
$nextVersion = $nextVersion ?: 1;
|
||||||
|
|
||||||
// Add the version number to this data
|
|
||||||
$manipulation[$table]['fields']['Version'] = $nextVersion;
|
|
||||||
$newManipulation['fields']['Version'] = $nextVersion;
|
|
||||||
|
|
||||||
// Write AuthorID for baseclass
|
|
||||||
if($table === $baseDataClass) {
|
if($table === $baseDataClass) {
|
||||||
|
// Write AuthorID for baseclass
|
||||||
$userID = (Member::currentUser()) ? Member::currentUser()->ID : 0;
|
$userID = (Member::currentUser()) ? Member::currentUser()->ID : 0;
|
||||||
$newManipulation['fields']['AuthorID'] = $userID;
|
$newManipulation['fields']['AuthorID'] = $userID;
|
||||||
|
|
||||||
|
// Update main table version if not previously known
|
||||||
|
$manipulation[$table]['fields']['Version'] = $nextVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update _versions table manipulation
|
||||||
|
$newManipulation['fields']['Version'] = $nextVersion;
|
||||||
$manipulation["{$table}_versions"] = $newManipulation;
|
$manipulation["{$table}_versions"] = $newManipulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,6 +645,19 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
|
|||||||
|
|
||||||
|
|
||||||
public function augmentWrite(&$manipulation) {
|
public function augmentWrite(&$manipulation) {
|
||||||
|
// get Version number from base data table on write
|
||||||
|
$version = null;
|
||||||
|
$baseDataClass = ClassInfo::baseDataClass($this->owner->class);
|
||||||
|
if(isset($manipulation[$baseDataClass]['fields'])) {
|
||||||
|
if ($this->migratingVersion) {
|
||||||
|
$manipulation[$baseDataClass]['fields']['Version'] = $this->migratingVersion;
|
||||||
|
}
|
||||||
|
if (isset($manipulation[$baseDataClass]['fields']['Version'])) {
|
||||||
|
$version = $manipulation[$baseDataClass]['fields']['Version'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update all tables
|
||||||
$tables = array_keys($manipulation);
|
$tables = array_keys($manipulation);
|
||||||
foreach($tables as $table) {
|
foreach($tables as $table) {
|
||||||
|
|
||||||
@ -649,20 +666,15 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
|
|||||||
unset($manipulation[$table]);
|
unset($manipulation[$table]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get ID field
|
// Get ID field
|
||||||
$id = $manipulation[$table]['id'] ? $manipulation[$table]['id'] : $manipulation[$table]['fields']['ID'];
|
$id = $manipulation[$table]['id']
|
||||||
|
? $manipulation[$table]['id']
|
||||||
|
: $manipulation[$table]['fields']['ID'];
|
||||||
if(!$id) {
|
if(!$id) {
|
||||||
user_error("Couldn't find ID in " . var_export($manipulation[$table], true), E_USER_ERROR);
|
user_error("Couldn't find ID in " . var_export($manipulation[$table], true), E_USER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->migratingVersion) {
|
|
||||||
$manipulation[$table]['fields']['Version'] = $this->migratingVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
$version = isset($manipulation[$table]['fields']['Version'])
|
|
||||||
? $manipulation[$table]['fields']['Version']
|
|
||||||
: null;
|
|
||||||
if($version < 0 || $this->_nextWriteWithoutVersion) {
|
if($version < 0 || $this->_nextWriteWithoutVersion) {
|
||||||
// Putting a Version of -1 is a signal to leave the version table alone, despite their being no version
|
// Putting a Version of -1 is a signal to leave the version table alone, despite their being no version
|
||||||
unset($manipulation[$table]['fields']['Version']);
|
unset($manipulation[$table]['fields']['Version']);
|
||||||
@ -672,7 +684,7 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
|
|||||||
$this->augmentWriteVersioned($manipulation, $table, $id);
|
$this->augmentWriteVersioned($manipulation, $table, $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For base classes of versioned data objects
|
// Remove "Version" column from subclasses of baseDataClass
|
||||||
if(!$this->hasVersionField($table)) {
|
if(!$this->hasVersionField($table)) {
|
||||||
unset($manipulation[$table]['fields']['Version']);
|
unset($manipulation[$table]['fields']['Version']);
|
||||||
}
|
}
|
||||||
@ -805,56 +817,64 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
|
|||||||
/**
|
/**
|
||||||
* Move a database record from one stage to the other.
|
* Move a database record from one stage to the other.
|
||||||
*
|
*
|
||||||
* @param fromStage Place to copy from. Can be either a stage name or a version number.
|
* @param int|string $fromStage Place to copy from. Can be either a stage name or a version number.
|
||||||
* @param toStage Place to copy to. Must be a stage name.
|
* @param string $toStage Place to copy to. Must be a stage name.
|
||||||
* @param createNewVersion Set this to true to create a new version number. By default, the existing version
|
* @param bool $createNewVersion Set this to true to create a new version number.
|
||||||
* number will be copied over.
|
* By default, the existing version number will be copied over.
|
||||||
*/
|
*/
|
||||||
public function publish($fromStage, $toStage, $createNewVersion = false) {
|
public function publish($fromStage, $toStage, $createNewVersion = false) {
|
||||||
$this->owner->extend('onBeforeVersionedPublish', $fromStage, $toStage, $createNewVersion);
|
$this->owner->extend('onBeforeVersionedPublish', $fromStage, $toStage, $createNewVersion);
|
||||||
|
|
||||||
$baseClass = $this->owner->class;
|
$baseClass = ClassInfo::baseDataClass($this->owner->class);
|
||||||
while( ($p = get_parent_class($baseClass)) != "DataObject") $baseClass = $p;
|
|
||||||
$extTable = $this->extendWithSuffix($baseClass);
|
$extTable = $this->extendWithSuffix($baseClass);
|
||||||
|
|
||||||
|
/** @var Versioned|DataObject $from */
|
||||||
if(is_numeric($fromStage)) {
|
if(is_numeric($fromStage)) {
|
||||||
$from = Versioned::get_version($baseClass, $this->owner->ID, $fromStage);
|
$from = Versioned::get_version($baseClass, $this->owner->ID, $fromStage);
|
||||||
} else {
|
} else {
|
||||||
$this->owner->flushCache();
|
$this->owner->flushCache();
|
||||||
$from = Versioned::get_one_by_stage($baseClass, $fromStage, "\"{$baseClass}\".\"ID\"={$this->owner->ID}");
|
$from = Versioned::get_one_by_stage($baseClass, $fromStage, array(
|
||||||
|
"\"{$baseClass}\".\"ID\" = ?" => $this->owner->ID
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if(!$from) {
|
||||||
|
user_error("Can't find {$this->owner->class}/{$this->owner->ID} in stage {$fromStage}", E_USER_WARNING);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$publisherID = isset(Member::currentUser()->ID) ? Member::currentUser()->ID : 0;
|
// Set version of new record
|
||||||
if($from) {
|
$from->forceChange();
|
||||||
$from->forceChange();
|
if($createNewVersion) {
|
||||||
if($createNewVersion) {
|
// Clear version to be automatically created on write
|
||||||
$latest = self::get_latest_version($baseClass, $this->owner->ID);
|
$from->Version = null;
|
||||||
$this->owner->Version = $latest->Version + 1;
|
} else {
|
||||||
} else {
|
$from->migrateVersion($from->Version);
|
||||||
$from->migrateVersion($from->Version);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark this version as having been published at some stage
|
// Mark this version as having been published at some stage
|
||||||
|
$publisherID = isset(Member::currentUser()->ID) ? Member::currentUser()->ID : 0;
|
||||||
DB::prepared_query("UPDATE \"{$extTable}_versions\"
|
DB::prepared_query("UPDATE \"{$extTable}_versions\"
|
||||||
SET \"WasPublished\" = ?, \"PublisherID\" = ?
|
SET \"WasPublished\" = ?, \"PublisherID\" = ?
|
||||||
WHERE \"RecordID\" = ? AND \"Version\" = ?",
|
WHERE \"RecordID\" = ? AND \"Version\" = ?",
|
||||||
array(1, $publisherID, $from->ID, $from->Version)
|
array(1, $publisherID, $from->ID, $from->Version)
|
||||||
);
|
);
|
||||||
|
|
||||||
$oldMode = Versioned::get_reading_mode();
|
|
||||||
Versioned::reading_stage($toStage);
|
|
||||||
|
|
||||||
$conn = DB::get_conn();
|
|
||||||
if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing($baseClass, true);
|
|
||||||
$from->write();
|
|
||||||
if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing($baseClass, false);
|
|
||||||
|
|
||||||
$from->destroy();
|
|
||||||
|
|
||||||
Versioned::set_reading_mode($oldMode);
|
|
||||||
} else {
|
|
||||||
user_error("Can't find {$this->owner->URLSegment}/{$this->owner->ID} in stage $fromStage", E_USER_WARNING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Change to new stage, write, and revert state
|
||||||
|
$oldMode = Versioned::get_reading_mode();
|
||||||
|
Versioned::reading_stage($toStage);
|
||||||
|
|
||||||
|
$conn = DB::get_conn();
|
||||||
|
if(method_exists($conn, 'allowPrimaryKeyEditing')) {
|
||||||
|
$conn->allowPrimaryKeyEditing($baseClass, true);
|
||||||
|
$from->write();
|
||||||
|
$conn->allowPrimaryKeyEditing($baseClass, false);
|
||||||
|
} else {
|
||||||
|
$from->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
$from->destroy();
|
||||||
|
|
||||||
|
Versioned::set_reading_mode($oldMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +31,7 @@ class VersionedTest extends SapphireTest {
|
|||||||
'VersionedTest_WithIndexes_Live' =>
|
'VersionedTest_WithIndexes_Live' =>
|
||||||
array('value' => false, 'message' => 'Unique indexes are no longer unique in _Live table'),
|
array('value' => false, 'message' => 'Unique indexes are no longer unique in _Live table'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test each table's performance
|
// Test each table's performance
|
||||||
foreach ($tableExpectations as $tableName => $expectation) {
|
foreach ($tableExpectations as $tableName => $expectation) {
|
||||||
$indexes = DB::get_schema()->indexList($tableName);
|
$indexes = DB::get_schema()->indexList($tableName);
|
||||||
@ -196,15 +196,37 @@ class VersionedTest extends SapphireTest {
|
|||||||
$page1 = $this->objFromFixture('VersionedTest_DataObject', 'page1');
|
$page1 = $this->objFromFixture('VersionedTest_DataObject', 'page1');
|
||||||
$page1->Content = 'orig';
|
$page1->Content = 'orig';
|
||||||
$page1->write();
|
$page1->write();
|
||||||
$oldVersion = $page1->Version;
|
$firstVersion = $page1->Version;
|
||||||
$page1->publish('Stage', 'Live', false);
|
$page1->publish('Stage', 'Live', false);
|
||||||
$this->assertEquals($oldVersion, $page1->Version, 'publish() with $createNewVersion=FALSE');
|
$this->assertEquals(
|
||||||
|
$firstVersion,
|
||||||
|
$page1->Version,
|
||||||
|
'publish() with $createNewVersion=FALSE does not create a new version'
|
||||||
|
);
|
||||||
|
|
||||||
$page1->Content = 'changed';
|
$page1->Content = 'changed';
|
||||||
$page1->write();
|
$page1->write();
|
||||||
$oldVersion = $page1->Version;
|
$secondVersion = $page1->Version;
|
||||||
|
$this->assertTrue($firstVersion < $secondVersion, 'write creates new version');
|
||||||
|
|
||||||
$page1->publish('Stage', 'Live', true);
|
$page1->publish('Stage', 'Live', true);
|
||||||
$this->assertTrue($oldVersion < $page1->Version, 'publish() with $createNewVersion=TRUE');
|
$thirdVersion = Versioned::get_latest_version('VersionedTest_DataObject', $page1->ID)->Version;
|
||||||
|
$liveVersion = Versioned::get_versionnumber_by_stage('VersionedTest_DataObject', 'Live', $page1->ID);
|
||||||
|
$stageVersion = Versioned::get_versionnumber_by_stage('VersionedTest_DataObject', 'Stage', $page1->ID);
|
||||||
|
$this->assertTrue(
|
||||||
|
$secondVersion < $thirdVersion,
|
||||||
|
'publish() with $createNewVersion=TRUE creates a new version'
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
$liveVersion,
|
||||||
|
$thirdVersion,
|
||||||
|
'publish() with $createNewVersion=TRUE publishes to live'
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
$stageVersion,
|
||||||
|
$secondVersion,
|
||||||
|
'publish() with $createNewVersion=TRUE does not affect stage'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRollbackTo() {
|
public function testRollbackTo() {
|
||||||
@ -220,10 +242,11 @@ class VersionedTest extends SapphireTest {
|
|||||||
$changedVersion = $page1->Version;
|
$changedVersion = $page1->Version;
|
||||||
|
|
||||||
$page1->doRollbackTo($origVersion);
|
$page1->doRollbackTo($origVersion);
|
||||||
$page1 = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage',
|
$page1 = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', array(
|
||||||
sprintf('"VersionedTest_DataObject"."ID" = %d', $page1->ID));
|
'"VersionedTest_DataObject"."ID" = ?' => $page1->ID
|
||||||
|
));
|
||||||
|
|
||||||
$this->assertTrue($page1->Version > $changedVersion, 'Create a new higher version number');
|
$this->assertTrue($page1->Version == $changedVersion + 1, 'Create a new higher version number');
|
||||||
$this->assertEquals('orig', $page1->Content, 'Copies the content from the old version');
|
$this->assertEquals('orig', $page1->Content, 'Copies the content from the old version');
|
||||||
|
|
||||||
// check db entries
|
// check db entries
|
||||||
|
Loading…
Reference in New Issue
Block a user