mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
FIXED: Issue where temporary table would cause unpredictable behaviour. Temporary table functionality was substituted with subqueries in each use case.
ADDED: Test case for version archive functionality.
This commit is contained in:
parent
c55b018feb
commit
0f09305e3d
@ -160,10 +160,19 @@ class Versioned extends DataExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Link to the version archived on that date
|
// Link to the version archived on that date
|
||||||
$archiveTable = $this->requireArchiveTempTable($baseTable, $date);
|
$safeDate = Convert::raw2sql($date);
|
||||||
$query->addFrom(array($archiveTable => "INNER JOIN \"$archiveTable\"
|
$query->addWhere(
|
||||||
ON \"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\"
|
"`{$baseTable}_versions`.`Version` IN
|
||||||
AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\""));
|
(SELECT LatestVersion FROM
|
||||||
|
(SELECT
|
||||||
|
`{$baseTable}_versions`.`RecordID`,
|
||||||
|
MAX(`{$baseTable}_versions`.`Version`) AS LatestVersion
|
||||||
|
FROM `{$baseTable}_versions`
|
||||||
|
WHERE `{$baseTable}_versions`.`LastEdited` <= '$safeDate'
|
||||||
|
GROUP BY `{$baseTable}_versions`.`RecordID`
|
||||||
|
) AS `{$baseTable}_versions_latest`
|
||||||
|
WHERE `{$baseTable}_versions_latest`.`RecordID` = `{$baseTable}_versions`.`RecordID`
|
||||||
|
)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Reading a specific stage (Stage or Live)
|
// Reading a specific stage (Stage or Live)
|
||||||
@ -204,10 +213,18 @@ class Versioned extends DataExtension {
|
|||||||
// Return latest version instances, regardless of whether they are on a particular stage
|
// Return latest version instances, regardless of whether they are on a particular stage
|
||||||
// This provides "show all, including deleted" functonality
|
// This provides "show all, including deleted" functonality
|
||||||
if($dataQuery->getQueryParam('Versioned.mode') == 'latest_versions') {
|
if($dataQuery->getQueryParam('Versioned.mode') == 'latest_versions') {
|
||||||
$archiveTable = self::requireArchiveTempTable($baseTable);
|
$query->addWhere(
|
||||||
$query->addInnerJoin($archiveTable, "\"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
|
"`{$alias}_versions`.`Version` IN
|
||||||
|
(SELECT LatestVersion FROM
|
||||||
|
(SELECT
|
||||||
|
`{$alias}_versions`.`RecordID`,
|
||||||
|
MAX(`{$alias}_versions`.`Version`) AS LatestVersion
|
||||||
|
FROM `{$alias}_versions`
|
||||||
|
GROUP BY `{$alias}_versions`.`RecordID`
|
||||||
|
) AS `{$alias}_versions_latest`
|
||||||
|
WHERE `{$alias}_versions_latest`.`RecordID` = `{$alias}_versions`.`RecordID`
|
||||||
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidArgumentException("Bad value for query parameter Versioned.mode: " . $dataQuery->getQueryParam('Versioned.mode'));
|
throw new InvalidArgumentException("Bad value for query parameter Versioned.mode: " . $dataQuery->getQueryParam('Versioned.mode'));
|
||||||
@ -235,34 +252,6 @@ class Versioned extends DataExtension {
|
|||||||
self::$archive_tables = array();
|
self::$archive_tables = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a temporary table mapping each database record to its version on the given date.
|
|
||||||
* This is used by the versioning system to return database content on that date.
|
|
||||||
* @param string $baseTable The base table.
|
|
||||||
* @param string $date The date. If omitted, then the latest version of each page will be returned.
|
|
||||||
* @todo Ensure that this is DB abstracted
|
|
||||||
*/
|
|
||||||
protected static function requireArchiveTempTable($baseTable, $date = null) {
|
|
||||||
if(!isset(self::$archive_tables[$baseTable])) {
|
|
||||||
self::$archive_tables[$baseTable] = DB::createTable("_Archive$baseTable", array(
|
|
||||||
"ID" => "INT NOT NULL",
|
|
||||||
"Version" => "INT NOT NULL",
|
|
||||||
), null, array('temporary' => true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!DB::query("SELECT COUNT(*) FROM \"" . self::$archive_tables[$baseTable] . "\"")->value()) {
|
|
||||||
if($date) $dateClause = "WHERE \"LastEdited\" <= '$date'";
|
|
||||||
else $dateClause = "";
|
|
||||||
|
|
||||||
DB::query("INSERT INTO \"" . self::$archive_tables[$baseTable] . "\"
|
|
||||||
SELECT \"RecordID\", max(\"Version\") FROM \"{$baseTable}_versions\"
|
|
||||||
$dateClause
|
|
||||||
GROUP BY \"RecordID\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$archive_tables[$baseTable];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of DataObject extensions that may require versioning for extra tables
|
* An array of DataObject extensions that may require versioning for extra tables
|
||||||
* The array value is a set of suffixes to form these table names, assuming a preceding '_'.
|
* The array value is a set of suffixes to form these table names, assuming a preceding '_'.
|
||||||
|
@ -266,6 +266,59 @@ class VersionedTest extends SapphireTest {
|
|||||||
$this->assertInstanceOf("VersionedTest_DataObject", $obj3);
|
$this->assertInstanceOf("VersionedTest_DataObject", $obj3);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testArchiveVersion() {
|
||||||
|
|
||||||
|
// In 2005 this file was created
|
||||||
|
SS_Datetime::set_mock_now('2005-01-01 00:00:00');
|
||||||
|
$testPage = new VersionedTest_Subclass();
|
||||||
|
$testPage->Title = 'Archived page';
|
||||||
|
$testPage->Content = 'This is the content from 2005';
|
||||||
|
$testPage->ExtraField = '2005';
|
||||||
|
$testPage->write();
|
||||||
|
$testPage->publish('Stage', 'Live');
|
||||||
|
|
||||||
|
// In 2007 we updated it
|
||||||
|
SS_Datetime::set_mock_now('2007-01-01 00:00:00');
|
||||||
|
$testPage->Content = "It's 2007 already!";
|
||||||
|
$testPage->ExtraField = '2007';
|
||||||
|
$testPage->write();
|
||||||
|
$testPage->publish('Stage', 'Live');
|
||||||
|
|
||||||
|
// In 2009 we updated it again
|
||||||
|
SS_Datetime::set_mock_now('2009-01-01 00:00:00');
|
||||||
|
$testPage->Content = "I'm enjoying 2009";
|
||||||
|
$testPage->ExtraField = '2009';
|
||||||
|
$testPage->write();
|
||||||
|
$testPage->publish('Stage', 'Live');
|
||||||
|
|
||||||
|
// End mock, back to the present day:)
|
||||||
|
SS_Datetime::clear_mock_now();
|
||||||
|
|
||||||
|
// Test 1 - 2006 Content
|
||||||
|
singleton('VersionedTest_Subclass')->flushCache(true);
|
||||||
|
Versioned::set_reading_mode('Archive.2006-01-01 00:00:00');
|
||||||
|
$testPage2006 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
|
||||||
|
$this->assertInstanceOf("VersionedTest_Subclass", $testPage2006);
|
||||||
|
$this->assertEquals("2005", $testPage2006->ExtraField);
|
||||||
|
$this->assertEquals("This is the content from 2005", $testPage2006->Content);
|
||||||
|
|
||||||
|
// Test 2 - 2008 Content
|
||||||
|
singleton('VersionedTest_Subclass')->flushCache(true);
|
||||||
|
Versioned::set_reading_mode('Archive.2008-01-01 00:00:00');
|
||||||
|
$testPage2008 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
|
||||||
|
$this->assertInstanceOf("VersionedTest_Subclass", $testPage2008);
|
||||||
|
$this->assertEquals("2007", $testPage2008->ExtraField);
|
||||||
|
$this->assertEquals("It's 2007 already!", $testPage2008->Content);
|
||||||
|
|
||||||
|
// Test 3 - Today
|
||||||
|
singleton('VersionedTest_Subclass')->flushCache(true);
|
||||||
|
Versioned::set_reading_mode('Stage.Stage');
|
||||||
|
$testPageCurrent = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
|
||||||
|
$this->assertInstanceOf("VersionedTest_Subclass", $testPageCurrent);
|
||||||
|
$this->assertEquals("2009", $testPageCurrent->ExtraField);
|
||||||
|
$this->assertEquals("I'm enjoying 2009", $testPageCurrent->Content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VersionedTest_DataObject extends DataObject implements TestOnly {
|
class VersionedTest_DataObject extends DataObject implements TestOnly {
|
||||||
|
Loading…
Reference in New Issue
Block a user