mirror of
https://github.com/silverstripe/silverstripe-subsites
synced 2024-10-22 11:05:55 +02:00
c9d3a1f854
Fixes for SS 3.0 beta 3 Fixed compatibility issues with ss3.0 rc1 fixed potential issue caused by the from array format changing in 3.0 Fixed strict standards warnings Fixed strict notice "Only variables should be passed by reference" Fixed strict notice "Only variables should be passed by reference" Fixed strict notice caused by SubsiteAdmin not declaring all of the properties for getCMSFields() Made Subsite::accessible_sites() static Fixed issue caused when trying to add a domain before saving for the first time Fixed undefined property ParentID
327 lines
11 KiB
PHP
327 lines
11 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Extension for the SiteTree object to add subsites support
|
|
*/
|
|
class SiteTreeSubsites extends DataExtension {
|
|
static $template_variables = array(
|
|
'((Company Name))' => 'Title'
|
|
);
|
|
|
|
static $template_fields = array(
|
|
"URLSegment",
|
|
"Title",
|
|
"MenuTitle",
|
|
"Content",
|
|
"MetaTitle",
|
|
"MetaDescription",
|
|
"MetaKeywords",
|
|
);
|
|
|
|
/**
|
|
* Set the fields that will be copied from the template.
|
|
* Note that ParentID and Sort are implied.
|
|
*/
|
|
static function set_template_fields($fieldList) {
|
|
self::$template_fields = $fieldList;
|
|
}
|
|
|
|
|
|
public static $has_one=array(
|
|
'Subsite' => 'Subsite', // The subsite that this page belongs to
|
|
'MasterPage' => 'SiteTree',// Optional; the page that is the content master
|
|
);
|
|
|
|
public static $has_many=array(
|
|
'RelatedPages' => 'RelatedPageLink'
|
|
);
|
|
|
|
public static $many_many=array(
|
|
'CrossSubsiteLinkTracking' => 'SiteTree' // Stored separately, as the logic for URL rewriting is different
|
|
);
|
|
|
|
public static $belongs_many_many=array(
|
|
'BackCrossSubsiteLinkTracking' => 'SiteTree'
|
|
);
|
|
|
|
public static $many_many_extraFields=array(
|
|
"CrossSubsiteLinkTracking" => array("FieldName" => "Varchar")
|
|
);
|
|
|
|
function isMainSite() {
|
|
if($this->owner->SubsiteID == 0) return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Update any requests to limit the results to the current site
|
|
*/
|
|
function augmentSQL(SQLQuery &$query) {
|
|
if(Subsite::$disable_subsite_filter) return;
|
|
|
|
// Don't run on delete queries, since they are always tied to
|
|
// a specific ID.
|
|
if ($query->getDelete()) 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->where || (!preg_match('/\.(\'|"|`|)ID(\'|"|`|)( ?)=/', $query->where[0]))) {
|
|
|
|
if (Subsite::$force_subsite) $subsiteID = Subsite::$force_subsite;
|
|
else {
|
|
/*if($context = DataObject::context_obj()) $subsiteID = (int)$context->SubsiteID;
|
|
else */$subsiteID = (int)Subsite::currentSubsiteID();
|
|
}
|
|
|
|
// The foreach is an ugly way of getting the first key :-)
|
|
foreach($query->getFrom() as $tableName => $info) {
|
|
// The tableName should be SiteTree or SiteTree_Live...
|
|
if(strpos($tableName,'SiteTree') === false) break;
|
|
$query->addWhere("\"$tableName\".\"SubsiteID\" IN ($subsiteID)");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function onBeforeWrite() {
|
|
if(!$this->owner->ID && !$this->owner->SubsiteID) $this->owner->SubsiteID = Subsite::currentSubsiteID();
|
|
|
|
parent::onBeforeWrite();
|
|
}
|
|
|
|
function updateCMSFields(FieldList $fields) {
|
|
if($this->owner->MasterPageID) $fields->insertFirst(new HeaderField('This page\'s content is copied from a master page: ' . $this->owner->MasterPage()->Title, 2));
|
|
|
|
// replace readonly link prefix
|
|
$subsite = $this->owner->Subsite();
|
|
if($subsite && $subsite->ID) {
|
|
$baseUrl = 'http://' . $subsite->domain() . '/';
|
|
$fields->removeByName('URLSegment');
|
|
|
|
$baseLink = Controller::join_links (
|
|
$baseUrl,
|
|
(SiteTree::nested_urls() && $this->owner->ParentID ? $this->owner->Parent()->RelativeLink(true) : null)
|
|
);
|
|
|
|
$url = (strlen($baseLink) > 36) ? "..." .substr($baseLink, -32) : $baseLink;
|
|
$urlsegment = new SiteTreeURLSegmentField("URLSegment", $this->owner->fieldLabel('URLSegment'));
|
|
$urlsegment->setURLPrefix($url);
|
|
$urlsegment->setHelpText(SiteTree::nested_urls() && count($this->owner->Children()) ? $this->owner->fieldLabel('LinkChangeNote'): false);
|
|
$fields->addFieldToTab('Root.Metadata', $urlsegment, 'MetaTitle');
|
|
}
|
|
|
|
$relatedCount = 0;
|
|
$reverse = $this->ReverseRelated();
|
|
if($reverse) $relatedCount += $reverse->Count();
|
|
$normalRelated = $this->NormalRelated();
|
|
if($normalRelated) $relatedCount += $normalRelated->Count();
|
|
|
|
$tabName = $relatedCount ? 'Related (' . $relatedCount . ')' : 'Related';
|
|
$tab = $fields->findOrMakeTab('Root.Related', $tabName);
|
|
// Related pages
|
|
$tab->push(new LiteralField('RelatedNote', '<p>You can list pages here that are related to this page.<br />When this page is updated, you will get a reminder to check whether these related pages need to be updated as well.</p>'));
|
|
$tab->push(
|
|
$related=new GridField('RelatedPages', 'Related Pages', $this->owner->RelatedPages(), GridFieldConfig_Base::create())
|
|
);
|
|
|
|
$related->setModelClass('RelatedPageLink');
|
|
|
|
// The 'show' link doesn't provide any useful info
|
|
//$related->setPermissions(array('add', 'edit', 'delete'));
|
|
|
|
if($reverse) {
|
|
$text = '<p>In addition, this page is marked as related by the following pages: </p><p>';
|
|
foreach($reverse as $rpage) {
|
|
$text .= $rpage->RelatedPageAdminLink(true) . " - " . $rpage->AbsoluteLink(true) . "<br />\n";
|
|
}
|
|
$text .= '</p>';
|
|
|
|
$tab->push(new LiteralField('ReverseRelated', $text));
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the RelatedPageLink objects that are reverse-associated with this page.
|
|
*/
|
|
function ReverseRelated() {
|
|
return DataObject::get('RelatedPageLink', "\"RelatedPageLink\".\"RelatedPageID\" = {$this->owner->ID}
|
|
AND R2.\"ID\" IS NULL", '')
|
|
->innerJoin('SiteTree', "\"SiteTree\".\"ID\" = \"RelatedPageLink\".\"MasterPageID\"")
|
|
->leftJoin('RelatedPageLink', "R2.\"MasterPageID\" = {$this->owner->ID} AND R2.\"RelatedPageID\" = \"RelatedPageLink\".\"MasterPageID\"", 'R2');
|
|
}
|
|
|
|
function NormalRelated() {
|
|
$return = new ArrayList();
|
|
$links = DataObject::get('RelatedPageLink', '"MasterPageID" = ' . $this->owner->ID);
|
|
if($links) foreach($links as $link) {
|
|
if($link->RelatedPage()->exists()) {
|
|
$return->push($link->RelatedPage());
|
|
}
|
|
}
|
|
|
|
return $return->Count() > 0 ? $return : false;
|
|
}
|
|
|
|
function alternateSiteConfig() {
|
|
if(!$this->owner->SubsiteID) return false;
|
|
$sc = DataObject::get_one('SiteConfig', '"SubsiteID" = ' . $this->owner->SubsiteID);
|
|
if(!$sc) {
|
|
$sc = new SiteConfig();
|
|
$sc->SubsiteID = $this->owner->SubsiteID;
|
|
$sc->Title = 'Your Site Name';
|
|
$sc->Tagline = 'your tagline here';
|
|
$sc->write();
|
|
}
|
|
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
|
|
*/
|
|
function canEdit($member = null) {
|
|
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');
|
|
|
|
// Return true if they have access to this object's site
|
|
if(!(in_array(0, $goodSites) || in_array($this->owner->SubsiteID, $goodSites))) return false;
|
|
}
|
|
|
|
/**
|
|
* @return boolean
|
|
*/
|
|
function canDelete($member = null) {
|
|
if(!$member && $member !== FALSE) $member = Member::currentUser();
|
|
|
|
return $this->canEdit($member);
|
|
}
|
|
|
|
/**
|
|
* @return boolean
|
|
*/
|
|
function canAddChildren($member = null) {
|
|
if(!$member && $member !== FALSE) $member = Member::currentUser();
|
|
|
|
return $this->canEdit($member);
|
|
}
|
|
|
|
/**
|
|
* @return boolean
|
|
*/
|
|
function canPublish($member = null) {
|
|
if(!$member && $member !== FALSE) $member = Member::currentUser();
|
|
|
|
return $this->canEdit($member);
|
|
}
|
|
|
|
/**
|
|
* Create a duplicate of this page and save it to another subsite
|
|
* @param $subsiteID int|Subsite The Subsite to copy to, or its ID
|
|
* @param $isTemplate boolean If this is true, then the current page will be treated as the template, and MasterPageID will be set
|
|
*/
|
|
public function duplicateToSubsite($subsiteID = null, $isTemplate = true) {
|
|
if(is_object($subsiteID)) {
|
|
$subsite = $subsiteID;
|
|
$subsiteID = $subsite->ID;
|
|
} else $subsite = DataObject::get_by_id('Subsite', $subsiteID);
|
|
|
|
$page = $this->owner->duplicate(false);
|
|
|
|
$page->CheckedPublicationDifferences = $page->AddedToStage = true;
|
|
$subsiteID = ($subsiteID ? $subsiteID : Subsite::currentSubsiteID());
|
|
$page->SubsiteID = $subsiteID;
|
|
|
|
if($isTemplate) $page->MasterPageID = $this->owner->ID;
|
|
|
|
$page->write();
|
|
|
|
return $page;
|
|
}
|
|
|
|
/**
|
|
* Called by ContentController::init();
|
|
*/
|
|
static function contentcontrollerInit($controller) {
|
|
// Need to set the SubsiteID to null incase we've been in the CMS
|
|
Session::set('SubsiteID', null);
|
|
$subsite = Subsite::currentSubsite();
|
|
if($subsite && $subsite->Theme) SSViewer::set_theme(Subsite::currentSubsite()->Theme);
|
|
}
|
|
|
|
/**
|
|
* Called by ModelAsController::init();
|
|
*/
|
|
static function modelascontrollerInit($controller) {
|
|
// Need to set the SubsiteID to null incase we've been in the CMS
|
|
Session::set('SubsiteID', null);
|
|
}
|
|
|
|
function alternateAbsoluteLink() {
|
|
// Generate the existing absolute URL and replace the domain with the subsite domain.
|
|
// This helps deal with Link() returning an absolute URL.
|
|
$url = Director::absoluteURL($this->owner->Link());
|
|
if($this->owner->SubsiteID) {
|
|
$url = preg_replace('/\/\/[^\/]+\//', '//' . $this->owner->Subsite()->domain() . '/', $url);
|
|
}
|
|
return $url;
|
|
}
|
|
|
|
function augmentSyncLinkTracking() {
|
|
// Set LinkTracking appropriately
|
|
$links = HTTP::getLinksIn($this->owner->Content);
|
|
$linkedPages = array();
|
|
|
|
if($links) foreach($links as $link) {
|
|
if(substr($link, 0, strlen('http://')) == 'http://') {
|
|
$withoutHttp = substr($link, strlen('http://'));
|
|
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; // We have no idea what the domain for the main site is, so cant track links to it
|
|
|
|
$origDisableSubsiteFilter = Subsite::$disable_subsite_filter;
|
|
Subsite::disable_subsite_filter(true);
|
|
$candidatePage = DataObject::get_one("SiteTree", "\"URLSegment\" = '" . urldecode( $rest). "' AND \"SubsiteID\" = " . $subsiteID, false);
|
|
Subsite::disable_subsite_filter($origDisableSubsiteFilter);
|
|
|
|
if($candidatePage) {
|
|
$linkedPages[] = $candidatePage->ID;
|
|
} else {
|
|
$this->owner->HasBrokenLink = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->owner->CrossSubsiteLinkTracking()->setByIDList($linkedPages);
|
|
}
|
|
|
|
/**
|
|
* Return a piece of text to keep DataObject cache keys appropriately specific
|
|
*/
|
|
function cacheKeyComponent() {
|
|
return 'subsite-'.Subsite::currentSubsiteID();
|
|
}
|
|
|
|
/**
|
|
* @param Member
|
|
* @return boolean|null
|
|
*/
|
|
function canCreate($member = null) {
|
|
// Typically called on a singleton, so we're not using the Subsite() relation
|
|
$subsite = Subsite::currentSubsite();
|
|
if($subsite && $subsite->exists() && $subsite->PageTypeBlacklist) {
|
|
$blacklisted = explode(',', $subsite->PageTypeBlacklist);
|
|
// All subclasses need to be listed explicitly
|
|
if(in_array($this->owner->class, $blacklisted)) return false;
|
|
}
|
|
}
|
|
} |