[ FluentSiteTreeExtension::class, ], ]; protected function setUp(): void { // We have our own home page fixtures, prevent the default one being created in this test suite. Config::modify()->set(SiteTree::class, 'create_default_pages', false); parent::setUp(); } public function testPagesInDifferentSubsitesCanShareURLSegment() { $subsiteMain = $this->objFromFixture(Subsite::class, 'main'); $subsite1 = $this->objFromFixture(Subsite::class, 'subsite1'); $pageMain = new SiteTree(); $pageMain->URLSegment = 'testpage'; $pageMain->write(); $pageMain->copyVersionToStage('Stage', 'Live'); $pageMainOther = new SiteTree(); $pageMainOther->URLSegment = 'testpage'; $pageMainOther->write(); $pageMainOther->copyVersionToStage('Stage', 'Live'); $this->assertNotEquals( $pageMain->URLSegment, $pageMainOther->URLSegment, 'Pages in same subsite cant share the same URL' ); Subsite::changeSubsite($subsite1->ID); $pageSubsite1 = new SiteTree(); $pageSubsite1->URLSegment = 'testpage'; $pageSubsite1->write(); $pageSubsite1->copyVersionToStage('Stage', 'Live'); $this->assertEquals( $pageMain->URLSegment, $pageSubsite1->URLSegment, 'Pages in different subsites can share the same URL' ); } public function testBasicSanity() { $this->assertInstanceOf(SiteConfig::class, singleton(SiteTree::class)->getSiteConfig()); // The following assert is breaking in Translatable. $this->assertInstanceOf(FieldList::class, singleton(SiteTree::class)->getCMSFields()); $this->assertInstanceOf(FieldList::class, singleton(SubsitesVirtualPage::class)->getCMSFields()); $this->assertTrue(is_array(singleton(SiteTreeSubsites::class)->extraStatics())); } public function errorPageLocationsProvider() { return [ ['domaintest1', '/error-500-one.example.org.html'], ['domaintestVagrant', '/error-500-localhost8080.html'] ]; } /** * @dataProvider errorPageLocationsProvider */ public function testErrorPageLocations($subsiteFixtureName, $expectedFilename) { $static_path = Config::inst()->get(ErrorPage::class, 'static_filepath'); $subsite = $this->objFromFixture(Subsite::class, $subsiteFixtureName); $expected_path = $static_path . $expectedFilename; Subsite::changeSubsite($subsite->ID); $path = TestErrorPage::get_error_filename_spy(500); $this->assertEquals($expected_path, $path); } public function testCanEditSiteTree() { $admin = $this->objFromFixture(Member::class, 'admin'); $subsite1member = $this->objFromFixture(Member::class, 'subsite1member'); $subsite2member = $this->objFromFixture(Member::class, 'subsite2member'); $mainpage = $this->objFromFixture('Page', 'home'); $subsite1page = $this->objFromFixture('Page', 'subsite1_home'); $subsite2page = $this->objFromFixture('Page', 'subsite2_home'); $subsite1 = $this->objFromFixture(Subsite::class, 'subsite1'); $subsite2 = $this->objFromFixture(Subsite::class, 'subsite2'); // Cant pass member as arguments to canEdit() because of GroupSubsites $this->logInAs($admin); $this->assertTrue( (bool)$subsite1page->canEdit(), 'Administrators can edit all subsites' ); Subsite::changeSubsite($subsite1); $this->logInAs($subsite1member->ID); $this->assertTrue( (bool)$subsite1page->canEdit(), 'Members can edit pages on a subsite if they are in a group belonging to this subsite' ); $this->logInAs($subsite2member->ID); $this->assertFalse( (bool)$subsite1page->canEdit(), 'Members cant edit pages on a subsite if they are not in a group belonging to this subsite' ); Subsite::changeSubsite(0); $this->assertFalse( $mainpage->canEdit(), 'Members cant edit pages on the main site if they are not in a group allowing this' ); } /** * Similar to {@link SubsitesVirtualPageTest->testSubsiteVirtualPageCanHaveSameUrlsegmentAsOtherSubsite()}. */ public function testTwoPagesWithSameURLOnDifferentSubsites() { // Set up a couple of pages with the same URL on different subsites $s1 = $this->objFromFixture(Subsite::class, 'domaintest1'); $s2 = $this->objFromFixture(Subsite::class, 'domaintest2'); $p1 = new SiteTree(); $p1->Title = $p1->URLSegment = 'test-page'; $p1->SubsiteID = $s1->ID; $p1->write(); $p2 = new SiteTree(); $p2->Title = $p1->URLSegment = 'test-page'; $p2->SubsiteID = $s2->ID; $p2->write(); // Check that the URLs weren't modified in our set-up $this->assertEquals('test-page', $p1->URLSegment); $this->assertEquals('test-page', $p2->URLSegment); // Check that if we switch between the different subsites, we receive the correct pages Subsite::changeSubsite($s1); $this->assertEquals($p1->ID, SiteTree::get_by_link('test-page')->ID); Subsite::changeSubsite($s2); $this->assertEquals($p2->ID, SiteTree::get_by_link('test-page')->ID); } public function testIgnoreSubsiteLocale() { $ignore_subsite_locale = Config::inst()->set(SiteTreeSubsites::class, 'ignore_subsite_locale', true); $subsitePage = $this->objFromFixture(Page::class, 'subsite_locale_about'); Subsite::changeSubsite($subsitePage->SubsiteID); $controller = ModelAsController::controller_for($subsitePage); $i18n_locale_before = i18n::get_locale(); SiteTree::singleton()->extend('contentcontrollerInit', $controller); $i18n_locale_after = i18n::get_locale(); $this->assertEquals($i18n_locale_before, $i18n_locale_after); } public function testPageTypesBlacklistInClassDropdown() { $this->logInAs('editor'); $s1 = $this->objFromFixture(Subsite::class, 'domaintest1'); $s2 = $this->objFromFixture(Subsite::class, 'domaintest2'); $page = singleton(SiteTree::class); $s1->PageTypeBlacklist = json_encode([TestClassA::class, ErrorPage::class]); $s1->write(); Subsite::changeSubsite($s1); $settingsFields = $page->getSettingsFields()->dataFieldByName('ClassName')->getSource(); $this->assertArrayNotHasKey( ErrorPage::class, $settingsFields ); $this->assertArrayNotHasKey( TestClassA::class, $settingsFields ); $this->assertArrayHasKey( TestClassB::class, $settingsFields ); Subsite::changeSubsite($s2); $settingsFields = $page->getSettingsFields()->dataFieldByName('ClassName')->getSource(); $this->assertArrayHasKey( ErrorPage::class, $settingsFields ); $this->assertArrayHasKey( TestClassA::class, $settingsFields ); $this->assertArrayHasKey( TestClassB::class, $settingsFields ); } public function testCopyToSubsite() { // Remove baseurl if testing in subdir Config::modify()->set(Director::class, 'alternate_base_url', '/'); /** @var Subsite $otherSubsite */ $otherSubsite = $this->objFromFixture(Subsite::class, 'subsite1'); $staffPage = $this->objFromFixture(Page::class, 'staff'); // nested page $contactPage = $this->objFromFixture(Page::class, 'contact'); // top level page $staffPage2 = $staffPage->duplicateToSubsite($otherSubsite->ID); $contactPage2 = $contactPage->duplicateToSubsite($otherSubsite->ID); $this->assertNotEquals($staffPage->ID, $staffPage2->ID); $this->assertNotEquals($staffPage->SubsiteID, $staffPage2->SubsiteID); $this->assertNotEquals($contactPage->ID, $contactPage2->ID); $this->assertNotEquals($contactPage->SubsiteID, $contactPage2->SubsiteID); $this->assertEmpty($staffPage2->ParentID); $this->assertEmpty($contactPage2->ParentID); $this->assertNotEmpty($staffPage->ParentID); $this->assertEmpty($contactPage->ParentID); // Staff is shifted to top level and given a unique url segment $domain = $otherSubsite->domain(); $this->assertEquals('http://' . $domain . '/staff-2', $staffPage2->AbsoluteLink()); $this->assertEquals('http://' . $domain . '/contact-us-2', $contactPage2->AbsoluteLink()); } public function testPageTypesBlacklistInCMSMain() { $this->logInAs('editor'); $s1 = $this->objFromFixture(Subsite::class, 'domaintest1'); $s2 = $this->objFromFixture(Subsite::class, 'domaintest2'); $s1->PageTypeBlacklist = json_encode([TestClassA::class, ErrorPage::class]); $s1->write(); Subsite::changeSubsite($s1); $cmsmain = CMSMain::create(); $hints = json_decode($cmsmain->SiteTreeHints() ?? '', true); $classes = $hints['Root']['disallowedChildren']; $this->assertContains(ErrorPage::class, $classes); $this->assertContains(TestClassA::class, $classes); $this->assertNotContains(TestClassB::class, $classes); Subsite::changeSubsite($s2); // SS 4.1 and above if ($cmsmain->hasMethod('getHintsCache')) { $cmsmain->getHintsCache()->clear(); } $hints = json_decode($cmsmain->SiteTreeHints() ?? '', true); $classes = $hints['Root']['disallowedChildren']; $this->assertNotContains(ErrorPage::class, $classes); $this->assertNotContains(TestClassA::class, $classes); $this->assertNotContains(TestClassB::class, $classes); } /** * Tests that url segments between subsites don't conflict, but do conflict within them */ public function testValidateURLSegment() { $this->logInWithPermission('ADMIN'); // Saving existing page in the same subsite doesn't change urls $mainHome = $this->objFromFixture(Page::class, 'home'); $mainSubsiteID = $this->idFromFixture(Subsite::class, 'main'); Subsite::changeSubsite($mainSubsiteID); $mainHome->Content = '
Some new content
'; $mainHome->write(); $this->assertEquals('home', $mainHome->URLSegment); $mainHome->publishRecursive(); $mainHomeLive = Versioned::get_one_by_stage('Page', 'Live', sprintf('"SiteTree"."ID" = \'%d\'', $mainHome->ID)); $this->assertEquals('home', $mainHomeLive->URLSegment); // Saving existing page in another subsite doesn't change urls Subsite::changeSubsite($mainSubsiteID); $subsite1Home = $this->objFromFixture('Page', 'subsite1_home'); $subsite1Home->Content = 'In subsite 1
'; $subsite1Home->write(); $this->assertEquals('home', $subsite1Home->URLSegment); $subsite1Home->publishRecursive(); $subsite1HomeLive = Versioned::get_one_by_stage( 'Page', 'Live', sprintf('"SiteTree"."ID" = \'%d\'', $subsite1Home->ID) ); $this->assertEquals('home', $subsite1HomeLive->URLSegment); // Creating a new page in a subsite doesn't conflict with urls in other subsites $subsite1ID = $this->idFromFixture(Subsite::class, 'subsite1'); Subsite::changeSubsite($subsite1ID); $subsite1NewPage = new Page(); $subsite1NewPage->SubsiteID = $subsite1ID; $subsite1NewPage->Title = 'Important Page (Subsite 1)'; $subsite1NewPage->URLSegment = 'important-page'; // Also exists in main subsite $subsite1NewPage->write(); $this->assertEquals('important-page', $subsite1NewPage->URLSegment); $subsite1NewPage->publishRecursive(); $subsite1NewPageLive = Versioned::get_one_by_stage( 'Page', 'Live', sprintf('"SiteTree"."ID" = \'%d\'', $subsite1NewPage->ID) ); $this->assertEquals('important-page', $subsite1NewPageLive->URLSegment); // Creating a new page in a subsite DOES conflict with urls in the same subsite $subsite1NewPage2 = new Page(); $subsite1NewPage2->SubsiteID = $subsite1ID; $subsite1NewPage2->Title = 'Important Page (Subsite 1)'; $subsite1NewPage2->URLSegment = 'important-page'; // Also exists in main subsite $subsite1NewPage2->write(); $this->assertEquals('important-page-2', $subsite1NewPage2->URLSegment); $subsite1NewPage2->publishRecursive(); $subsite1NewPage2Live = Versioned::get_one_by_stage( 'Page', 'Live', sprintf('"SiteTree"."ID" = \'%d\'', $subsite1NewPage2->ID) ); $this->assertEquals('important-page-2', $subsite1NewPage2Live->URLSegment); // Original page is left un-modified $mainSubsiteImportantPageID = $this->idFromFixture('Page', 'importantpage'); $mainSubsiteImportantPage = Page::get()->byID($mainSubsiteImportantPageID); $this->assertEquals('important-page', $mainSubsiteImportantPage->URLSegment); $mainSubsiteImportantPage->Content = 'New Important Page Content
'; $mainSubsiteImportantPage->write(); $this->assertEquals('important-page', $mainSubsiteImportantPage->URLSegment); } /** * @param bool $withChildren * @param int $expectedChildren * @dataProvider duplicateToSubsiteProvider */ public function testDuplicateToSubsite($withChildren, $expectedChildren) { /** @var SiteTree $page */ $page = $this->objFromFixture(Page::class, 'about'); /** @var Subsite $newSubsite */ $newSubsite = $this->objFromFixture(Subsite::class, 'subsite1'); /** @var SiteTree $duplicatedPage */ $duplicatedPage = $page->duplicateToSubsite($newSubsite->ID, $withChildren); $this->assertInstanceOf(SiteTree::class, $duplicatedPage, 'A new page is returned'); $this->assertEquals($newSubsite->ID, $duplicatedPage->SubsiteID, 'Ensure returned records are on new subsite'); $this->assertCount(1, $page->AllChildren()); $this->assertCount( $expectedChildren, $duplicatedPage->AllChildren(), 'Duplicated page also duplicates children' ); } /** * @return array[] */ public function duplicateToSubsiteProvider() { return [ [true, 1], [false, 0], ]; } public function testThemeResolverIsUsedForSettingThemeList() { $firstResolver = $this->createMock(ThemeResolver::class); $firstResolver->expects($this->never())->method('getThemeList'); Injector::inst()->registerService($firstResolver, ThemeResolver::class); $subsitePage = $this->objFromFixture(Page::class, 'home'); Subsite::changeSubsite($subsitePage->SubsiteID); $controller = ModelAsController::controller_for($subsitePage); SiteTree::singleton()->extend('contentcontrollerInit', $controller); $secondResolver = $this->createMock(ThemeResolver::class); $secondResolver->expects($this->once())->method('getThemeList'); Injector::inst()->registerService($secondResolver, ThemeResolver::class); $subsitePage = $this->objFromFixture(Page::class, 'subsite1_home'); Subsite::changeSubsite($subsitePage->SubsiteID); $controller = ModelAsController::controller_for($subsitePage); SiteTree::singleton()->extend('contentcontrollerInit', $controller); } public function provideAlternateAbsoluteLink() { return [ ['home', null, 'http://localhost'], ['home', 'myaction', 'http://localhost/home/myaction'], ['contact', null, 'http://localhost/contact-us'], ['contact', 'myaction', 'http://localhost/contact-us/myaction'], ['subsite1_home', null, 'http://subsite1.localhost'], ['subsite1_home', 'myaction', 'http://subsite1.localhost/home/myaction'], ['subsite1_contactus', null, 'http://subsite1.localhost/contact-us'], ['subsite1_contactus', 'myaction', 'http://subsite1.localhost/contact-us/myaction'] ]; } /** * @dataProvider provideAlternateAbsoluteLink * @param string $pageFixtureName * @param string|null $action * @param string $expectedAbsoluteLink */ public function testAlternateAbsoluteLink($pageFixtureName, $action, $expectedAbsoluteLink) { // Setting a control value, in case base url is set for the installation under test Config::modify()->set(Director::class, 'alternate_base_url', 'http://localhost'); /** @var Page $page */ $page = $this->objFromFixture(Page::class, $pageFixtureName); $result = $page->AbsoluteLink($action); $this->assertEquals($expectedAbsoluteLink, $result); } public function testURLSegmentBaseIsSetToSubsiteBaseURL() { // This subsite has a domain with 'one.example.org' as the primary domain /** @var Subsite $subsite */ $subsite = $this->objFromFixture(Subsite::class, 'domaintest1'); Subsite::changeSubsite($subsite); $page = new SiteTree(); $page->SubsiteID = $subsite->ID; $page->write(); $fields = $page->getCMSFields(); /** @var SiteTreeURLSegmentField $urlSegmentField */ $urlSegmentField = $fields->dataFieldByName('URLSegment'); $this->assertInstanceOf(SiteTreeURLSegmentField::class, $urlSegmentField); $this->assertSame('http://one.example.org/', $urlSegmentField->getURLPrefix()); } }