2007-08-16 08:38:29 +02:00
< ? php
/**
* Extension for the SiteTree object to add subsites support
*/
2012-03-25 18:35:01 +02:00
class SiteTreeSubsites extends DataExtension {
2007-08-16 08:38:29 +02:00
2012-04-26 01:42:05 +02:00
public static $has_one = array (
2009-06-22 14:03:04 +02:00
'Subsite' => 'Subsite' , // The subsite that this page belongs to
2010-03-01 04:01:50 +01:00
'MasterPage' => 'SiteTree' , // Optional; the page that is the content master
2012-07-10 15:43:53 +02:00
);
2012-04-26 01:42:05 +02:00
public static $has_many = array (
2010-03-01 04:15:07 +01:00
'RelatedPages' => 'RelatedPageLink'
2012-07-10 15:43:53 +02:00
);
2012-04-26 01:42:05 +02:00
public static $many_many = array (
2010-03-01 04:15:07 +01:00
'CrossSubsiteLinkTracking' => 'SiteTree' // Stored separately, as the logic for URL rewriting is different
2012-07-10 15:43:53 +02:00
);
2012-04-26 01:42:05 +02:00
public static $belongs_many_many = array (
2010-03-01 04:15:07 +01:00
'BackCrossSubsiteLinkTracking' => 'SiteTree'
2009-06-22 14:03:04 +02:00
);
2012-07-10 15:43:53 +02:00
public static $many_many_extraFields = array (
" CrossSubsiteLinkTracking " => array ( " FieldName " => " Varchar " )
);
2007-08-16 08:38:29 +02:00
2010-06-28 23:40:36 +02:00
function isMainSite () {
if ( $this -> owner -> SubsiteID == 0 ) return true ;
return false ;
}
2007-08-16 08:38:29 +02:00
/**
* Update any requests to limit the results to the current site
*/
function augmentSQL ( SQLQuery & $query ) {
2007-09-05 06:47:05 +02:00
if ( Subsite :: $disable_subsite_filter ) return ;
2010-03-02 02:15:11 +01:00
// Don't run on delete queries, since they are always tied to
// a specific ID.
2012-04-25 14:29:32 +02:00
if ( $query -> getDelete ()) return ;
2009-10-29 02:40:46 +01:00
2007-08-16 08:38:29 +02:00
// If you're querying by ID, ignore the sub-site - this is a bit ugly...
2010-03-02 02:15:11 +01:00
// 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)) {
2010-03-01 03:56:01 +01:00
if ( ! $query -> where || ( ! preg_match ( '/\.(\'|"|`|)ID(\'|"|`|)( ?)=/' , $query -> where [ 0 ]))) {
2010-03-02 02:15:11 +01:00
2010-03-01 22:56:24 +01:00
if ( Subsite :: $force_subsite ) $subsiteID = Subsite :: $force_subsite ;
else {
2012-03-25 18:35:01 +02:00
/* if ( $context = DataObject :: context_obj ()) $subsiteID = ( int ) $context -> SubsiteID ;
else */ $subsiteID = ( int ) Subsite :: currentSubsiteID ();
2010-03-01 22:56:24 +01:00
}
2007-08-29 08:03:57 +02:00
2007-08-16 08:38:29 +02:00
// The foreach is an ugly way of getting the first key :-)
2012-04-25 14:29:32 +02:00
foreach ( $query -> getFrom () as $tableName => $info ) {
2007-11-06 04:06:02 +01:00
// The tableName should be SiteTree or SiteTree_Live...
if ( strpos ( $tableName , 'SiteTree' ) === false ) break ;
2012-04-25 14:29:32 +02:00
$query -> addWhere ( " \" $tableName\ " . \ " SubsiteID \" IN ( $subsiteID ) " );
2007-08-16 08:38:29 +02:00
break ;
}
}
}
2010-03-02 02:15:11 +01:00
function onBeforeWrite () {
if ( ! $this -> owner -> ID && ! $this -> owner -> SubsiteID ) $this -> owner -> SubsiteID = Subsite :: currentSubsiteID ();
parent :: onBeforeWrite ();
2007-08-16 08:38:29 +02:00
}
2012-04-25 14:29:32 +02:00
function updateCMSFields ( FieldList $fields ) {
2012-08-10 11:23:19 +02:00
$subsites = Subsite :: accessible_sites ( " CMS_ACCESS_CMSMain " );
$subsitesMap = array ();
if ( $subsites && $subsites -> Count ()) {
2013-01-03 17:38:51 +01:00
$subsitesMap = $subsites -> map ( 'ID' , 'Title' );
2012-08-10 11:23:19 +02:00
unset ( $subsitesMap [ $this -> owner -> SubsiteID ]);
}
// Master page notice
if ( $this -> owner -> MasterPageID ) {
$masterPage = $this -> owner -> MasterPage ();
$masterNoteField = new LiteralField (
'MasterLink' ,
sprintf (
_t (
'SiteTreeSubsites.MasterLinkNote' ,
'<p>This page\'s content is copied from the <a href="%s" target="_blank">%s</a> master page (<a href="%s">edit</a>)</p>'
),
$masterPage -> AbsoluteLink (),
$masterPage -> Title ,
Controller :: join_links (
singleton ( 'CMSMain' ) -> Link ( 'show' ),
$masterPage -> ID
)
)
);
2013-01-03 17:38:51 +01:00
$fields -> addFieldToTab ( 'Root.Main' , $masterNoteField );
2012-08-10 11:23:19 +02:00
}
// Master page edit field (only allowed from default subsite to avoid inconsistent relationships)
$isDefaultSubsite = $this -> owner -> SubsiteID == 0 || $this -> owner -> Subsite () -> DefaultSite ;
if ( $isDefaultSubsite && $subsitesMap ) {
$fields -> addFieldToTab (
2013-01-03 17:38:51 +01:00
'Root.Main' ,
2012-08-10 11:23:19 +02:00
new DropdownField (
" CopyToSubsiteID " ,
_t ( 'SiteTreeSubsites.CopyToSubsite' , " Copy page to subsite " ),
$subsitesMap ,
''
)
);
$fields -> addFieldToTab (
2013-01-03 17:38:51 +01:00
'Root.Main' ,
2012-08-10 11:23:19 +02:00
$copyAction = new InlineFormAction (
" copytosubsite " ,
_t ( 'SiteTreeSubsites.CopyAction' , " Copy " )
)
);
$copyAction -> includeDefaultJS ( false );
} else {
$defaultSubsite = DataObject :: get_one ( 'Subsite' , '"DefaultSite" = 1' );
if ( $defaultSubsite ) {
2013-01-03 17:38:51 +01:00
$fields -> addFieldToTab ( 'Root.Main' ,
2012-08-10 11:23:19 +02:00
$masterPageField = new SubsitesTreeDropdownField (
" MasterPageID " ,
_t ( 'VirtualPage.MasterPage' , " Master page " ),
" SiteTree " ,
" ID " ,
" MenuTitle "
)
);
$masterPageField -> setSubsiteID ( $defaultSubsite -> ID );
}
}
2008-12-02 05:06:58 +01:00
// replace readonly link prefix
$subsite = $this -> owner -> Subsite ();
if ( $subsite && $subsite -> ID ) {
$baseUrl = 'http://' . $subsite -> domain () . '/' ;
2012-07-10 15:43:53 +02:00
$baseLink = Controller :: join_links (
$baseUrl ,
( SiteTree :: nested_urls () && $this -> owner -> ParentID ? $this -> owner -> Parent () -> RelativeLink ( true ) : null )
);
2012-07-11 15:32:10 +02:00
$url = ( strlen ( $baseLink ) > 36 ? " ... " . substr ( $baseLink , - 32 ) : $baseLink );
$urlsegment = $fields -> dataFieldByName ( 'URLSegment' );
2012-07-10 15:43:53 +02:00
$urlsegment -> setURLPrefix ( $url );
2008-12-02 05:06:58 +01:00
}
2010-03-01 04:01:50 +01:00
2010-03-01 04:15:07 +01:00
$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 );
2010-03-01 04:01:50 +01:00
// Related pages
2012-07-11 15:32:10 +02:00
$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>' ));
2010-03-01 04:15:07 +01:00
$tab -> push (
2012-03-25 18:35:01 +02:00
$related = new GridField ( 'RelatedPages' , 'Related Pages' , $this -> owner -> RelatedPages (), GridFieldConfig_Base :: create ())
2010-03-01 04:01:50 +01:00
);
2010-03-01 04:15:07 +01:00
2012-07-10 15:43:53 +02:00
$related -> setModelClass ( 'RelatedPageLink' );
2010-03-01 04:15:19 +01:00
// The 'show' link doesn't provide any useful info
2012-03-25 18:35:01 +02:00
//$related->setPermissions(array('add', 'edit', 'delete'));
2010-03-01 04:15:19 +01:00
2010-03-01 04:15:07 +01:00
if ( $reverse ) {
2010-03-01 23:26:56 +01:00
$text = '<p>In addition, this page is marked as related by the following pages: </p><p>' ;
2010-03-01 04:15:07 +01:00
foreach ( $reverse as $rpage ) {
2010-03-01 23:26:56 +01:00
$text .= $rpage -> RelatedPageAdminLink ( true ) . " - " . $rpage -> AbsoluteLink ( true ) . " <br /> \n " ;
2010-03-01 04:15:07 +01:00
}
2010-03-01 23:26:56 +01:00
$text .= '</p>' ;
2010-03-01 04:15:07 +01:00
$tab -> push ( new LiteralField ( 'ReverseRelated' , $text ));
}
}
2010-03-01 23:26:56 +01:00
/**
* Returns the RelatedPageLink objects that are reverse - associated with this page .
*/
2010-03-01 22:59:08 +01:00
function ReverseRelated () {
2010-03-01 23:27:10 +01:00
return DataObject :: get ( 'RelatedPageLink' , " \" RelatedPageLink \" . \" RelatedPageID \" = { $this -> owner -> ID }
2012-03-25 18:35:01 +02:00
AND R2 . \ " ID \" IS NULL " , '' )
2012-07-10 15:43:53 +02:00
-> innerJoin ( 'SiteTree' , " \" SiteTree \" . \" ID \" = \" RelatedPageLink \" . \" MasterPageID \" " )
-> leftJoin ( 'RelatedPageLink' , " R2. \" MasterPageID \" = { $this -> owner -> ID } AND R2. \" RelatedPageID \" = \" RelatedPageLink \" . \" MasterPageID \" " , 'R2' );
2010-03-01 22:59:08 +01:00
}
function NormalRelated () {
2012-03-25 18:35:01 +02:00
$return = new ArrayList ();
2010-04-30 00:58:10 +02:00
$links = DataObject :: get ( 'RelatedPageLink' , '"MasterPageID" = ' . $this -> owner -> ID );
2010-03-01 22:59:08 +01:00
if ( $links ) foreach ( $links as $link ) {
if ( $link -> RelatedPage () -> exists ()) {
$return -> push ( $link -> RelatedPage ());
}
}
return $return -> Count () > 0 ? $return : false ;
}
2010-03-01 23:27:21 +01:00
function alternateSiteConfig () {
2010-03-11 22:51:06 +01:00
if ( ! $this -> owner -> SubsiteID ) return false ;
2010-04-30 00:58:10 +02:00
$sc = DataObject :: get_one ( 'SiteConfig' , '"SubsiteID" = ' . $this -> owner -> SubsiteID );
2010-03-01 23:28:50 +01:00
if ( ! $sc ) {
$sc = new SiteConfig ();
$sc -> SubsiteID = $this -> owner -> SubsiteID ;
$sc -> Title = 'Your Site Name' ;
$sc -> Tagline = 'your tagline here' ;
$sc -> write ();
}
return $sc ;
2010-03-01 23:27:21 +01:00
}
2008-11-24 07:37:22 +01:00
/**
* 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 ) {
2010-08-23 02:07:05 +02:00
if ( ! $member ) $member = Member :: currentUser ();
2009-05-15 05:12:43 +02:00
2010-03-01 22:37:56 +01:00
// Find the sites that this user has access to
$goodSites = Subsite :: accessible_sites ( 'CMS_ACCESS_CMSMain' , true , 'all' , $member ) -> column ( 'ID' );
2008-11-26 05:03:14 +01:00
2010-03-01 22:37:56 +01:00
// Return true if they have access to this object's site
2010-08-23 02:07:05 +02:00
if ( ! ( in_array ( 0 , $goodSites ) || in_array ( $this -> owner -> SubsiteID , $goodSites ))) return false ;
2008-11-24 07:37:22 +01:00
}
/**
* @ return boolean
*/
function canDelete ( $member = null ) {
2008-11-26 05:03:14 +01:00
if ( ! $member && $member !== FALSE ) $member = Member :: currentUser ();
2008-11-24 07:37:22 +01:00
return $this -> canEdit ( $member );
}
/**
* @ return boolean
*/
function canAddChildren ( $member = null ) {
2008-11-26 05:03:14 +01:00
if ( ! $member && $member !== FALSE ) $member = Member :: currentUser ();
2008-11-24 07:37:22 +01:00
return $this -> canEdit ( $member );
}
/**
* @ return boolean
*/
function canPublish ( $member = null ) {
2008-11-26 05:03:14 +01:00
if ( ! $member && $member !== FALSE ) $member = Member :: currentUser ();
2008-11-24 07:37:22 +01:00
return $this -> canEdit ( $member );
}
2007-08-16 08:38:29 +02:00
/**
* Create a duplicate of this page and save it to another subsite
2007-08-29 00:29:44 +02:00
* @ param $subsiteID int | Subsite The Subsite to copy to , or its ID
2007-08-16 08:38:29 +02:00
*/
2012-08-07 17:37:44 +02:00
public function duplicateToSubsite ( $subsiteID = null ) {
2007-08-16 08:38:29 +02:00
if ( is_object ( $subsiteID )) {
$subsite = $subsiteID ;
$subsiteID = $subsite -> ID ;
2010-03-31 00:50:37 +02:00
} else $subsite = DataObject :: get_by_id ( 'Subsite' , $subsiteID );
2007-08-16 08:38:29 +02:00
2012-07-16 01:14:13 +02:00
$oldSubsite = Subsite :: currentSubsiteID ();
if ( $subsiteID ) {
Subsite :: changeSubsite ( $subsiteID );
} else {
$subsiteID = $oldSubsite ;
}
2007-08-16 08:38:29 +02:00
$page = $this -> owner -> duplicate ( false );
$page -> CheckedPublicationDifferences = $page -> AddedToStage = true ;
2012-07-11 15:32:10 +02:00
$subsiteID = ( $subsiteID ? $subsiteID : $oldSubsite );
2007-08-16 08:38:29 +02:00
$page -> SubsiteID = $subsiteID ;
2012-08-07 17:37:44 +02:00
$page -> MasterPageID = $this -> owner -> ID ;
2007-08-16 08:38:29 +02:00
$page -> write ();
2012-07-16 01:14:13 +02:00
Subsite :: changeSubsite ( $oldSubsite );
2007-08-16 08:38:29 +02:00
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 );
2008-11-20 00:25:43 +01:00
$subsite = Subsite :: currentSubsite ();
if ( $subsite && $subsite -> Theme ) SSViewer :: set_theme ( Subsite :: currentSubsite () -> Theme );
2007-08-16 08:38:29 +02:00
}
/**
* 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 );
}
2007-09-05 08:42:57 +02:00
function alternateAbsoluteLink () {
2009-06-18 06:53:14 +02:00
// 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 ());
2010-03-01 03:53:15 +01:00
if ( $this -> owner -> SubsiteID ) {
$url = preg_replace ( '/\/\/[^\/]+\//' , '//' . $this -> owner -> Subsite () -> domain () . '/' , $url );
}
return $url ;
2007-09-05 08:42:57 +02:00
}
2010-03-01 22:59:08 +01:00
2010-03-01 04:15:07 +01:00
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
2011-09-12 12:18:56 +02:00
$origDisableSubsiteFilter = Subsite :: $disable_subsite_filter ;
2010-03-01 04:15:07 +01:00
Subsite :: disable_subsite_filter ( true );
$candidatePage = DataObject :: get_one ( " SiteTree " , " \" URLSegment \" = ' " . urldecode ( $rest ) . " ' AND \" SubsiteID \" = " . $subsiteID , false );
2011-09-12 12:18:56 +02:00
Subsite :: disable_subsite_filter ( $origDisableSubsiteFilter );
2010-03-01 04:15:07 +01:00
if ( $candidatePage ) {
$linkedPages [] = $candidatePage -> ID ;
} else {
$this -> owner -> HasBrokenLink = true ;
}
}
}
}
$this -> owner -> CrossSubsiteLinkTracking () -> setByIDList ( $linkedPages );
}
2010-03-01 23:32:15 +01:00
/**
* Return a piece of text to keep DataObject cache keys appropriately specific
*/
function cacheKeyComponent () {
return 'subsite-' . Subsite :: currentSubsiteID ();
}
2011-08-30 18:58:36 +02:00
/**
* @ 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 ;
}
}
}