Merge pull request #247 from tractorcow/pulls/1.2/fix-subsites-urlsegment

BUG Fix issue with urlsegment being renamed in subsites
This commit is contained in:
Daniel Hensby 2016-05-23 10:06:34 +01:00
commit 9e7142d229
8 changed files with 302 additions and 233 deletions

View File

@ -9,18 +9,18 @@ class SubsitesVirtualPage extends VirtualPage
'CustomMetaDescription' => 'Text',
'CustomExtraMeta' => 'HTMLText'
);
public function getCMSFields()
{
$fields = parent::getCMSFields();
$subsites = DataObject::get('Subsite');
if (!$subsites) {
$subsites = new ArrayList();
} else {
$subsites=ArrayList::create($subsites->toArray());
}
$subsites->push(new ArrayData(array('Title' => 'Main site', 'ID' => 0)));
$fields->addFieldToTab(
@ -32,7 +32,7 @@ class SubsitesVirtualPage extends VirtualPage
)->addExtraClass('subsitestreedropdownfield-chooser no-change-track'),
'CopyContentFromID'
);
// Setup the linking to the original page.
$pageSelectionField = new SubsitesTreeDropdownField(
"CopyContentFromID",
@ -41,13 +41,13 @@ class SubsitesVirtualPage extends VirtualPage
"ID",
"MenuTitle"
);
if (Controller::has_curr() && Controller::curr()->getRequest()) {
$subsiteID = Controller::curr()->getRequest()->requestVar('CopyContentFromID_SubsiteID');
$pageSelectionField->setSubsiteID($subsiteID);
}
$fields->replaceField('CopyContentFromID', $pageSelectionField);
// Create links back to the original object in the CMS
if ($this->CopyContentFromID) {
$editLink = "admin/pages/edit/show/$this->CopyContentFromID/?SubsiteID=" . $this->CopyContentFrom()->SubsiteID;
@ -63,8 +63,8 @@ class SubsitesVirtualPage extends VirtualPage
);
$linkToContentLabelField->setAllowHTML(true);
}
$fields->addFieldToTab(
'Root.Main',
TextField::create(
@ -97,7 +97,7 @@ class SubsitesVirtualPage extends VirtualPage
)->setDescription(_t('SubsitesVirtualPage.OverrideNote')),
'ExtraMeta'
);
return $fields;
}
@ -116,7 +116,7 @@ class SubsitesVirtualPage extends VirtualPage
{
return ($this->CopyContentFromID) ? (int)$this->CopyContentFrom()->SubsiteID : (int)Session::get('SubsiteID');
}
public function getVirtualFields()
{
$fields = parent::getVirtualFields();
@ -125,7 +125,7 @@ class SubsitesVirtualPage extends VirtualPage
unset($fields[$k]);
}
}
foreach (self::$db as $field => $type) {
if (in_array($field, $fields)) {
unset($fields[array_search($field, $fields)]);
@ -134,7 +134,7 @@ class SubsitesVirtualPage extends VirtualPage
return $fields;
}
public function syncLinkTracking()
{
$oldState = Subsite::$disable_subsite_filter;
@ -148,7 +148,7 @@ class SubsitesVirtualPage extends VirtualPage
public function onBeforeWrite()
{
parent::onBeforeWrite();
if ($this->CustomMetaTitle) {
$this->MetaTitle = $this->CustomMetaTitle;
} else {
@ -170,46 +170,6 @@ class SubsitesVirtualPage extends VirtualPage
$this->ExtraMeta = $this->ContentSource()->ExtraMeta ? $this->ContentSource()->ExtraMeta : $this->ExtraMeta;
}
}
public function validURLSegment()
{
$isValid = parent::validURLSegment();
// Veto the validation rules if its false. In this case, some logic
// needs to be duplicated from parent to find out the exact reason the validation failed.
if (!$isValid) {
$IDFilter = ($this->ID) ? "AND \"SiteTree\".\"ID\" <> $this->ID" : null;
$parentFilter = null;
if (Config::inst()->get('SiteTree', 'nested_urls')) {
if ($this->ParentID) {
$parentFilter = " AND \"SiteTree\".\"ParentID\" = $this->ParentID";
} else {
$parentFilter = ' AND "SiteTree"."ParentID" = 0';
}
}
$origDisableSubsiteFilter = Subsite::$disable_subsite_filter;
Subsite::$disable_subsite_filter = true;
$existingPage = DataObject::get_one(
'SiteTree',
"\"URLSegment\" = '$this->URLSegment' $IDFilter $parentFilter",
false // disable cache, it doesn't include subsite status in the key
);
Subsite::$disable_subsite_filter = $origDisableSubsiteFilter;
$existingPageInSubsite = DataObject::get_one(
'SiteTree',
"\"URLSegment\" = '$this->URLSegment' $IDFilter $parentFilter",
false // disable cache, it doesn't include subsite status in the key
);
// If URL has been vetoed because of an existing page,
// be more specific and allow same URLSegments in different subsites
$isValid = !($existingPage && $existingPageInSubsite);
}
return $isValid;
}
}
class SubsitesVirtualPage_Controller extends VirtualPage_Controller
@ -220,14 +180,14 @@ class SubsitesVirtualPage_Controller extends VirtualPage_Controller
$this->failover->write();
return;
}
public function init()
{
$origDisableSubsiteFilter = Subsite::$disable_subsite_filter;
Subsite::$disable_subsite_filter = true;
parent::init();
Subsite::$disable_subsite_filter = $origDisableSubsiteFilter;
}
}

View File

@ -24,7 +24,7 @@ class SiteTreeSubsites extends DataExtension
}
return false;
}
/**
* Update any requests to limit the results to the current site
*/
@ -36,7 +36,7 @@ class SiteTreeSubsites extends DataExtension
if ($dataQuery->getQueryParam('Subsite.filter') === false) {
return;
}
// If you're querying by ID, ignore the sub-site - this is a bit ugly...
// if(!$query->where || (strpos($query->where[0], ".\"ID\" = ") === false && strpos($query->where[0], ".`ID` = ") === false && strpos($query->where[0], ".ID = ") === false && strpos($query->where[0], "ID = ") !== 0)) {
if ($query->filtersOnID()) {
@ -60,13 +60,13 @@ class SiteTreeSubsites extends DataExtension
break;
}
}
public function onBeforeWrite()
{
if (!$this->owner->ID && !$this->owner->SubsiteID) {
$this->owner->SubsiteID = Subsite::currentSubsiteID();
}
parent::onBeforeWrite();
}
@ -107,7 +107,7 @@ class SiteTreeSubsites extends DataExtension
if ($subsite && $subsite->exists()) {
// Use baseurl from domain
$baseLink = $subsite->absoluteBaseURL();
// Add parent page if enabled
if($nested_urls_enabled && $this->owner->ParentID) {
$baseLink = Controller::join_links(
@ -115,12 +115,12 @@ class SiteTreeSubsites extends DataExtension
$this->owner->Parent()->RelativeLink(true)
);
}
$urlsegment = $fields->dataFieldByName('URLSegment');
$urlsegment->setURLPrefix($baseLink);
}
}
public function alternateSiteConfig()
{
if (!$this->owner->SubsiteID) {
@ -136,12 +136,12 @@ class SiteTreeSubsites extends DataExtension
}
return $sc;
}
/**
* Only allow editing of a page if the member satisfies one of the following conditions:
* - Is in a group which has access to the subsite this page belongs to
* - Is in a group with edit permissions on the "main site"
*
*
* @return boolean
*/
public function canEdit($member = null)
@ -149,7 +149,7 @@ class SiteTreeSubsites extends DataExtension
if (!$member) {
$member = Member::currentUser();
}
// Find the sites that this user has access to
$goodSites = Subsite::accessible_sites('CMS_ACCESS_CMSMain', true, 'all', $member)->column('ID');
@ -169,7 +169,7 @@ class SiteTreeSubsites extends DataExtension
return false;
}
}
/**
* @return boolean
*/
@ -178,10 +178,10 @@ class SiteTreeSubsites extends DataExtension
if (!$member && $member !== false) {
$member = Member::currentUser();
}
return $this->canEdit($member);
}
/**
* @return boolean
*/
@ -190,10 +190,10 @@ class SiteTreeSubsites extends DataExtension
if (!$member && $member !== false) {
$member = Member::currentUser();
}
return $this->canEdit($member);
}
/**
* @return boolean
*/
@ -218,7 +218,7 @@ class SiteTreeSubsites extends DataExtension
} else {
$subsite = DataObject::get_by_id('Subsite', $subsiteID);
}
$oldSubsite=Subsite::currentSubsiteID();
if ($subsiteID) {
Subsite::changeSubsite($subsiteID);
@ -294,7 +294,7 @@ class SiteTreeSubsites extends DataExtension
// Set LinkTracking appropriately
$links = HTTP::getLinksIn($this->owner->Content);
$linkedPages = array();
if ($links) {
foreach ($links as $link) {
if (substr($link, 0, strlen('http://')) == 'http://') {
@ -302,7 +302,7 @@ class SiteTreeSubsites extends DataExtension
if (strpos($withoutHttp, '/') && strpos($withoutHttp, '/') < strlen($withoutHttp)) {
$domain = substr($withoutHttp, 0, strpos($withoutHttp, '/'));
$rest = substr($withoutHttp, strpos($withoutHttp, '/') + 1);
$subsiteID = Subsite::getSubsiteIDForDomain($domain);
if ($subsiteID == 0) {
continue;
@ -312,7 +312,7 @@ class SiteTreeSubsites extends DataExtension
Subsite::disable_subsite_filter(true);
$candidatePage = DataObject::get_one("SiteTree", "\"URLSegment\" = '" . Convert::raw2sql(urldecode($rest)) . "' AND \"SubsiteID\" = " . $subsiteID, false);
Subsite::disable_subsite_filter($origDisableSubsiteFilter);
if ($candidatePage) {
$linkedPages[] = $candidatePage->ID;
} else {
@ -322,10 +322,37 @@ class SiteTreeSubsites extends DataExtension
}
}
}
$this->owner->CrossSubsiteLinkTracking()->setByIDList($linkedPages);
}
/**
* Ensure that valid url segments are checked within the correct subsite of the owner object,
* even if the current subsiteID is set to some other subsite.
*
* @return null|bool Either true or false, or null to not influence result
*/
public function augmentValidURLSegment()
{
// If this page is being filtered in the current subsite, then no custom validation query is required.
$subsite = Subsite::$force_subsite ?: Subsite::currentSubsiteID();
if (empty($this->owner->SubsiteID) || $subsite == $this->owner->SubsiteID) {
return null;
}
// Backup forced subsite
$prevForceSubsite = Subsite::$force_subsite;
Subsite::$force_subsite = $this->owner->SubsiteID;
// Repeat validation in the correct subsite
$isValid = $this->owner->validURLSegment();
// Restore
Subsite::$force_subsite = $prevForceSubsite;
return (bool)$isValid;
}
/**
* Return a piece of text to keep DataObject cache keys appropriately specific
*/
@ -333,7 +360,7 @@ class SiteTreeSubsites extends DataExtension
{
return 'subsite-'.Subsite::currentSubsiteID();
}
/**
* @param Member
* @return boolean|null

View File

@ -9,8 +9,8 @@ class Subsite extends DataObject
{
/**
* @var $use_session_subsiteid Boolean Set to TRUE when using the CMS and FALSE
* when browsing the frontend of a website.
*
* when browsing the frontend of a website.
*
* @todo Remove flag once the Subsite CMS works without session state,
* similarly to the Translatable module.
*/
@ -21,7 +21,7 @@ class Subsite extends DataObject
* to limit DataObject::get*() calls to a specific subsite. Useful for debugging.
*/
public static $disable_subsite_filter = false;
/**
* Allows you to force a specific subsite ID, or comma separated list of IDs.
* Only works for reading. An object cannot be written to more than 1 subsite.
@ -33,10 +33,10 @@ class Subsite extends DataObject
* @var boolean
*/
public static $write_hostmap = true;
/**
* Memory cache of accessible sites
*
*
* @array
*/
private static $_cache_accessible_sites = array();
@ -54,7 +54,7 @@ class Subsite extends DataObject
* are listed.
*/
private static $allowed_themes = array();
/**
* @var Boolean If set to TRUE, don't assume 'www.example.com' and 'example.com' are the same.
* Doesn't affect wildcard matching, so '*.example.com' will match 'www.example.com' (but not 'example.com')
@ -69,14 +69,14 @@ class Subsite extends DataObject
/**
* Set allowed themes
*
*
* @param array $themes - Numeric array of all themes which are allowed to be selected for all subsites.
*/
public static function set_allowed_themes($themes)
{
self::$allowed_themes = $themes;
}
/**
* Gets the subsite currently set in the session.
*
@ -99,7 +99,6 @@ class Subsite extends DataObject
*
* @todo Pass $request object from controller so we don't have to rely on $_GET
*
* @param boolean $cache
* @return int ID of the current subsite instance
*/
public static function currentSubsiteID()
@ -118,7 +117,7 @@ class Subsite extends DataObject
return (int)$id;
}
/**
* Switch to another subsite through storing the subsite identifier in the current PHP session.
* Only takes effect when {@link Subsite::$use_session_subsiteid} is set to TRUE.
@ -151,13 +150,13 @@ class Subsite extends DataObject
Permission::flush_permission_cache();
}
/**
* Get a matching subsite for the given host, or for the current HTTP_HOST.
* Supports "fuzzy" matching of domains by placing an asterisk at the start of end of the string,
* for example matching all subdomains on *.example.com with one subsite,
* and all subdomains on *.example.org on another.
*
*
* @param $host The host to find the subsite for. If not specified, $_SERVER['HTTP_HOST'] is used.
* @return int Subsite ID
*/
@ -215,7 +214,7 @@ class Subsite extends DataObject
}
/**
*
*
* @param string $className
* @param string $filter
* @param string $sort
@ -237,7 +236,7 @@ class Subsite extends DataObject
{
self::$disable_subsite_filter = $disabled;
}
/**
* Flush caches on database reset
*/
@ -246,7 +245,7 @@ class Subsite extends DataObject
self::$_cache_accessible_sites = array();
self::$_cache_subsite_for_domain = array();
}
/**
* Return all subsites, regardless of permissions (augmented with main site).
*
@ -333,13 +332,13 @@ class Subsite extends DataObject
$member = DataObject::get_by_id('Member', $member);
}
// Rationalise permCode argument
// Rationalise permCode argument
if (is_array($permCode)) {
$SQL_codes = "'" . implode("', '", Convert::raw2sql($permCode)) . "'";
} else {
$SQL_codes = "'" . Convert::raw2sql($permCode) . "'";
}
// Cache handling
$cacheKey = $SQL_codes . '-' . $member->ID . '-' . $includeMainSite . '-' . $mainSiteTitle;
if (isset(self::$_cache_accessible_sites[$cacheKey])) {
@ -386,19 +385,19 @@ class Subsite extends DataObject
}
if (self::hasMainSitePermission($member, $permCode)) {
$subsites=$subsites->toArray();
$mainSite = new Subsite();
$mainSite->Title = $mainSiteTitle;
array_unshift($subsites, $mainSite);
$subsites=ArrayList::create($subsites);
}
}
self::$_cache_accessible_sites[$cacheKey] = $subsites;
return $subsites;
}
/**
* Write a host->domain map to subsites/host-map.php
*
@ -412,14 +411,14 @@ class Subsite extends DataObject
if (!self::$write_hostmap) {
return;
}
if (!$file) {
$file = Director::baseFolder().'/subsites/host-map.php';
}
$hostmap = array();
$subsites = DataObject::get('Subsite');
if ($subsites) {
foreach ($subsites as $subsite) {
$domains = $subsite->Domains();
@ -437,7 +436,7 @@ class Subsite extends DataObject
}
}
}
$data = "<?php \n";
$data .= "// Generated by Subsite::writeHostMap() on " . date('d/M/y') . "\n";
$data .= '$subsiteHostmap = ' . var_export($hostmap, true) . ';';
@ -446,16 +445,16 @@ class Subsite extends DataObject
file_put_contents($file, $data);
}
}
/**
* Checks if a member can be granted certain permissions, regardless of the subsite context.
* Similar logic to {@link Permission::checkMember()}, but only returns TRUE
* if the member is part of a group with the "AccessAllSubsites" flag set.
* If more than one permission is passed to the method, at least one of them must
* be granted for if to return TRUE.
*
*
* @todo Allow permission inheritance through group hierarchy.
*
*
* @param Member Member to check against. Defaults to currently logged in member
* @param Array Permission code strings. Defaults to "ADMIN".
* @return boolean
@ -473,7 +472,7 @@ class Subsite extends DataObject
if (!$member) {
return false;
}
if (!in_array("ADMIN", $permissionCodes)) {
$permissionCodes[] = "ADMIN";
}
@ -481,7 +480,7 @@ class Subsite extends DataObject
$SQLa_perm = Convert::raw2sql($permissionCodes);
$SQL_perms = join("','", $SQLa_perm);
$memberID = (int)$member->ID;
// Count this user's groups which can access the main site
$groupCount = DB::query("
SELECT COUNT(\"Permission\".\"ID\")
@ -508,7 +507,7 @@ class Subsite extends DataObject
// There has to be at least one that allows access.
return ($groupCount + $roleCount > 0);
}
/**
*
* @var array
@ -523,7 +522,7 @@ class Subsite extends DataObject
// Used to hide unfinished/private subsites from public view.
// If unset, will default to true
'IsPublic' => 'Boolean',
// Comma-separated list of disallowed page types
'PageTypeBlacklist' => 'Text',
);
@ -535,7 +534,7 @@ class Subsite extends DataObject
private static $has_many = array(
'Domains' => 'SubsiteDomain',
);
/**
*
* @var array
@ -561,13 +560,13 @@ class Subsite extends DataObject
'Domains.Domain',
'IsPublic',
);
/**
*
* @var string
*/
private static $default_sort = "\"Title\" ASC";
/**
* @todo Possible security issue, don't grant edit permissions to everybody.
* @return boolean
@ -579,7 +578,7 @@ class Subsite extends DataObject
/**
* Show the configuration fields for each subsite
*
*
* @return FieldList
*/
public function getCMSFields()
@ -597,13 +596,13 @@ class Subsite extends DataObject
'<p>'._t('Subsite.DOMAINSAVEFIRST', 'You can only add domains after saving for the first time').'</p>'
);
}
$languageSelector = new DropdownField(
'Language',
$this->fieldLabel('Language'),
i18n::get_common_locales()
);
$pageTypeMap = array();
$pageTypes = SiteTree::page_type_classes();
foreach ($pageTypes as $pageType) {
@ -618,7 +617,7 @@ class Subsite extends DataObject
_t('Subsite.TabTitleConfig', 'Configuration'),
new HeaderField($this->getClassName() . ' configuration', 2),
new TextField('Title', $this->fieldLabel('Title'), $this->Title),
new HeaderField(
_t('Subsite.DomainsHeadline', "Domains for this subsite")
),
@ -629,8 +628,8 @@ class Subsite extends DataObject
new CheckboxField('IsPublic', $this->fieldLabel('IsPublic'), $this->IsPublic),
new DropdownField('Theme', $this->fieldLabel('Theme'), $this->allowedThemes(), $this->Theme),
new LiteralField(
'PageTypeBlacklistToggle',
sprintf(
@ -654,9 +653,9 @@ class Subsite extends DataObject
$this->extend('updateCMSFields', $fields);
return $fields;
}
/**
*
*
* @param boolean $includerelations
* @return array
*/
@ -677,7 +676,7 @@ class Subsite extends DataObject
}
/**
*
*
* @return array
*/
public function summaryFields()
@ -688,10 +687,10 @@ class Subsite extends DataObject
'IsPublic' => _t('Subsite.IsPublicHeaderField', 'Active subsite'),
);
}
/**
* Return the themes that can be used with this subsite, as an array of themecode => description
*
*
* @return array
*/
public function allowedThemes()
@ -727,7 +726,7 @@ class Subsite extends DataObject
}
/**
*
*
* @return ValidationResult
*/
public function validate()
@ -749,11 +748,11 @@ class Subsite extends DataObject
Subsite::writeHostMap();
parent::onAfterWrite();
}
/**
* Return the primary domain of this site. Tries to "normalize" the domain name,
* by replacing potential wildcards.
*
*
* @return string The full domain name of this subsite (without protocol prefix)
*/
public function domain()
@ -780,9 +779,9 @@ class Subsite extends DataObject
->sort('"IsPrimary" DESC')
->first();
}
/**
*
*
* @return string - The full domain name of this subsite (without protocol prefix)
*/
public function getPrimaryDomain()
@ -792,7 +791,7 @@ class Subsite extends DataObject
/**
* Get the absolute URL for this subsite
* @return string
* @return string
*/
public function absoluteBaseURL()
{
@ -816,8 +815,8 @@ class Subsite extends DataObject
/**
* Javascript admin action to duplicate this subsite
*
* @return string - javascript
*
* @return string - javascript
*/
public function adminDuplicate()
{
@ -827,7 +826,7 @@ class Subsite extends DataObject
'Created a copy of {title}',
array('title' => Convert::raw2js($this->Title))
);
return <<<JS
statusMessage($message, 'good');
$('Form_EditForm').loadURLFromServer('admin/subsites/show/$newItem->ID');
@ -843,7 +842,7 @@ JS;
}
/**
*
*
* @param array $permissionCodes
* @return DataList
*/

View File

@ -6,6 +6,7 @@ class BaseSubsiteTest extends SapphireTest
parent::setUp();
Subsite::$use_session_subsiteid = true;
Subsite::$force_subsite = null;
}
/**

View File

@ -3,7 +3,7 @@
class SiteTreeSubsitesTest extends BaseSubsiteTest
{
public static $fixture_file = 'subsites/tests/SubsiteTest.yml';
protected $extraDataObjects = array(
'SiteTreeSubsitesTest_ClassA',
'SiteTreeSubsitesTest_ClassB'
@ -12,38 +12,38 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
protected $illegalExtensions = array(
'SiteTree' => array('Translatable')
);
public function testPagesInDifferentSubsitesCanShareURLSegment()
{
$subsiteMain = $this->objFromFixture('Subsite', 'main');
$subsite1 = $this->objFromFixture('Subsite', 'subsite1');
$pageMain = new SiteTree();
$pageMain->URLSegment = 'testpage';
$pageMain->write();
$pageMain->publish('Stage', 'Live');
$pageMainOther = new SiteTree();
$pageMainOther->URLSegment = 'testpage';
$pageMainOther->write();
$pageMainOther->publish('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->publish('Stage', 'Live');
$this->assertEquals($pageMain->URLSegment, $pageSubsite1->URLSegment,
'Pages in different subsites can share the same URL'
);
}
public function testBasicSanity()
{
$this->assertTrue(singleton('SiteTree')->getSiteConfig() instanceof SiteConfig);
@ -52,19 +52,19 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
$this->assertTrue(singleton('SubsitesVirtualPage')->getCMSFields() instanceof FieldList);
$this->assertTrue(is_array(singleton('SiteTreeSubsites')->extraStatics()));
}
public function testErrorPageLocations()
{
$subsite1 = $this->objFromFixture('Subsite', 'domaintest1');
Subsite::changeSubsite($subsite1->ID);
$path = ErrorPage::get_filepath_for_errorcode(500);
$static_path = Config::inst()->get('ErrorPage', 'static_filepath');
$expected_path = $static_path . '/error-500-'.$subsite1->domain().'.html';
$this->assertEquals($expected_path, $path);
}
public function testCanEditSiteTree()
{
$admin = $this->objFromFixture('Member', 'admin');
@ -75,29 +75,29 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
$subsite2page = $this->objFromFixture('Page', 'subsite2_home');
$subsite1 = $this->objFromFixture('Subsite', 'subsite1');
$subsite2 = $this->objFromFixture('Subsite', 'subsite2');
// Cant pass member as arguments to canEdit() because of GroupSubsites
Session::set("loggedInAs", $admin->ID);
$this->assertTrue(
(bool)$subsite1page->canEdit(),
'Administrators can edit all subsites'
);
// @todo: Workaround because GroupSubsites->augmentSQL() is relying on session state
Subsite::changeSubsite($subsite1);
Session::set("loggedInAs", $subsite1member->ID);
$this->assertTrue(
(bool)$subsite1page->canEdit(),
'Members can edit pages on a subsite if they are in a group belonging to this subsite'
);
Session::set("loggedInAs", $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'
);
// @todo: Workaround because GroupSubsites->augmentSQL() is relying on session state
Subsite::changeSubsite(0);
$this->assertFalse(
@ -105,7 +105,7 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
'Members cant edit pages on the main site if they are not in a group allowing this'
);
}
/**
* Similar to {@link SubsitesVirtualPageTest->testSubsiteVirtualPageCanHaveSameUrlsegmentAsOtherSubsite()}.
*/
@ -114,7 +114,7 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
// Set up a couple of pages with the same URL on different subsites
$s1 = $this->objFromFixture('Subsite', 'domaintest1');
$s2 = $this->objFromFixture('Subsite', 'domaintest2');
$p1 = new SiteTree();
$p1->Title = $p1->URLSegment = "test-page";
$p1->SubsiteID = $s1->ID;
@ -128,7 +128,7 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
// Check that the URLs weren't modified in our set-up
$this->assertEquals($p1->URLSegment, 'test-page');
$this->assertEquals($p2->URLSegment, 'test-page');
// 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);
@ -136,22 +136,22 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
Subsite::changeSubsite($s2);
$this->assertEquals($p2->ID, SiteTree::get_by_link('test-page')->ID);
}
public function testPageTypesBlacklistInClassDropdown()
{
$editor = $this->objFromFixture('Member', 'editor');
Session::set("loggedInAs", $editor->ID);
$s1 = $this->objFromFixture('Subsite', 'domaintest1');
$s2 = $this->objFromFixture('Subsite', 'domaintest2');
$page = singleton('SiteTree');
$s1->PageTypeBlacklist = 'SiteTreeSubsitesTest_ClassA,ErrorPage';
$s1->write();
Subsite::changeSubsite($s1);
$settingsFields = $page->getSettingsFields()->dataFieldByName('ClassName')->getSource();
$this->assertArrayNotHasKey('ErrorPage',
$settingsFields
);
@ -174,17 +174,17 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
$settingsFields
);
}
public function testPageTypesBlacklistInCMSMain()
{
$editor = $this->objFromFixture('Member', 'editor');
Session::set("loggedInAs", $editor->ID);
$cmsmain = new CMSMain();
$s1 = $this->objFromFixture('Subsite', 'domaintest1');
$s2 = $this->objFromFixture('Subsite', 'domaintest2');
$s1->PageTypeBlacklist = 'SiteTreeSubsitesTest_ClassA,ErrorPage';
$s1->write();
@ -202,6 +202,65 @@ class SiteTreeSubsitesTest extends BaseSubsiteTest
$this->assertNotContains('SiteTreeSubsitesTest_ClassA', $classes);
$this->assertNotContains('SiteTreeSubsitesTest_ClassB', $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', 'home');
$mainSubsiteID = $this->idFromFixture('Subsite', 'main');
Subsite::changeSubsite($mainSubsiteID);
$mainHome->Content = '<p>Some new content</p>';
$mainHome->write();
$this->assertEquals('home', $mainHome->URLSegment);
$mainHome->doPublish();
$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 = '<p>In subsite 1</p>';
$subsite1Home->write();
$this->assertEquals('home', $subsite1Home->URLSegment);
$subsite1Home->doPublish();
$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', '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->doPublish();
$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->doPublish();
$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 = '<p>New Important Page Content</p>';
$mainSubsiteImportantPage->write();
$this->assertEquals('important-page', $mainSubsiteImportantPage->URLSegment);
}
}
class SiteTreeSubsitesTest_ClassA extends SiteTree implements TestOnly

View File

@ -17,17 +17,17 @@ class SubsiteTest extends BaseSubsiteTest
* @var array
*/
protected $origServer = array();
public function setUp()
{
parent::setUp();
Config::inst()->update('Director', 'alternate_base_url', '/');
$this->origStrictSubdomainMatching = Subsite::$strict_subdomain_matching;
$this->origServer = $_SERVER;
Subsite::$strict_subdomain_matching = false;
}
public function tearDown()
{
$_SERVER = $this->origServer;
@ -42,15 +42,16 @@ class SubsiteTest extends BaseSubsiteTest
public function testSubsiteCreation()
{
Subsite::$write_hostmap = false;
// Create the instance
$template = $this->objFromFixture('Subsite', 'main');
// Test that changeSubsite is working
Subsite::changeSubsite($template->ID);
$this->assertEquals($template->ID, Subsite::currentSubsiteID());
$tmplStaff = $this->objFromFixture('Page', 'staff');
$tmplHome = DataObject::get_one('Page', "\"URLSegment\" = 'home'");
// Publish all the pages in the template, testing that DataObject::get only returns pages from the chosen subsite
$pages = DataObject::get("SiteTree");
$totalPages = $pages->Count();
@ -61,22 +62,22 @@ class SubsiteTest extends BaseSubsiteTest
// Create a new site
$subsite = $template->duplicate();
// Check title
$this->assertEquals($subsite->Title, $template->Title);
// Another test that changeSubsite is working
$subsite->activate();
$siteHome = DataObject::get_one('Page', "\"URLSegment\" = 'home'");
$this->assertNotEquals($siteHome, false, 'Home Page for subsite not found');
$this->assertEquals($subsite->ID, $siteHome->SubsiteID,
'createInstance() copies existing pages retaining the same URLSegment'
);
Subsite::changeSubsite(0);
}
/**
* Confirm that domain lookup is working
*/
@ -89,7 +90,7 @@ class SubsiteTest extends BaseSubsiteTest
foreach (DataObject::get('SubsiteDomain') as $domain) {
$domain->delete();
}
// Much more expressive than YML in this case
$subsite1 = $this->createSubsiteWithDomains(array(
'one.example.org' => true,
@ -105,19 +106,19 @@ class SubsiteTest extends BaseSubsiteTest
'subdomain.unique.com' => false,
'*.onmultiplesubsites.com' => false,
));
$this->assertEquals(
$subsite3->ID,
Subsite::getSubsiteIDForDomain('subdomain.unique.com'),
'Full unique match'
);
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('one.example.org'),
'Full match, doesn\'t complain about multiple matches within a single subsite'
);
$failed = false;
try {
Subsite::getSubsiteIDForDomain('subdomain.onmultiplesubsites.com');
@ -128,19 +129,19 @@ class SubsiteTest extends BaseSubsiteTest
$failed,
'Fails on multiple matches with wildcard vs. www across multiple subsites'
);
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('one.unique.com'),
'Fuzzy match suffixed with wildcard (rule "one.*")'
);
$this->assertEquals(
$subsite2->ID,
Subsite::getSubsiteIDForDomain('two.mysite.com'),
'Matches correct subsite for rule'
);
$this->assertEquals(
$subsite2->ID,
Subsite::getSubsiteIDForDomain('other.mysite.com'),
@ -153,7 +154,7 @@ class SubsiteTest extends BaseSubsiteTest
"Doesn't match unknown subsite"
);
}
public function testStrictSubdomainMatching()
{
// Clear existing fixtures
@ -163,7 +164,7 @@ class SubsiteTest extends BaseSubsiteTest
foreach (DataObject::get('SubsiteDomain') as $domain) {
$domain->delete();
}
// Much more expressive than YML in this case
$subsite1 = $this->createSubsiteWithDomains(array(
'example.org' => true,
@ -176,7 +177,7 @@ class SubsiteTest extends BaseSubsiteTest
));
Subsite::$strict_subdomain_matching = false;
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('example.org'),
@ -197,9 +198,9 @@ class SubsiteTest extends BaseSubsiteTest
Subsite::getSubsiteIDForDomain('www.wildcard.com'),
'Doesn\'t match www prefix without strict check, even if a wildcard subdomain is in place'
);
Subsite::$strict_subdomain_matching = true;
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('example.org'),
@ -226,7 +227,7 @@ class SubsiteTest extends BaseSubsiteTest
'Fails on multiple matches with strict checking and wildcard vs. www'
);
}
protected function createSubsiteWithDomains($domains)
{
$subsite = new Subsite(array(
@ -241,7 +242,7 @@ class SubsiteTest extends BaseSubsiteTest
));
$domain->write();
}
return $subsite;
}
@ -267,7 +268,7 @@ class SubsiteTest extends BaseSubsiteTest
$this->assertEquals($_SERVER['HTTP_HOST'], singleton('Subsite')->PrimaryDomain);
$this->assertEquals('http://'.$_SERVER['HTTP_HOST'].Director::baseURL(), singleton('Subsite')->absoluteBaseURL());
}
/**
* Tests that Subsite and SubsiteDomain both respect http protocol correctly
*/
@ -276,20 +277,20 @@ class SubsiteTest extends BaseSubsiteTest
$subsite2 = $this->objFromFixture('Subsite', 'domaintest2');
$domain2a = $this->objFromFixture('SubsiteDomain', 'dt2a');
$domain2b = $this->objFromFixture('SubsiteDomain', 'dt2b');
// domaintest4 is 'https' (primary only)
$subsite4 = $this->objFromFixture('Subsite', 'domaintest4');
$domain4a = $this->objFromFixture('SubsiteDomain', 'dt4a');
$domain4b = $this->objFromFixture('SubsiteDomain', 'dt4b'); // secondary domain is http only though
// domaintest5 is 'http'
$subsite5 = $this->objFromFixture('Subsite', 'domaintest5');
$domain5a = $this->objFromFixture('SubsiteDomain', 'dt5');
// Check protocol when current protocol is http://
$_SERVER['HTTP_HOST'] = 'www.mysite.com';
$_SERVER['HTTPS'] = '';
$this->assertEquals('http://two.mysite.com/', $subsite2->absoluteBaseURL());
$this->assertEquals('http://two.mysite.com/', $domain2a->absoluteBaseURL());
$this->assertEquals('http://subsite.mysite.com/', $domain2b->absoluteBaseURL());
@ -298,11 +299,11 @@ class SubsiteTest extends BaseSubsiteTest
$this->assertEquals('http://www.secondary.com/', $domain4b->absoluteBaseURL());
$this->assertEquals('http://www.tertiary.com/', $subsite5->absoluteBaseURL());
$this->assertEquals('http://www.tertiary.com/', $domain5a->absoluteBaseURL());
// Check protocol when current protocol is https://
$_SERVER['HTTP_HOST'] = 'www.mysite.com';
$_SERVER['HTTPS'] = 'ON';
$this->assertEquals('https://two.mysite.com/', $subsite2->absoluteBaseURL());
$this->assertEquals('https://two.mysite.com/', $domain2a->absoluteBaseURL());
$this->assertEquals('https://subsite.mysite.com/', $domain2b->absoluteBaseURL());
@ -373,14 +374,14 @@ class SubsiteTest extends BaseSubsiteTest
sort($member2SiteTitles);
$this->assertEquals('Subsite1 Template', $member2SiteTitles[0], 'Member can get to subsite via a group role');
}
public function testhasMainSitePermission()
{
$admin = $this->objFromFixture('Member', 'admin');
$subsite1member = $this->objFromFixture('Member', 'subsite1member');
$subsite1admin = $this->objFromFixture('Member', 'subsite1admin');
$allsubsitesauthor = $this->objFromFixture('Member', 'allsubsitesauthor');
$this->assertTrue(
Subsite::hasMainSitePermission($admin),
'Default permissions granted for super-admin'
@ -425,7 +426,7 @@ class SubsiteTest extends BaseSubsiteTest
$page1->write();
$page1->doPublish();
$this->assertEquals($page1->SubsiteID, $subsite1->ID);
// duplicate
$subsite2 = $subsite1->duplicate();
$subsite2->activate();
@ -434,7 +435,7 @@ class SubsiteTest extends BaseSubsiteTest
$page2->Title = 'MyNewAwesomePage';
$page2->write();
$page2->doPublish();
// check change & check change has not affected subiste1
$subsite1->activate();
$this->assertEquals('MyAwesomePage', DataObject::get_by_id('Page', $page1->ID)->Title);

View File

@ -64,40 +64,52 @@ Page:
mainSubsitePage:
Title: MainSubsitePage
SubsiteID: 0
URLSegment: mainsubsitepage
home:
Title: Home
SubsiteID: =>Subsite.main
URLSegment: home
about:
Title: About
SubsiteID: =>Subsite.main
URLSegment: about
linky:
Title: Linky
SubsiteID: =>Subsite.main
URLSegment: linky
staff:
Title: Staff
ParentID: =>Page.about
SubsiteID: =>Subsite.main
URLSegment: staff
contact:
Title: Contact Us
SubsiteID: =>Subsite.main
URLSegment: contact-us
importantpage:
Title: Important Page
SubsiteID: =>Subsite.main
URLSegment: important-page
subsite1_home:
Title: Home (Subsite 1)
SubsiteID: =>Subsite.subsite1
URLSegment: home
subsite1_contactus:
Title: Contact Us (Subsite 1)
SubsiteID: =>Subsite.subsite1
URLSegment: contact-us
subsite1_staff:
Title: Staff
SubsiteID: =>Subsite.subsite1
URLSegment: staff
subsite2_home:
Title: Home (Subsite 2)
SubsiteID: =>Subsite.subsite2
URLSegment: home
subsite2_contactus:
Title: Contact Us (Subsite 2)
SubsiteID: =>Subsite.subsite2
URLSegment: contact-us
PermissionRoleCode:
roleCode1:

View File

@ -6,12 +6,12 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
'subsites/tests/SubsiteTest.yml',
'subsites/tests/SubsitesVirtualPageTest.yml',
);
public function setUp()
{
parent::setUp();
$this->logInWithPermission('ADMIN');
$fh = fopen(Director::baseFolder() . '/assets/testscript-test-file.pdf', "w");
fwrite($fh, str_repeat('x', 1000000));
fclose($fh);
@ -31,26 +31,26 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
}
}
}
// Attempt to bring main:linky to subsite2:linky
public function testVirtualPageFromAnotherSubsite()
{
Subsite::$write_hostmap = false;
$subsite = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($subsite->ID);
Subsite::$disable_subsite_filter = false;
$linky = $this->objFromFixture('Page', 'linky');
$svp = new SubsitesVirtualPage();
$svp->CopyContentFromID = $linky->ID;
$svp->SubsiteID = $subsite->ID;
$svp->URLSegment = 'linky';
$svp->write();
$this->assertEquals($svp->SubsiteID, $subsite->ID);
$this->assertEquals($svp->Title, $linky->Title);
}
@ -70,12 +70,12 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$svp->CopyContentFromID = $page->ID;
$svp->write();
$svp->doPublish();
// Rename the file
$file = $this->objFromFixture('File', 'file1');
$file->Name = 'renamed-test-file.pdf';
$file->write();
// Verify that the draft and publish virtual pages both have the corrected link
$this->assertContains('<img src="assets/renamed-test-file.pdf"',
DB::query("SELECT \"Content\" FROM \"SiteTree\" WHERE \"ID\" = $svp->ID")->value());
@ -111,27 +111,27 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$p->doPublish();
$this->fixVersionNumberCache($vp);
$this->assertTrue($vp->IsAddedToStage);
// A new VP created after P's initial construction
$vp2 = new SubsitesVirtualPage();
$vp2->CopyContentFromID = $p->ID;
$vp2->write();
$this->assertTrue($vp2->IsAddedToStage);
// Also remains orange after a republish
$p->Content = "new content";
$p->write();
$p->doPublish();
$this->fixVersionNumberCache($vp2);
$this->assertTrue($vp2->IsAddedToStage);
// VP is now published
$vp->doPublish();
$this->fixVersionNumberCache($vp);
$this->assertTrue($vp->ExistsOnLive);
$this->assertFalse($vp->IsModifiedOnStage);
// P edited, VP and P both go green
$p->Content = "third content";
$p->write();
@ -146,7 +146,7 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$this->assertTrue($vp->ExistsOnLive);
$this->assertFalse($vp->IsModifiedOnStage);
}
/**
* This test ensures published Subsites Virtual Pages immediately reflect updates
* to their published target pages. Note - this has to happen when the virtual page
@ -162,12 +162,12 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$p->writeToStage('Stage');
$p->publish('Stage', 'Live');
$this->assertTrue($p->ExistsOnLive);
// change to subsite
$subsite = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($subsite->ID);
Subsite::$disable_subsite_filter = false;
// create svp in subsite
$svp = new SubsitesVirtualPage();
$svp->CopyContentFromID = $p->ID;
@ -176,34 +176,34 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$svp->publish('Stage', 'Live');
$this->assertEquals($svp->SubsiteID, $subsite->ID);
$this->assertTrue($svp->ExistsOnLive);
// change back to original subsite ("Main site")
Subsite::changeSubsite(0);
// update original page
$p->Title = 'New Title';
// "save & publish"
$p->writeToStage('Stage');
$p->publish('Stage', 'Live');
$this->assertNotEquals($p->SubsiteID, $subsite->ID);
// reload SVP from database
// can't use DO::get by id because caches.
$svpdb = $svp->get()->byID($svp->ID);
// ensure title changed
$this->assertEquals($svpdb->Title, $p->Title);
}
public function testUnpublishingParentPageUnpublishesSubsiteVirtualPages()
{
Config::inst()->update('StaticPublisher', 'disable_realtime', true);
// Go to main site, get parent page
$subsite = $this->objFromFixture('Subsite', 'main');
Subsite::changeSubsite($subsite->ID);
$page = $this->objFromFixture('Page', 'importantpage');
// Create two SVPs on other subsites
$subsite = $this->objFromFixture('Subsite', 'subsite1');
Subsite::changeSubsite($subsite->ID);
@ -211,30 +211,30 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$vp1->CopyContentFromID = $page->ID;
$vp1->write();
$vp1->doPublish();
$subsite = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($subsite->ID);
$vp2 = new SubsitesVirtualPage();
$vp2->CopyContentFromID = $page->ID;
$vp2->write();
$vp2->doPublish();
// Switch back to main site, unpublish source
$subsite = $this->objFromFixture('Subsite', 'main');
Subsite::changeSubsite($subsite->ID);
$page = $this->objFromFixture('Page', 'importantpage');
$page->doUnpublish();
Subsite::changeSubsite($vp1->SubsiteID);
$onLive = Versioned::get_one_by_stage('SubsitesVirtualPage', 'Live', "\"SiteTree_Live\".\"ID\" = ".$vp1->ID);
$this->assertNull($onLive, 'SVP has been removed from live');
$subsite = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($vp2->SubsiteID);
$onLive = Versioned::get_one_by_stage('SubsitesVirtualPage', 'Live', "\"SiteTree_Live\".\"ID\" = ".$vp2->ID);
$this->assertNull($onLive, 'SVP has been removed from live');
}
/**
* Similar to {@link SiteTreeSubsitesTest->testTwoPagesWithSameURLOnDifferentSubsites()}
* and {@link SiteTreeSubsitesTest->testPagesInDifferentSubsitesCanShareURLSegment()}.
@ -245,11 +245,11 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$subsite1 = $this->objFromFixture('Subsite', 'subsite1');
$subsite2 = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($subsite1->ID);
$subsite1Page = $this->objFromFixture('Page', 'subsite1_staff');
$subsite1Page->URLSegment = 'staff';
$subsite1Page->write();
// saving on subsite1, and linking to subsite1
$subsite1Vp = new SubsitesVirtualPage();
$subsite1Vp->CopyContentFromID = $subsite1Page->ID;
@ -260,11 +260,11 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$subsite1Page->URLSegment,
"Doesn't allow explicit URLSegment overrides when already existing in same subsite"
);
//Change to subsite 2
Subsite::changeSubsite($subsite2->ID);
// saving in subsite2 (which already has a page with URLSegment 'contact-us'),
// saving in subsite2 (which already has a page with URLSegment 'contact-us'),
// but linking to a page in subsite1
$subsite2Vp = new SubsitesVirtualPage();
$subsite2Vp->CopyContentFromID = $subsite1Page->ID;
@ -274,6 +274,16 @@ class SubsitesVirtualPageTest extends BaseSubsiteTest
$subsite2Vp->URLSegment,
$subsite1Page->URLSegment,
"Does allow explicit URLSegment overrides when only existing in a different subsite"
);
// When changing subsites and re-saving this page, it doesn't trigger a change
Subsite::changeSubsite($subsite1->ID);
$subsite1Page->write();
$subsite2Vp->write();
$this->assertEquals(
$subsite2Vp->URLSegment,
$subsite1Page->URLSegment,
"SubsiteVirtualPage doesn't change urls when being written in another subsite"
);
}