mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
765 lines
25 KiB
PHP
765 lines
25 KiB
PHP
<?php
|
|
|
|
class VirtualPageTest extends FunctionalTest {
|
|
protected static $fixture_file = 'VirtualPageTest.yml';
|
|
protected static $use_draft_site = false;
|
|
protected $autoFollowRedirection = false;
|
|
|
|
protected $extraDataObjects = array(
|
|
'VirtualPageTest_ClassA',
|
|
'VirtualPageTest_ClassB',
|
|
'VirtualPageTest_ClassC',
|
|
'VirtualPageTest_NotRoot',
|
|
'VirtualPageTest_PageExtension',
|
|
'VirtualPageTest_PageWithAllowedChildren',
|
|
'VirtualPageTest_TestDBField',
|
|
'VirtualPageTest_VirtualPageSub',
|
|
);
|
|
|
|
protected $illegalExtensions = array(
|
|
'SiteTree' => array('SiteTreeSubsites', 'Translatable')
|
|
);
|
|
|
|
protected $requiredExtensions = array(
|
|
'SiteTree' => array('VirtualPageTest_PageExtension')
|
|
);
|
|
|
|
public function setUp() {
|
|
parent::setUp();
|
|
|
|
// Ensure we always have permission to save/publish
|
|
$this->logInWithPermission("ADMIN");
|
|
|
|
$this->origInitiallyCopiedFields = VirtualPage::config()->initially_copied_fields;
|
|
Config::inst()->remove('VirtualPage', 'initially_copied_fields');
|
|
VirtualPage::config()->initially_copied_fields = array_merge(
|
|
$this->origInitiallyCopiedFields,
|
|
array('MyInitiallyCopiedField')
|
|
);
|
|
|
|
$this->origNonVirtualField = VirtualPage::config()->non_virtual_fields;
|
|
Config::inst()->remove('VirtualPage', 'non_virtual_fields');
|
|
VirtualPage::config()->non_virtual_fields = array_merge(
|
|
$this->origNonVirtualField,
|
|
array('MyNonVirtualField', 'MySharedNonVirtualField')
|
|
);
|
|
}
|
|
|
|
public function tearDown() {
|
|
parent::tearDown();
|
|
|
|
Config::inst()->remove('VirtualPage', 'initially_copied_fields');
|
|
Config::inst()->remove('VirtualPage', 'non_virtual_fields');
|
|
VirtualPage::config()->initially_copied_fields = $this->origInitiallyCopiedFields;
|
|
VirtualPage::config()->non_virtual_fields = $this->origNonVirtualField;
|
|
}
|
|
|
|
/**
|
|
* Test that, after you update the source page of a virtual page, all the virtual pages
|
|
* are updated
|
|
*/
|
|
public function testEditingSourcePageUpdatesVirtualPages() {
|
|
$master = $this->objFromFixture('Page', 'master');
|
|
$master->Title = "New title";
|
|
$master->MenuTitle = "New menutitle";
|
|
$master->Content = "<p>New content</p>";
|
|
$master->write();
|
|
|
|
$vp1 = $this->objFromFixture('VirtualPage', 'vp1');
|
|
$vp2 = $this->objFromFixture('VirtualPage', 'vp2');
|
|
|
|
$this->assertEquals("New title", $vp1->Title);
|
|
$this->assertEquals("New title", $vp2->Title);
|
|
$this->assertEquals("New menutitle", $vp1->MenuTitle);
|
|
$this->assertEquals("New menutitle", $vp2->MenuTitle);
|
|
$this->assertEquals("<p>New content</p>", $vp1->Content);
|
|
$this->assertEquals("<p>New content</p>", $vp2->Content);
|
|
}
|
|
|
|
/**
|
|
* Test that, after you publish the source page of a virtual page, all the already published
|
|
* virtual pages are published
|
|
*/
|
|
public function testPublishingSourcePagePublishesAlreadyPublishedVirtualPages() {
|
|
$this->logInWithPermission('ADMIN');
|
|
|
|
$master = $this->objFromFixture('Page', 'master');
|
|
$master->doPublish();
|
|
|
|
$master->Title = "New title";
|
|
$master->MenuTitle = "New menutitle";
|
|
$master->Content = "<p>New content</p>";
|
|
$master->write();
|
|
|
|
$vp1 = DataObject::get_by_id("VirtualPage", $this->idFromFixture('VirtualPage', 'vp1'));
|
|
$vp2 = DataObject::get_by_id("VirtualPage", $this->idFromFixture('VirtualPage', 'vp2'));
|
|
$this->assertTrue($vp1->doPublish());
|
|
$this->assertTrue($vp2->doPublish());
|
|
|
|
$master->doPublish();
|
|
|
|
Versioned::reading_stage("Live");
|
|
$vp1 = DataObject::get_by_id("VirtualPage", $this->idFromFixture('VirtualPage', 'vp1'));
|
|
$vp2 = DataObject::get_by_id("VirtualPage", $this->idFromFixture('VirtualPage', 'vp2'));
|
|
|
|
$this->assertNotNull($vp1);
|
|
$this->assertNotNull($vp2);
|
|
|
|
$this->assertEquals("New title", $vp1->Title);
|
|
$this->assertEquals("New title", $vp2->Title);
|
|
$this->assertEquals("New menutitle", $vp1->MenuTitle);
|
|
$this->assertEquals("New menutitle", $vp2->MenuTitle);
|
|
$this->assertEquals("<p>New content</p>", $vp1->Content);
|
|
$this->assertEquals("<p>New content</p>", $vp2->Content);
|
|
Versioned::reading_stage("Stage");
|
|
}
|
|
|
|
/**
|
|
* Test that virtual pages get the content from the master page when they are created.
|
|
*/
|
|
public function testNewVirtualPagesGrabTheContentFromTheirMaster() {
|
|
$vp = new VirtualPage();
|
|
$vp->write();
|
|
|
|
$vp->CopyContentFromID = $this->idFromFixture('Page', 'master');
|
|
$vp->write();
|
|
|
|
$this->assertEquals("My Page", $vp->Title);
|
|
$this->assertEquals("My Page Nav", $vp->MenuTitle);
|
|
|
|
$vp->CopyContentFromID = $this->idFromFixture('Page', 'master2');
|
|
$vp->write();
|
|
|
|
$this->assertEquals("My Other Page", $vp->Title);
|
|
$this->assertEquals("My Other Page Nav", $vp->MenuTitle);
|
|
}
|
|
|
|
/**
|
|
* Virtual pages are always supposed to chose the same content as the published source page.
|
|
* This means that when you publish them, they should show the published content of the source
|
|
* page, not the draft content at the time when you clicked 'publish' in the CMS.
|
|
*/
|
|
public function testPublishingAVirtualPageCopiedPublishedContentNotDraftContent() {
|
|
$p = new Page();
|
|
$p->Content = "published content";
|
|
$p->write();
|
|
$p->doPublish();
|
|
|
|
// Don't publish this change - published page will still say 'published content'
|
|
$p->Content = "draft content";
|
|
$p->write();
|
|
|
|
$vp = new VirtualPage();
|
|
$vp->CopyContentFromID = $p->ID;
|
|
$vp->write();
|
|
|
|
$vp->doPublish();
|
|
|
|
// The draft content of the virtual page should say 'draft content'
|
|
$this->assertEquals('draft content',
|
|
DB::query('SELECT "Content" from "SiteTree" WHERE "ID" = ' . $vp->ID)->value());
|
|
|
|
// The published content of the virtual page should say 'published content'
|
|
$this->assertEquals('published content',
|
|
DB::query('SELECT "Content" from "SiteTree_Live" WHERE "ID" = ' . $vp->ID)->value());
|
|
}
|
|
|
|
public function testCantPublishVirtualPagesBeforeTheirSource() {
|
|
// An unpublished source page
|
|
$p = new Page();
|
|
$p->Content = "test content";
|
|
$p->write();
|
|
|
|
// With no source page, we can't publish
|
|
$vp = new VirtualPage();
|
|
$vp->write();
|
|
$this->assertFalse($vp->canPublish());
|
|
|
|
// When the source page isn't published, we can't publish
|
|
$vp->CopyContentFromID = $p->ID;
|
|
$vp->write();
|
|
$this->assertFalse($vp->canPublish());
|
|
|
|
// Once the source page gets published, then we can publish
|
|
$p->doPublish();
|
|
$this->assertTrue($vp->canPublish());
|
|
}
|
|
|
|
public function testCanDeleteOrphanedVirtualPagesFromLive() {
|
|
// An unpublished source page
|
|
$p = new Page();
|
|
$p->Content = "test content";
|
|
$p->write();
|
|
$p->doPublish();
|
|
|
|
$vp = new VirtualPage();
|
|
$vp->CopyContentFromID = $p->ID;
|
|
$vp->write();
|
|
|
|
// Delete the source page
|
|
$this->assertTrue($vp->canPublish());
|
|
$this->assertTrue($p->doDeleteFromLive());
|
|
|
|
// Confirm that we can unpublish, but not publish
|
|
$this->assertTrue($vp->canDeleteFromLive());
|
|
$this->assertFalse($vp->canPublish());
|
|
|
|
// Confirm that the action really works
|
|
$this->assertTrue($vp->doDeleteFromLive());
|
|
$this->assertNull(DB::query("SELECT \"ID\" FROM \"SiteTree_Live\" WHERE \"ID\" = $vp->ID")->value());
|
|
}
|
|
|
|
public function testCanEdit() {
|
|
$parentPage = $this->objFromFixture('Page', 'master3');
|
|
$virtualPage = $this->objFromFixture('VirtualPage', 'vp3');
|
|
$bob = $this->objFromFixture('Member', 'bob');
|
|
$andrew = $this->objFromFixture('Member', 'andrew');
|
|
|
|
// Bob can edit the mirrored page, but he shouldn't be able to edit the virtual page.
|
|
$this->logInAs($bob);
|
|
$this->assertTrue($parentPage->canEdit());
|
|
$this->assertFalse($virtualPage->canEdit());
|
|
|
|
// Andrew can only edit the virtual page, but not the original.
|
|
$this->logInAs($andrew);
|
|
$this->assertFalse($parentPage->canEdit());
|
|
$this->assertTrue($virtualPage->canEdit());
|
|
}
|
|
|
|
public function testCanView() {
|
|
$parentPage = $this->objFromFixture('Page', 'master3');
|
|
$parentPage->publish('Stage', 'Live');
|
|
$virtualPage = $this->objFromFixture('VirtualPage', 'vp3');
|
|
$virtualPage->publish('Stage', 'Live');
|
|
$cindy = $this->objFromFixture('Member', 'cindy');
|
|
$alice = $this->objFromFixture('Member', 'alice');
|
|
|
|
// Cindy can see both pages
|
|
$this->logInAs($cindy);
|
|
$this->assertTrue($parentPage->canView());
|
|
$this->assertTrue($virtualPage->canView());
|
|
|
|
// Alice can't see the virtual page, since it's restricted to cindy
|
|
$this->logInAs($alice);
|
|
$this->assertTrue($parentPage->canView());
|
|
$this->assertFalse($virtualPage->canView());
|
|
}
|
|
|
|
public function testVirtualPagesArentInappropriatelyPublished() {
|
|
// Fixture
|
|
$p = new Page();
|
|
$p->Content = "test content";
|
|
$p->write();
|
|
$vp = new VirtualPage();
|
|
$vp->CopyContentFromID = $p->ID;
|
|
$vp->write();
|
|
|
|
// VP is oragne
|
|
$this->assertTrue($vp->getIsAddedToStage());
|
|
|
|
// VP is still orange after we publish
|
|
$p->doPublish();
|
|
$this->fixVersionNumberCache($vp);
|
|
$this->assertTrue($vp->getIsAddedToStage());
|
|
|
|
// A new VP created after P's initial construction
|
|
$vp2 = new VirtualPage();
|
|
$vp2->CopyContentFromID = $p->ID;
|
|
$vp2->write();
|
|
$this->assertTrue($vp2->getIsAddedToStage());
|
|
|
|
// Also remains orange after a republish
|
|
$p->Content = "new content";
|
|
$p->write();
|
|
$p->doPublish();
|
|
$this->fixVersionNumberCache($vp2);
|
|
$this->assertTrue($vp2->getIsAddedToStage());
|
|
|
|
// VP is now published
|
|
$vp->doPublish();
|
|
|
|
$this->fixVersionNumberCache($vp);
|
|
$this->assertTrue($vp->getExistsOnLive());
|
|
$this->assertFalse($vp->getIsModifiedOnStage());
|
|
|
|
// P edited, VP and P both go green
|
|
$p->Content = "third content";
|
|
$p->write();
|
|
|
|
$this->fixVersionNumberCache($vp, $p);
|
|
$this->assertTrue($p->getIsModifiedOnStage());
|
|
$this->assertTrue($vp->getIsModifiedOnStage());
|
|
|
|
// Publish, VP goes black
|
|
$p->doPublish();
|
|
$this->fixVersionNumberCache($vp);
|
|
$this->assertTrue($vp->getExistsOnLive());
|
|
$this->assertFalse($vp->getIsModifiedOnStage());
|
|
}
|
|
|
|
public function testVirtualPagesCreateVersionRecords() {
|
|
$source = $this->objFromFixture('Page', 'master');
|
|
$source->Title = "T0";
|
|
$source->write();
|
|
$source->doPublish();
|
|
|
|
// Creating a new VP to ensure that Version #s are out of alignment
|
|
$vp = new VirtualPage();
|
|
$vp->CopyContentFromID = $source->ID;
|
|
$vp->write();
|
|
|
|
$source->Title = "T1";
|
|
$source->write();
|
|
$source->Title = "T2";
|
|
$source->write();
|
|
|
|
$this->assertEquals($vp->ID, DB::query("SELECT \"RecordID\" FROM \"SiteTree_versions\"
|
|
WHERE \"RecordID\" = $vp->ID AND \"Title\" = 'T1'")->value());
|
|
$this->assertEquals($vp->ID, DB::query("SELECT \"RecordID\" FROM \"SiteTree_versions\"
|
|
WHERE \"RecordID\" = $vp->ID AND \"Title\" = 'T2'")->value());
|
|
$this->assertEquals($vp->ID, DB::query("SELECT \"RecordID\" FROM \"SiteTree_versions\"
|
|
WHERE \"RecordID\" = $vp->ID AND \"Version\" = $vp->Version")->value());
|
|
|
|
$vp->doPublish();
|
|
|
|
// Check that the published content is copied from the published page, with a legal
|
|
// version
|
|
$liveVersion = DB::query("SELECT \"Version\" FROM \"SiteTree_Live\" WHERE \"ID\" = $vp->ID")->value();
|
|
|
|
$this->assertEquals("T0", DB::query("SELECT \"Title\" FROM \"SiteTree_Live\"
|
|
WHERE \"ID\" = $vp->ID")->value());
|
|
|
|
// SiteTree_Live.Version should reference a legal entry in SiteTree_versions for the
|
|
// virtual page
|
|
$this->assertEquals("T0", DB::query("SELECT \"Title\" FROM \"SiteTree_versions\"
|
|
WHERE \"RecordID\" = $vp->ID AND \"Version\" = $liveVersion")->value());
|
|
}
|
|
|
|
public function fixVersionNumberCache($page) {
|
|
$pages = func_get_args();
|
|
foreach($pages as $p) {
|
|
Versioned::prepopulate_versionnumber_cache('SiteTree', 'Stage', array($p->ID));
|
|
Versioned::prepopulate_versionnumber_cache('SiteTree', 'Live', array($p->ID));
|
|
}
|
|
}
|
|
|
|
public function testUnpublishingSourcePageOfAVirtualPageAlsoUnpublishesVirtualPage() {
|
|
// Create page and virutal page
|
|
$p = new Page();
|
|
$p->Title = "source";
|
|
$p->write();
|
|
$this->assertTrue($p->doPublish());
|
|
$vp = new VirtualPage();
|
|
$vp->CopyContentFromID = $p->ID;
|
|
$vp->write();
|
|
$this->assertTrue($vp->doPublish());
|
|
|
|
// All is fine, the virtual page doesn't have a broken link
|
|
$this->assertFalse($vp->HasBrokenLink);
|
|
|
|
// Unpublish the source page, confirm that the virtual page has also been unpublished
|
|
$p->doUnpublish();
|
|
|
|
// The draft VP still has the CopyContentFromID link
|
|
$vp->flushCache();
|
|
$vp = DataObject::get_by_id('SiteTree', $vp->ID);
|
|
$this->assertEquals($p->ID, $vp->CopyContentFromID);
|
|
|
|
$vpLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $vp->ID);
|
|
$this->assertNull($vpLive);
|
|
|
|
// Delete from draft, confirm that the virtual page has a broken link on the draft site
|
|
$p->delete();
|
|
$vp->flushCache();
|
|
$vp = DataObject::get_by_id('SiteTree', $vp->ID);
|
|
$this->assertEquals(1, $vp->HasBrokenLink);
|
|
}
|
|
|
|
public function testDeletingFromLiveSourcePageOfAVirtualPageAlsoUnpublishesVirtualPage() {
|
|
// Create page and virutal page
|
|
$p = new Page();
|
|
$p->Title = "source";
|
|
$p->write();
|
|
$this->assertTrue($p->doPublish());
|
|
$vp = new VirtualPage();
|
|
$vp->CopyContentFromID = $p->ID;
|
|
$vp->write();
|
|
$this->assertTrue($vp->doPublish());
|
|
|
|
// All is fine, the virtual page doesn't have a broken link
|
|
$this->assertFalse($vp->HasBrokenLink);
|
|
|
|
// Delete the source page from draft, confirm that this creates a broken link
|
|
$pID = $p->ID;
|
|
$p->delete();
|
|
$vp->flushCache();
|
|
$vp = DataObject::get_by_id('SiteTree', $vp->ID);
|
|
$this->assertEquals(1, $vp->HasBrokenLink);
|
|
|
|
// Delete the source page form live, confirm that the virtual page has also been unpublished
|
|
$pLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $pID);
|
|
$this->assertTrue($pLive->doDeleteFromLive());
|
|
$vpLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $vp->ID);
|
|
$this->assertNull($vpLive);
|
|
|
|
// Delete from draft, confirm that the virtual page has a broken link on the draft site
|
|
$pLive->delete();
|
|
$vp->flushCache();
|
|
$vp = DataObject::get_by_id('SiteTree', $vp->ID);
|
|
$this->assertEquals(1, $vp->HasBrokenLink);
|
|
}
|
|
|
|
/**
|
|
* Base functionality tested in {@link SiteTreeTest->testAllowedChildrenValidation()}.
|
|
*/
|
|
public function testAllowedChildrenLimitedOnVirtualPages() {
|
|
$classA = new SiteTreeTest_ClassA();
|
|
$classA->write();
|
|
$classB = new SiteTreeTest_ClassB();
|
|
$classB->write();
|
|
$classBVirtual = new VirtualPage();
|
|
$classBVirtual->CopyContentFromID = $classB->ID;
|
|
$classBVirtual->write();
|
|
$classC = new SiteTreeTest_ClassC();
|
|
$classC->write();
|
|
$classCVirtual = new VirtualPage();
|
|
$classCVirtual->CopyContentFromID = $classC->ID;
|
|
$classCVirtual->write();
|
|
|
|
$classBVirtual->ParentID = $classA->ID;
|
|
$valid = $classBVirtual->doValidate();
|
|
$this->assertTrue($valid->valid(), "Does allow child linked to virtual page type allowed by parent");
|
|
|
|
$classCVirtual->ParentID = $classA->ID;
|
|
$valid = $classCVirtual->doValidate();
|
|
$this->assertFalse($valid->valid(), "Doesn't allow child linked to virtual page type disallowed by parent");
|
|
}
|
|
|
|
public function testGetVirtualFields() {
|
|
// Needs association with an original, otherwise will just return the "base" virtual fields
|
|
$page = new VirtualPageTest_ClassA();
|
|
$page->write();
|
|
$virtual = new VirtualPage();
|
|
$virtual->CopyContentFromID = $page->ID;
|
|
$virtual->write();
|
|
|
|
$this->assertContains('MyVirtualField', $virtual->getVirtualFields());
|
|
$this->assertNotContains('MyNonVirtualField', $virtual->getVirtualFields());
|
|
$this->assertNotContains('MyInitiallyCopiedField', $virtual->getVirtualFields());
|
|
}
|
|
|
|
public function testCopyFrom() {
|
|
$original = new VirtualPageTest_ClassA();
|
|
$original->MyInitiallyCopiedField = 'original';
|
|
$original->MyVirtualField = 'original';
|
|
$original->MyNonVirtualField = 'original';
|
|
$original->write();
|
|
|
|
$virtual = new VirtualPage();
|
|
$virtual->CopyContentFromID = $original->ID;
|
|
$virtual->write();
|
|
|
|
$virtual->copyFrom($original);
|
|
// Using getField() to avoid side effects from an overloaded __get()
|
|
$this->assertEquals(
|
|
'original',
|
|
$virtual->getField('MyInitiallyCopiedField'),
|
|
'Fields listed in $initially_copied_fields are copied on first copyFrom() invocation'
|
|
);
|
|
$this->assertEquals(
|
|
'original',
|
|
$virtual->getField('MyVirtualField'),
|
|
'Fields not listed in $initially_copied_fields are copied in copyFrom()'
|
|
);
|
|
$this->assertNull(
|
|
$virtual->getField('MyNonVirtualField'),
|
|
'Fields listed in $non_virtual_fields are not copied in copyFrom()'
|
|
);
|
|
|
|
$original->MyInitiallyCopiedField = 'changed';
|
|
$original->write();
|
|
$virtual->copyFrom($original);
|
|
$this->assertEquals(
|
|
'original',
|
|
$virtual->MyInitiallyCopiedField,
|
|
'Fields listed in $initially_copied_fields are not copied on subsequent copyFrom() invocations'
|
|
);
|
|
}
|
|
|
|
public function testWriteWithoutVersion() {
|
|
$original = new SiteTree();
|
|
$original->write();
|
|
// Create a second version (different behaviour),
|
|
// as SiteTree->onAfterWrite() checks for Version == 1
|
|
$original->Title = 'prepare';
|
|
$original->write();
|
|
$originalVersion = $original->Version;
|
|
|
|
$virtual = new VirtualPage();
|
|
$virtual->CopyContentFromID = $original->ID;
|
|
$virtual->write();
|
|
// Create a second version, see above.
|
|
$virtual->Title = 'prepare';
|
|
$virtual->write();
|
|
$virtualVersion = $virtual->Version;
|
|
|
|
$virtual->Title = 'changed 1';
|
|
$virtual->writeWithoutVersion();
|
|
$this->assertEquals(
|
|
$virtual->Version,
|
|
$virtualVersion,
|
|
'writeWithoutVersion() on VirtualPage doesnt increment version'
|
|
);
|
|
|
|
$original->Title = 'changed 2';
|
|
$original->writeWithoutVersion();
|
|
|
|
DataObject::flush_and_destroy_cache();
|
|
$virtual = DataObject::get_by_id('VirtualPage', $virtual->ID, false);
|
|
$this->assertEquals(
|
|
$virtual->Version,
|
|
$virtualVersion,
|
|
'writeWithoutVersion() on original page doesnt increment version on related VirtualPage'
|
|
);
|
|
|
|
$original->Title = 'changed 3';
|
|
$original->write();
|
|
DataObject::flush_and_destroy_cache();
|
|
$virtual = DataObject::get_by_id('VirtualPage', $virtual->ID, false);
|
|
$this->assertGreaterThan(
|
|
$virtualVersion,
|
|
$virtual->Version,
|
|
'write() on original page does increment version on related VirtualPage'
|
|
);
|
|
}
|
|
|
|
public function testCanBeRoot() {
|
|
$page = new SiteTree();
|
|
$page->ParentID = 0;
|
|
$page->write();
|
|
|
|
$notRootPage = new VirtualPageTest_NotRoot();
|
|
// we don't want the original on root, but rather the VirtualPage pointing to it
|
|
$notRootPage->ParentID = $page->ID;
|
|
$notRootPage->write();
|
|
|
|
$virtual = new VirtualPage();
|
|
$virtual->CopyContentFromID = $page->ID;
|
|
$virtual->write();
|
|
|
|
$virtual = DataObject::get_by_id('VirtualPage', $virtual->ID, false);
|
|
$virtual->CopyContentFromID = $notRootPage->ID;
|
|
$virtual->flushCache();
|
|
|
|
$isDetected = false;
|
|
try {
|
|
$virtual->write();
|
|
} catch(ValidationException $e) {
|
|
$this->assertContains('is not allowed on the root level', $e->getMessage());
|
|
$isDetected = true;
|
|
}
|
|
|
|
if(!$isDetected) $this->fail('Fails validation with $can_be_root=false');
|
|
}
|
|
|
|
public function testPageTypeChangeDoesntKeepOrphanedVirtualPageRecord() {
|
|
$page = new SiteTree();
|
|
$page->write();
|
|
$page->publish('Stage', 'Live');
|
|
|
|
$virtual = new VirtualPageTest_VirtualPageSub();
|
|
$virtual->CopyContentFromID = $page->ID;
|
|
$virtual->write();
|
|
$virtual->publish('Stage', 'Live');
|
|
|
|
$nonVirtual = $virtual;
|
|
$nonVirtual->ClassName = 'VirtualPageTest_ClassA';
|
|
$nonVirtual->write(); // not publishing
|
|
|
|
$this->assertNotNull(
|
|
DB::query(sprintf('SELECT "ID" FROM "SiteTree" WHERE "ID" = %d', $nonVirtual->ID))->value(),
|
|
"Shared base database table entry exists after type change"
|
|
);
|
|
$this->assertNull(
|
|
DB::query(sprintf('SELECT "ID" FROM "VirtualPage" WHERE "ID" = %d', $nonVirtual->ID))->value(),
|
|
"Base database table entry no longer exists after type change"
|
|
);
|
|
$this->assertNull(
|
|
DB::query(sprintf('SELECT "ID" FROM "VirtualPageTest_VirtualPageSub" WHERE "ID" = %d', $nonVirtual->ID))->value(),
|
|
"Sub database table entry no longer exists after type change"
|
|
);
|
|
$this->assertNull(
|
|
DB::query(sprintf('SELECT "ID" FROM "VirtualPage_Live" WHERE "ID" = %d', $nonVirtual->ID))->value(),
|
|
"Base live database table entry no longer exists after type change"
|
|
);
|
|
$this->assertNull(
|
|
DB::query(sprintf('SELECT "ID" FROM "VirtualPageTest_VirtualPageSub_Live" WHERE "ID" = %d', $nonVirtual->ID))->value(),
|
|
"Sub live database table entry no longer exists after type change"
|
|
);
|
|
}
|
|
|
|
public function testPageTypeChangePropagatesToLive() {
|
|
$page = new SiteTree();
|
|
$page->MySharedNonVirtualField = 'original';
|
|
$page->write();
|
|
$page->publish('Stage', 'Live');
|
|
|
|
$virtual = new VirtualPageTest_VirtualPageSub();
|
|
$virtual->CopyContentFromID = $page->ID;
|
|
$virtual->write();
|
|
$virtual->publish('Stage', 'Live');
|
|
|
|
$page->Title = 'original'; // 'Title' is a virtual field
|
|
// Publication would causes the virtual field to copy through onBeforeWrite(),
|
|
// but we want to test that it gets copied on class name change instead
|
|
$page->write();
|
|
|
|
$nonVirtual = $virtual;
|
|
$nonVirtual->ClassName = 'VirtualPageTest_ClassA';
|
|
$nonVirtual->MySharedNonVirtualField = 'changed on new type';
|
|
$nonVirtual->write(); // not publishing the page type change here
|
|
|
|
$this->assertEquals('original', $nonVirtual->Title,
|
|
'Copies virtual fields from original draft into new instance on type change '
|
|
);
|
|
|
|
$nonVirtualLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree_Live"."ID" = ' . $nonVirtual->ID);
|
|
$this->assertNotNull($nonVirtualLive);
|
|
$this->assertEquals('VirtualPageTest_ClassA', $nonVirtualLive->ClassName);
|
|
$this->assertEquals('changed on new type', $nonVirtualLive->MySharedNonVirtualField);
|
|
|
|
$page->MySharedNonVirtualField = 'changed only on original';
|
|
$page->write();
|
|
$page->publish('Stage', 'Live');
|
|
|
|
$nonVirtualLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree_Live"."ID" = ' . $nonVirtual->ID, false);
|
|
$this->assertEquals('changed on new type', $nonVirtualLive->MySharedNonVirtualField,
|
|
'No field copying from previous original after page type changed'
|
|
);
|
|
}
|
|
|
|
public function testVirtualPageFindsCorrectCasting() {
|
|
$page = new VirtualPageTest_ClassA();
|
|
$page->CastingTest = "Some content";
|
|
$page->write();
|
|
$virtual = new VirtualPage();
|
|
$virtual->CopyContentFromID = $page->ID;
|
|
$virtual->write();
|
|
|
|
$this->assertEquals('VirtualPageTest_TestDBField', $virtual->castingHelper('CastingTest'));
|
|
$this->assertEquals('SOME CONTENT', $virtual->obj('CastingTest')->forTemplate());
|
|
}
|
|
|
|
public function testVirtualPageAsAnAllowedChild() {
|
|
$parentPage = new VirtualPageTest_PageWithAllowedChildren();
|
|
$parentPage->write();
|
|
|
|
$childPage = new VirtualPageTest_ClassA();
|
|
$childPage->ParentID = $parentPage->ID;
|
|
$childPage->write();
|
|
|
|
// Check we're allowed to create a VirtualPage without linking it to a page yet
|
|
$childVirtualPage = new VirtualPage();
|
|
$childVirtualPage->ParentID = $parentPage->ID;
|
|
try {
|
|
$childVirtualPage->write();
|
|
} catch(ValidationException $e) {
|
|
$this->fail('Failed to write VirtualPage when it is an allowed child');
|
|
}
|
|
|
|
// Check that we can link a VirtualPage to a page type that's an allowed child
|
|
$childVirtualPage->CopyContentFromID = $childPage->ID;
|
|
try {
|
|
$childVirtualPage->write();
|
|
} catch(ValidationException $e) {
|
|
$this->fail('Failed to write VirtualPage when it is linked to an allowed child');
|
|
}
|
|
|
|
// Check that we CAN'T link a VirtualPage to a page that is NOT an allowed child
|
|
$disallowedChild = new VirtualPageTest_ClassB();
|
|
$disallowedChild->write();
|
|
$childVirtualPage->CopyContentFromID = $disallowedChild->ID;
|
|
$isDetected = false;
|
|
try {
|
|
$childVirtualPage->write();
|
|
} catch(ValidationException $e) {
|
|
$this->assertContains('not allowed as child of this parent page', $e->getMessage());
|
|
$isDetected = true;
|
|
}
|
|
|
|
if(!$isDetected) $this->fail("Shouldn't be allowed to write a VirtualPage that links to a disallowed child");
|
|
}
|
|
|
|
public function testVirtualPagePointingToRedirectorPage() {
|
|
if (!class_exists('RedirectorPage')) {
|
|
$this->markTestSkipped('RedirectorPage required');
|
|
}
|
|
|
|
$rp = new RedirectorPage(array('ExternalURL' => 'http://google.com', 'RedirectionType' => 'External'));
|
|
$rp->write();
|
|
$rp->doPublish();
|
|
|
|
$vp = new VirtualPage(array('URLSegment' => 'vptest', 'CopyContentFromID' => $rp->ID));
|
|
$vp->write();
|
|
$vp->doPublish();
|
|
|
|
$response = $this->get($vp->Link());
|
|
$this->assertEquals(301, $response->getStatusCode());
|
|
$this->assertEquals('http://google.com', $response->getHeader('Location'));
|
|
}
|
|
}
|
|
|
|
class VirtualPageTest_ClassA extends Page implements TestOnly {
|
|
|
|
private static $db = array(
|
|
'MyInitiallyCopiedField' => 'Text',
|
|
'MyVirtualField' => 'Text',
|
|
'MyNonVirtualField' => 'Text',
|
|
'CastingTest' => 'VirtualPageTest_TestDBField'
|
|
);
|
|
|
|
private static $allowed_children = array('VirtualPageTest_ClassB');
|
|
}
|
|
|
|
class VirtualPageTest_ClassB extends Page implements TestOnly {
|
|
private static $allowed_children = array('VirtualPageTest_ClassC');
|
|
}
|
|
|
|
class VirtualPageTest_ClassC extends Page implements TestOnly {
|
|
private static $allowed_children = array();
|
|
}
|
|
|
|
class VirtualPageTest_NotRoot extends Page implements TestOnly {
|
|
private static $can_be_root = false;
|
|
}
|
|
|
|
class VirtualPageTest_TestDBField extends Varchar implements TestOnly {
|
|
public function forTemplate() {
|
|
return strtoupper($this->XML());
|
|
}
|
|
}
|
|
|
|
class VirtualPageTest_VirtualPageSub extends VirtualPage implements TestOnly {
|
|
private static $db = array(
|
|
'MyProperty' => 'Varchar',
|
|
);
|
|
}
|
|
|
|
class VirtualPageTest_PageExtension extends DataExtension implements TestOnly {
|
|
|
|
private static $db = array(
|
|
// These fields are just on an extension to simulate shared properties between Page and VirtualPage.
|
|
// Not possible through direct $db definitions due to VirtualPage inheriting from Page, and Page being defined elsewhere.
|
|
'MySharedVirtualField' => 'Text',
|
|
'MySharedNonVirtualField' => 'Text',
|
|
);
|
|
|
|
}
|
|
|
|
class VirtualPageTest_PageWithAllowedChildren extends Page implements TestOnly {
|
|
private static $allowed_children = array(
|
|
'VirtualPageTest_ClassA',
|
|
'VirtualPage'
|
|
);
|
|
}
|