2007-08-18 13:38:11 +02:00
< ? php
/**
* A dynamically created subdomain . SiteTree objects can now belong to a subdomain
*/
2007-08-27 07:07:27 +02:00
class Subsite extends DataObject implements PermissionProvider {
2007-09-05 06:47:05 +02:00
static $disable_subsite_filter = false ;
2007-08-18 13:38:11 +02:00
static $default_sort = 'Title' ;
static $use_domain = false ;
static $db = array (
'Subdomain' => 'Varchar' ,
'Title' => 'Varchar(255)' ,
'RedirectURL' => 'Varchar(255)' ,
'DefaultSite' => 'Boolean' ,
'Theme' => 'Varchar' ,
'Domain' => 'Varchar' ,
'IsPublic' => 'Boolean'
);
2008-06-19 02:46:51 +02:00
static $has_one = array (
);
2007-08-18 13:38:11 +02:00
static $indexes = array (
'Subdomain' => true ,
'Domain' => true
);
2008-06-24 04:31:26 +02:00
static $defaults = array (
'IsPublic' => 1 ,
);
2007-08-18 13:38:11 +02:00
2008-11-24 05:47:37 +01:00
static $base_domain , $default_subdomain ;
static $cached_subsite = null ;
2007-08-18 13:38:11 +02:00
2008-06-24 04:31:26 +02:00
public static $allowed_domains = array ();
protected static $allowed_themes = array ();
2007-08-27 07:07:27 +02:00
2008-04-22 08:53:35 +02:00
static function set_allowed_domains ( $domain ){
if ( is_array ( $domain )){
foreach ( $domain as $do ){
2008-11-24 05:47:37 +01:00
Subsite :: set_allowed_domains ( $do );
2008-04-22 08:53:35 +02:00
}
} else {
self :: $allowed_domains [] = $domain ;
}
}
2008-06-24 04:31:26 +02:00
static function set_allowed_themes ( $themes ) {
self :: $allowed_themes = $themes ;
}
2008-11-20 00:25:43 +01:00
/**
* Return the themes that can be used with this subsite , as an array of themecode => description
*/
function allowedThemes () {
if ( $themes = $this -> stat ( 'allowed_themes' )) {
return ArrayLib :: valuekey ( $themes );
} else {
$themes = array ();
foreach ( scandir ( '../themes/' ) as $theme ) {
if ( $theme [ 0 ] == '.' ) continue ;
$theme = strtok ( $theme , '_' );
$themes [ $theme ] = $theme ;
}
ksort ( $themes );
return $themes ;
}
}
2007-08-18 13:38:11 +02:00
/**
* Return the base domain for this set of subsites .
2008-11-24 05:47:37 +01:00
* You can set this by setting Subsite :: $Base_domain , otherwise it defaults to HTTP_HOST
2007-08-18 13:38:11 +02:00
*/
static function base_domain () {
if ( self :: $base_domain ) return self :: $base_domain ;
else return $_SERVER [ 'HTTP_HOST' ];
}
/**
* Return the default domain of this set of subsites . Generally this will be the base domain ,
2008-11-24 05:47:37 +01:00
* but hyou can also set Subsite :: $default_subdomain to add a default prefix to this
2007-08-18 13:38:11 +02:00
*/
static function default_domain () {
if ( self :: $default_subdomain ) return self :: $default_subdomain . '.' . self :: base_domain ();
else return self :: base_domain ();
}
/**
* Return the domain of this site
*/
function domain () {
$base = $this -> Domain ? $this -> Domain : self :: base_domain ();
$sub = $this -> Subdomain ? $this -> Subdomain : self :: $default_subdomain ;
if ( $sub ) return " $sub . $base " ;
else return $base ;
}
2008-11-24 05:47:37 +01:00
// Show the configuration fields for each subsite
2007-08-18 13:38:11 +02:00
function getCMSFields () {
$fields = new FieldSet (
new TabSet ( 'Root' ,
new Tab ( 'Configuration' ,
new HeaderField ( $this -> getClassName () . ' configuration' , 2 ),
new TextField ( 'Title' , 'Name of subsite:' , $this -> Title ),
2007-08-27 07:07:27 +02:00
new FieldGroup ( 'URL' ,
2008-11-24 05:47:37 +01:00
new TextField ( 'Subdomain' , " " , $this -> Subdomain ),
new DropdownField ( 'Domain' , '.' , ArrayLib :: valuekey ( $this -> stat ( 'allowed_domains' )), $this -> Domain )
2007-08-27 07:07:27 +02:00
),
2007-08-18 13:38:11 +02:00
// new TextField('RedirectURL', 'Redirect to URL', $this->RedirectURL),
2008-11-24 05:47:37 +01:00
new CheckboxField ( 'DefaultSite' , 'Use this subsite as the default site' , $this -> DefaultSite ),
new CheckboxField ( 'IsPublic' , 'Can access this subsite publicly?' , $this -> IsPublic ),
2008-06-24 04:31:26 +02:00
2008-11-20 00:25:43 +01:00
new DropdownField ( 'Theme' , 'Theme' , $this -> allowedThemes (), $this -> Theme )
2007-08-18 13:38:11 +02:00
)
),
new HiddenField ( 'ID' , '' , $this -> ID ),
new HiddenField ( 'IsSubsite' , '' , 1 )
);
// This code needs to be updated to reference the new SS 2.0.3 theme system
/* if ( $themes = SSViewer :: getThemes ( false ))
$fields -> addFieldsToTab ( 'Root.Configuration' , new DropdownField ( 'Theme' , 'Theme:' , $themes , $this -> Theme ));
*/
2008-06-19 02:46:51 +02:00
2008-07-15 01:48:37 +02:00
$this -> extend ( 'updateCMSFields' , $fields );
2007-08-18 13:38:11 +02:00
return $fields ;
}
function getClassName () {
return $this -> class ;
}
function getCMSActions () {
return new FieldSet (
2007-08-29 00:29:44 +02:00
new FormAction ( 'callPageMethod' , " Create copy " , null , 'adminDuplicate' )
2007-08-18 13:38:11 +02:00
);
}
2007-08-29 00:29:44 +02:00
function adminDuplicate () {
$newItem = $this -> duplicate ();
$JS_title = Convert :: raw2js ( $this -> Title );
return <<< JS
statusMessage ( 'Created a copy of $JS_title' , 'good' );
$ ( 'Form_EditForm' ) . loadURLFromServer ( 'admin/subsites/show/$newItem->ID' );
JS ;
}
2008-11-24 05:47:37 +01:00
static function currentSubsite () {
if ( ! self :: $cached_subsite ) self :: $cached_subsite = DataObject :: get_by_id ( 'Subsite' , self :: currentSubsiteID ());
2007-08-18 13:38:11 +02:00
return self :: $cached_subsite ;
}
/**
* This function gets the current subsite ID from the session . It used in the backend so Ajax requests
* use the correct subsite . The frontend handles subsites differently . It calls getSubsiteIDForDomain
2008-11-24 05:47:37 +01:00
* directly from ModelAsController :: getNestedController .
2007-08-18 13:38:11 +02:00
*/
2008-11-24 05:47:37 +01:00
static function currentSubsiteID () {
2007-08-18 13:38:11 +02:00
$id = Session :: get ( 'SubsiteID' );
2008-11-24 05:47:37 +01:00
if ( $id === null ) Session :: set ( 'SubsiteID' , $id = self :: getSubsiteIDForDomain ());
2007-08-18 13:38:11 +02:00
return ( int ) $id ;
}
static function create ( $name ) {
$newSubsite = Object :: create ( 'Subsite' );
$newSubsite -> Title = $name ;
$newSubsite -> Subdomain = str_replace ( ' ' , '-' , preg_replace ( '/[^0-9A-Za-z\s]/' , '' , strtolower ( trim ( $name ))));
$newSubsite -> write ();
$newSubsite -> createInitialRecords ();
return $newSubsite ;
}
/**
* Switch to another subsite
* @ param $subsite Either the ID of the subsite , or the subsite object itself
*/
static function changeSubsite ( $subsite ) {
// Debug::backtrace();
if ( ! $subsite ) {
Session :: set ( 'SubsiteID' , 0 );
return ;
}
if ( is_object ( $subsite ))
$subsite = $subsite -> ID ;
Session :: set ( 'SubsiteID' , $subsite );
/* if ( ! is_object ( $subsite ) && is_numeric ( $subsite ))
$subsite = DataObject :: get_by_id ( 'Subsite' , $subsite );
if ( $subsite )
Session :: set ( 'SubsiteID' , $subsite -> ID ); */
}
2007-08-31 02:29:25 +02:00
/**
* Make this subsite the current one
*/
public function activate () {
Subsite :: changeSubsite ( $this );
}
2007-08-18 13:38:11 +02:00
function canEdit () {
return true ;
}
static function getSubsiteIDForDomain () {
$domainNameParts = explode ( '.' , $_SERVER [ 'HTTP_HOST' ]);
2007-12-04 00:11:45 +01:00
if ( $domainNameParts [ 0 ] == 'www' ) array_shift ( $domainNameParts );
2007-08-18 13:38:11 +02:00
$SQL_subdomain = Convert :: raw2sql ( array_shift ( $domainNameParts ));
$SQL_domain = join ( '.' , Convert :: raw2sql ( $domainNameParts ));
2008-11-24 05:47:37 +01:00
// $_REQUEST['showqueries'] = 1;
2007-08-31 02:29:25 +02:00
$subsite = null ;
2007-08-18 13:38:11 +02:00
if ( self :: $use_domain ) {
$subsite = DataObject :: get_one ( 'Subsite' , " `Subdomain` = ' $SQL_subdomain ' AND `Domain`=' $SQL_domain ' AND `IsPublic`=1 " );
2007-08-31 02:29:25 +02:00
}
if ( ! $subsite ) {
2007-08-18 13:38:11 +02:00
$subsite = DataObject :: get_one ( 'Subsite' , " `Subdomain` = ' $SQL_subdomain ' AND `IsPublic`=1 " );
}
if ( $subsite ) {
// This will need to be updated to use the current theme system
// SSViewer::setCurrentTheme($subsite->Theme);
return $subsite -> ID ;
}
}
function getMembersByPermission ( $permissionCodes = array ( 'ADMIN' )){
if ( ! is_array ( $permissionCodes ))
user_error ( 'Permissions must be passed to Subsite::getMembersByPermission as an array' , E_USER_ERROR );
$SQL_permissionCodes = Convert :: raw2sql ( $permissionCodes );
$SQL_permissionCodes = join ( " ',' " , $SQL_permissionCodes );
$join = <<< SQL
LEFT JOIN `Group_Members` ON `Member` . `ID` = `Group_Members` . `MemberID`
LEFT JOIN `Group` ON `Group` . `ID` = `Group_Members` . `GroupID`
LEFT JOIN `Permission` ON `Permission` . `GroupID` = `Group` . `ID`
SQL ;
return DataObject :: get ( 'Member' , " `Group`.`SubsiteID` = $this->ID AND `Permission`.`Code` IN (' $SQL_permissionCodes ') " , '' , $join );
}
static function getSubsitesForMember ( $member = null , $permissionCodes = array ( 'ADMIN' )) {
if ( ! is_array ( $permissionCodes ))
user_error ( 'Permissions must be passed to Subsite::getSubsitesForMember as an array' , E_USER_ERROR );
if ( ! $member )
$member = Member :: currentMember ();
$memberID = ( int ) $member -> ID ;
$SQLa_permissionCodes = Convert :: raw2sql ( $permissionCodes );
$SQLa_permissionCodes = join ( " ',' " , $SQLa_permissionCodes );
if ( self :: hasMainSitePermission ( $member , $permissionCodes ))
return DataObject :: get ( 'Subsite' );
else
return DataObject :: get ( 'Subsite' , " `MemberID` = { $memberID } " . ( $permissionCodes ? " AND `Permission`.`Code` IN (' $SQLa_permissionCodes ') " : '' ), '' , " LEFT JOIN `Group` ON `Subsite`.`ID` = `SubsiteID` LEFT JOIN `Permission` ON `Group`.`ID` = `Permission`.`GroupID` LEFT JOIN `Group_Members` ON `Group`.`ID` = `Group_Members`.`GroupID` " );
}
2008-11-24 05:47:37 +01:00
/**
* Returns true if the given user is able to access the main site ( SubsiteID = 0 ) with the given permission code .
*/
2007-08-18 13:38:11 +02:00
static function hasMainSitePermission ( $member = null , $permissionCodes = array ( 'ADMIN' )) {
if ( ! is_array ( $permissionCodes ))
user_error ( 'Permissions must be passed to Subsite::hasMainSitePermission as an array' , E_USER_ERROR );
if ( ! $member )
2008-11-24 05:47:37 +01:00
$member = Member :: currentMember ();
if ( Permission :: checkMember ( $member , " ADMIN " )) return true ;
2007-08-18 13:38:11 +02:00
$SQLa_perm = Convert :: raw2sql ( $permissionCodes );
$SQL_perms = join ( " ',' " , $SQLa_perm );
$memberID = ( int ) $member -> ID ;
2007-08-21 00:37:43 +02:00
// `SubsiteID` = 0 AND
2008-11-24 05:47:37 +01:00
return DB :: query ( " SELECT COUNT(`Permission`.`ID`) FROM `Permission`
INNER JOIN `Group` ON `Group` . `ID` = `Permission` . `GroupID` AND `Group` . `SubsiteID` = 0
INNER JOIN `Group_Members` USING ( `GroupID` )
WHERE `Permission` . `Code` IN ( '$SQL_perms' ) AND `MemberID` = { $memberID } " )->value();
2007-08-18 13:38:11 +02:00
}
function createInitialRecords () {
}
2007-08-29 00:29:44 +02:00
/**
* Duplicate this subsite
*/
function duplicate () {
$newTemplate = parent :: duplicate ();
$oldSubsiteID = Session :: get ( 'SubsiteID' );
self :: changeSubsite ( $this -> ID );
/*
* Copy data from this template to the given subsite . Does this using an iterative depth - first search .
* This will make sure that the new parents on the new subsite are correct , and there are no funny
* issues with having to check whether or not the new parents have been added to the site tree
* when a page , etc , is duplicated
*/
$stack = array ( array ( 0 , 0 ));
while ( count ( $stack ) > 0 ) {
list ( $sourceParentID , $destParentID ) = array_pop ( $stack );
$children = Versioned :: get_by_stage ( 'Page' , 'Live' , " `ParentID`= $sourceParentID " , '' );
if ( $children ) {
foreach ( $children as $child ) {
$childClone = $child -> duplicateToSubsite ( $newTemplate , false );
$childClone -> ParentID = $destParentID ;
$childClone -> writeToStage ( 'Stage' );
$childClone -> publish ( 'Stage' , 'Live' );
array_push ( $stack , array ( $child -> ID , $childClone -> ID ));
}
}
}
self :: changeSubsite ( $oldSubsiteID );
return $newTemplate ;
2007-08-31 02:29:25 +02:00
}
/**
* Return the subsites that the current user can access .
* Look for one of the given permission codes on the site .
*
* @ param $permCode array | string Either a single permission code or an array of permission codes .
*/
function accessible_sites ( $permCode ) {
$member = Member :: currentUser ();
if ( is_array ( $permCode )) $SQL_codes = " ' " . implode ( " ', ' " , Convert :: raw2sql ( $permCode )) . " ' " ;
else $SQL_codes = " ' " . Convert :: raw2sql ( $permCode ) . " ' " ;
if ( ! $member ) return new DataObjectSet ();
$subsites = DataObject :: get ( 'Subsite' ,
2008-02-26 04:14:27 +01:00
" `Group_Members`.`MemberID` = $member->ID AND `Permission`.`Code` IN ( $SQL_codes , 'ADMIN') AND Subdomain IS NOT NULL AND `Subsite`.Title != '' " , '' ,
2007-08-31 02:29:25 +02:00
" LEFT JOIN `Group` ON (`SubsiteID`=`Subsite`.`ID` OR `SubsiteID` = 0) LEFT JOIN `Group_Members` ON `Group_Members`.`GroupID`=`Group`.`ID`
LEFT JOIN `Permission` ON `Group` . `ID` = `Permission` . `GroupID` " );
return $subsites ;
}
2007-08-18 13:38:11 +02:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CMS ADMINISTRATION HELPERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Return the FieldSet that will build the search form in the CMS
*/
function adminSearchFields () {
return new FieldSet (
new TextField ( 'Name' , 'Sub-site name' )
);
}
2007-08-27 07:07:27 +02:00
function providePermissions () {
return array (
'SUBSITE_EDIT' => 'Edit Sub-site Details' ,
);
}
2007-09-05 06:47:05 +02:00
static function get_from_all_subsites ( $className , $filter = " " , $sort = " " , $join = " " , $limit = " " ) {
self :: $disable_subsite_filter = true ;
$result = DataObject :: get ( $className , $filter , $sort , $join , $limit );
self :: $disable_subsite_filter = false ;
return $result ;
}
2008-08-21 07:50:38 +02:00
/**
* Disable the sub - site filtering ; queries will select from all subsites
*/
static function disable_subsite_filter ( $disabled = true ) {
self :: $disable_subsite_filter = $disabled ;
}
2007-08-18 13:38:11 +02:00
}
/**
* An instance of subsite that can be duplicated to provide a quick way to create new subsites .
*/
class Subsite_Template extends Subsite {
/**
* Create an instance of this template , with the given title & subdomain
*/
function createInstance ( $title , $subdomain ) {
$intranet = Object :: create ( 'Subsite' );
$intranet -> Title = $title ;
$intranet -> Domain = $this -> Domain ;
$intranet -> Subdomain = $subdomain ;
$intranet -> TemplateID = $this -> ID ;
$intranet -> write ();
$oldSubsiteID = Session :: get ( 'SubsiteID' );
self :: changeSubsite ( $this -> ID );
/*
* Copy data from this template to the given subsite . Does this using an iterative depth - first search .
* This will make sure that the new parents on the new subsite are correct , and there are no funny
* issues with having to check whether or not the new parents have been added to the site tree
* when a page , etc , is duplicated
*/
$stack = array ( array ( 0 , 0 ));
while ( count ( $stack ) > 0 ) {
list ( $sourceParentID , $destParentID ) = array_pop ( $stack );
$children = Versioned :: get_by_stage ( 'Page' , 'Live' , " `ParentID`= $sourceParentID " , '' );
if ( $children ) {
foreach ( $children as $child ) {
2007-08-29 00:29:44 +02:00
$childClone = $child -> duplicateToSubsite ( $intranet );
2007-08-18 13:38:11 +02:00
$childClone -> ParentID = $destParentID ;
$childClone -> writeToStage ( 'Stage' );
$childClone -> publish ( 'Stage' , 'Live' );
array_push ( $stack , array ( $child -> ID , $childClone -> ID ));
}
}
}
self :: changeSubsite ( $oldSubsiteID );
return $intranet ;
}
}
?>