2009-05-06 08:36:16 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
class VersionedTest extends SapphireTest {
|
|
|
|
static $fixture_file = 'sapphire/tests/model/VersionedTest.yml';
|
2010-04-12 04:03:16 +02:00
|
|
|
|
|
|
|
protected $extraDataObjects = array(
|
|
|
|
'VersionedTest_DataObject',
|
2010-10-19 05:01:51 +02:00
|
|
|
'VersionedTest_Subclass'
|
2010-04-12 04:03:16 +02:00
|
|
|
);
|
2009-05-06 08:36:16 +02:00
|
|
|
|
2010-10-19 05:01:51 +02:00
|
|
|
protected $requiredExtensions = array(
|
|
|
|
"VersionedTest_DataObject" => array('Versioned')
|
|
|
|
);
|
|
|
|
|
|
|
|
function testDeletingOrphanedVersions() {
|
|
|
|
$obj = new VersionedTest_Subclass();
|
|
|
|
$obj->ExtraField = 'Foo'; // ensure that child version table gets written
|
|
|
|
$obj->write();
|
|
|
|
$obj->publish('Stage', 'Live');
|
|
|
|
|
|
|
|
$obj->ExtraField = 'Bar'; // ensure that child version table gets written
|
|
|
|
$obj->write();
|
|
|
|
$obj->publish('Stage', 'Live');
|
|
|
|
|
|
|
|
$versions = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\" WHERE \"RecordID\" = '$obj->ID'")->value();
|
|
|
|
|
|
|
|
$this->assertGreaterThan(0, $versions, 'At least 1 version exists in the history of the page');
|
|
|
|
|
|
|
|
// Force orphaning of all versions created earlier, only on parent record.
|
|
|
|
// The child versiones table should still have the correct relationship
|
|
|
|
DB::query("DELETE FROM \"VersionedTest_DataObject_versions\" WHERE \"RecordID\" = $obj->ID");
|
|
|
|
|
|
|
|
// insert a record with no primary key (ID)
|
2010-10-19 05:06:15 +02:00
|
|
|
DB::query("INSERT INTO \"VersionedTest_DataObject_versions\" (\"RecordID\") VALUES ($obj->ID)");
|
2010-10-19 05:01:51 +02:00
|
|
|
|
|
|
|
// run the script which should clean that up
|
|
|
|
$obj->augmentDatabase();
|
|
|
|
|
|
|
|
$versions = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\" WHERE \"RecordID\" = '$obj->ID'")->value();
|
|
|
|
$this->assertEquals(0, $versions, 'Orphaned versions on child tables are removed');
|
|
|
|
|
|
|
|
// test that it doesn't delete records that we need
|
|
|
|
$obj->write();
|
|
|
|
$obj->publish('Stage', 'Live');
|
|
|
|
|
|
|
|
$count = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\" WHERE \"RecordID\" = '$obj->ID'")->value();
|
|
|
|
$obj->augmentDatabase();
|
|
|
|
|
|
|
|
$count2 = DB::query("SELECT COUNT(*) FROM \"VersionedTest_Subclass_versions\" WHERE \"RecordID\" = '$obj->ID'")->value();
|
|
|
|
|
|
|
|
$this->assertEquals($count, $count2);
|
|
|
|
}
|
|
|
|
|
2009-05-27 02:09:23 +02:00
|
|
|
function testForceChangeUpdatesVersion() {
|
2010-10-12 23:42:45 +02:00
|
|
|
$obj = new VersionedTest_DataObject();
|
|
|
|
$obj->Name = "test";
|
|
|
|
$obj->write();
|
|
|
|
|
|
|
|
$oldVersion = $obj->Version;
|
|
|
|
$obj->forceChange();
|
|
|
|
$obj->write();
|
2010-10-13 03:04:38 +02:00
|
|
|
|
2009-05-27 02:09:23 +02:00
|
|
|
$this->assertTrue(
|
2010-10-12 23:42:45 +02:00
|
|
|
($obj->Version > $oldVersion),
|
2009-05-27 02:09:23 +02:00
|
|
|
"A object Version is increased when just calling forceChange() without any other changes"
|
|
|
|
);
|
|
|
|
}
|
2010-10-19 05:01:51 +02:00
|
|
|
|
2009-05-06 08:36:16 +02:00
|
|
|
/**
|
|
|
|
* Test Versioned::get_including_deleted()
|
|
|
|
*/
|
|
|
|
function testGetIncludingDeleted() {
|
|
|
|
// Delete a page
|
|
|
|
$this->objFromFixture('Page', 'page3')->delete();
|
2010-10-13 03:04:38 +02:00
|
|
|
|
2009-05-06 08:36:16 +02:00
|
|
|
// Get all items, ignoring deleted
|
2009-09-30 23:54:49 +02:00
|
|
|
$remainingPages = DataObject::get("SiteTree", "\"ParentID\" = 0", "\"SiteTree\".\"ID\" ASC");
|
2009-05-06 08:36:16 +02:00
|
|
|
// Check that page 3 has gone
|
2009-05-14 07:26:47 +02:00
|
|
|
$this->assertNotNull($remainingPages);
|
2009-05-06 08:36:16 +02:00
|
|
|
$this->assertEquals(array("Page 1", "Page 2"), $remainingPages->column('Title'));
|
|
|
|
|
|
|
|
// Get all including deleted
|
2009-09-30 23:54:49 +02:00
|
|
|
$allPages = Versioned::get_including_deleted("SiteTree", "\"ParentID\" = 0", "\"SiteTree\".\"ID\" ASC");
|
2009-05-06 08:36:16 +02:00
|
|
|
// Check that page 3 is still there
|
|
|
|
$this->assertEquals(array("Page 1", "Page 2", "Page 3"), $allPages->column('Title'));
|
|
|
|
|
|
|
|
// Check that this still works if we switch to reading the other stage
|
|
|
|
Versioned::reading_stage("Live");
|
2009-09-30 23:54:49 +02:00
|
|
|
$allPages = Versioned::get_including_deleted("SiteTree", "\"ParentID\" = 0", "\"SiteTree\".\"ID\" ASC");
|
2009-05-06 08:36:16 +02:00
|
|
|
$this->assertEquals(array("Page 1", "Page 2", "Page 3"), $allPages->column('Title'));
|
|
|
|
|
|
|
|
}
|
2009-06-22 04:42:42 +02:00
|
|
|
|
|
|
|
function testVersionedFieldsAdded() {
|
|
|
|
$obj = new VersionedTest_DataObject();
|
|
|
|
// Check that the Version column is added as a full-fledged column
|
2011-03-11 03:06:09 +01:00
|
|
|
$this->assertType('Int', $obj->dbObject('Version'));
|
2010-10-13 03:04:38 +02:00
|
|
|
|
2009-06-22 04:42:42 +02:00
|
|
|
$obj2 = new VersionedTest_Subclass();
|
|
|
|
// Check that the Version column is added as a full-fledged column
|
2011-03-11 03:06:09 +01:00
|
|
|
$this->assertType('Int', $obj2->dbObject('Version'));
|
2009-06-22 04:42:42 +02:00
|
|
|
}
|
|
|
|
|
2010-10-13 03:04:38 +02:00
|
|
|
function testPublishCreateNewVersion() {
|
|
|
|
$page1 = $this->objFromFixture('Page', 'page1');
|
|
|
|
$page1->Content = 'orig';
|
|
|
|
$page1->write();
|
|
|
|
$oldVersion = $page1->Version;
|
|
|
|
$page1->publish('Stage', 'Live', false);
|
|
|
|
$this->assertEquals($oldVersion, $page1->Version, 'publish() with $createNewVersion=FALSE');
|
|
|
|
|
|
|
|
$page1->Content = 'changed';
|
|
|
|
$page1->write();
|
|
|
|
$oldVersion = $page1->Version;
|
|
|
|
$page1->publish('Stage', 'Live', true);
|
|
|
|
$this->assertTrue($oldVersion < $page1->Version, 'publish() with $createNewVersion=TRUE');
|
|
|
|
}
|
|
|
|
|
|
|
|
function testRollbackTo() {
|
|
|
|
$page1 = $this->objFromFixture('Page', 'page1');
|
|
|
|
$page1->Content = 'orig';
|
|
|
|
$page1->write();
|
|
|
|
$page1->publish('Stage', 'Live');
|
|
|
|
$origVersion = $page1->Version;
|
|
|
|
|
|
|
|
$page1->Content = 'changed';
|
|
|
|
$page1->write();
|
|
|
|
$page1->publish('Stage', 'Live');
|
|
|
|
$changedVersion = $page1->Version;
|
|
|
|
|
|
|
|
$page1->doRollbackTo($origVersion);
|
2010-10-13 03:27:26 +02:00
|
|
|
$page1 = Versioned::get_one_by_stage('Page', 'Stage', sprintf('"SiteTree"."ID" = %d', $page1->ID));
|
2010-10-13 03:04:38 +02:00
|
|
|
|
|
|
|
$this->assertTrue($page1->Version > $changedVersion, 'Create a new higher version number');
|
|
|
|
$this->assertEquals('orig', $page1->Content, 'Copies the content from the old version');
|
|
|
|
}
|
2010-10-15 04:55:45 +02:00
|
|
|
|
|
|
|
function testDeleteFromStage() {
|
|
|
|
$page1 = $this->objFromFixture('Page', 'page1');
|
|
|
|
$pageID = $page1->ID;
|
|
|
|
|
|
|
|
$page1->Content = 'orig';
|
|
|
|
$page1->write();
|
|
|
|
$page1->publish('Stage', 'Live');
|
|
|
|
|
|
|
|
$this->assertEquals(1, DB::query('SELECT COUNT(*) FROM "SiteTree" WHERE "ID" = '.$pageID)->value());
|
|
|
|
$this->assertEquals(1, DB::query('SELECT COUNT(*) FROM "SiteTree_Live" WHERE "ID" = '.$pageID)->value());
|
|
|
|
|
|
|
|
$page1->deleteFromStage('Live');
|
|
|
|
|
|
|
|
// Confirm that deleteFromStage() doesn't manipulate the original record
|
|
|
|
$this->assertEquals($pageID, $page1->ID);
|
|
|
|
|
|
|
|
$this->assertEquals(1, DB::query('SELECT COUNT(*) FROM "SiteTree" WHERE "ID" = '.$pageID)->value());
|
|
|
|
$this->assertEquals(0, DB::query('SELECT COUNT(*) FROM "SiteTree_Live" WHERE "ID" = '.$pageID)->value());
|
|
|
|
|
|
|
|
$page1->delete();
|
|
|
|
|
|
|
|
$this->assertEquals(0, $page1->ID);
|
|
|
|
$this->assertEquals(0, DB::query('SELECT COUNT(*) FROM "SiteTree" WHERE "ID" = '.$pageID)->value());
|
|
|
|
$this->assertEquals(0, DB::query('SELECT COUNT(*) FROM "SiteTree_Live" WHERE "ID" = '.$pageID)->value());
|
|
|
|
}
|
2010-10-13 03:04:38 +02:00
|
|
|
|
2010-10-15 05:53:14 +02:00
|
|
|
function testWritingNewToStage() {
|
|
|
|
$origStage = Versioned::current_stage();
|
|
|
|
|
|
|
|
Versioned::reading_stage("Stage");
|
|
|
|
$page = new Page();
|
|
|
|
$page->Title = "testWritingNewToStage";
|
|
|
|
$page->URLSegment = "testWritingNewToStage";
|
|
|
|
$page->write();
|
|
|
|
|
|
|
|
$live = Versioned::get_by_stage('SiteTree', 'Live', "\"SiteTree_Live\".\"ID\"='$page->ID'");
|
|
|
|
$this->assertNull($live);
|
|
|
|
|
|
|
|
$stage = Versioned::get_by_stage('SiteTree', 'Stage', "\"SiteTree\".\"ID\"='$page->ID'");
|
|
|
|
$this->assertNotNull($stage);
|
|
|
|
$this->assertEquals($stage->First()->Title, 'testWritingNewToStage');
|
|
|
|
|
|
|
|
Versioned::reading_stage($origStage);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This tests for the situation described in the ticket #5596.
|
|
|
|
* Writing new Page to live first creates a row in SiteTree table (to get the new ID), then "changes
|
|
|
|
* it's mind" in Versioned and writes SiteTree_Live. It does not remove the SiteTree record though.
|
|
|
|
*/
|
|
|
|
function testWritingNewToLive() {
|
|
|
|
$origStage = Versioned::current_stage();
|
|
|
|
|
|
|
|
Versioned::reading_stage("Live");
|
|
|
|
$page = new Page();
|
|
|
|
$page->Title = "testWritingNewToLive";
|
|
|
|
$page->URLSegment = "testWritingNewToLive";
|
|
|
|
$page->write();
|
|
|
|
|
|
|
|
$live = Versioned::get_by_stage('SiteTree', 'Live', "\"SiteTree_Live\".\"ID\"='$page->ID'");
|
|
|
|
$this->assertNotNull($live->First());
|
|
|
|
$this->assertEquals($live->First()->Title, 'testWritingNewToLive');
|
|
|
|
|
|
|
|
$stage = Versioned::get_by_stage('SiteTree', 'Stage', "\"SiteTree\".\"ID\"='$page->ID'");
|
|
|
|
$this->assertNull($stage);
|
|
|
|
|
|
|
|
Versioned::reading_stage($origStage);
|
|
|
|
}
|
2010-10-19 00:53:19 +02:00
|
|
|
|
|
|
|
/**
|
2010-10-19 02:58:40 +02:00
|
|
|
* Tests DataObject::hasOwnTableDatabaseField
|
2010-10-19 00:53:19 +02:00
|
|
|
*/
|
|
|
|
public function testHasOwnTableDatabaseFieldWithVersioned() {
|
|
|
|
$noversion = new DataObject();
|
|
|
|
$versioned = new VersionedTest_DataObject();
|
|
|
|
$versionedSub = new VersionedTest_Subclass();
|
|
|
|
$versionField = new VersionedTest_UnversionedWithField();
|
|
|
|
|
|
|
|
$this->assertFalse(
|
|
|
|
(bool) $noversion->hasOwnTableDatabaseField('Version'),
|
|
|
|
'Plain models have no version field.'
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
'Int', $versioned->hasOwnTableDatabaseField('Version'),
|
|
|
|
'The versioned ext adds an Int version field.'
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
'Int', $versionedSub->hasOwnTableDatabaseField('Version'),
|
|
|
|
'Sub-classes of a versioned model have a Version field.'
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
'Varchar', $versionField->hasOwnTableDatabaseField('Version'),
|
|
|
|
'Models w/o Versioned can have their own Version field.'
|
|
|
|
);
|
|
|
|
}
|
2009-06-22 04:42:42 +02:00
|
|
|
}
|
|
|
|
|
2010-04-12 04:03:16 +02:00
|
|
|
class VersionedTest_DataObject extends DataObject implements TestOnly {
|
2009-06-22 04:42:42 +02:00
|
|
|
static $db = array(
|
|
|
|
"Name" => "Varchar",
|
|
|
|
);
|
|
|
|
|
|
|
|
static $extensions = array(
|
|
|
|
"Versioned('Stage', 'Live')"
|
|
|
|
);
|
|
|
|
}
|
2009-05-06 08:36:16 +02:00
|
|
|
|
2010-04-12 04:03:16 +02:00
|
|
|
class VersionedTest_Subclass extends VersionedTest_DataObject implements TestOnly {
|
2009-06-22 04:42:42 +02:00
|
|
|
static $db = array(
|
|
|
|
"ExtraField" => "Varchar",
|
|
|
|
);
|
2010-10-19 05:01:51 +02:00
|
|
|
|
|
|
|
static $extensions = array(
|
|
|
|
"Versioned('Stage', 'Live')"
|
|
|
|
);
|
2009-06-22 04:42:42 +02:00
|
|
|
}
|
2010-10-19 00:53:19 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @ignore
|
|
|
|
*/
|
|
|
|
class VersionedTest_UnversionedWithField extends DataObject implements TestOnly {
|
|
|
|
public static $db = array('Version' => 'Varchar(255)');
|
|
|
|
}
|