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
static $template_variables = array (
'((Company Name))' => 'Title'
);
2007-09-05 06:47:05 +02:00
static $template_fields = array (
2007-08-16 08:38:29 +02:00
" URLSegment " ,
" Title " ,
" MenuTitle " ,
" Content " ,
" MetaTitle " ,
" MetaDescription " ,
" MetaKeywords " ,
);
2008-02-27 05:59:22 +01:00
2007-08-16 08:38:29 +02:00
/**
* 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 ;
}
2012-04-26 01:42:05 +02:00
public static $has_one = array (
2012-07-10 15:43:53 +02:00
'Subsite' => 'Subsite' , // The subsite that this page belongs to
'MasterPage' => 'SiteTree' , // Optional; the page that is the content master
);
2012-04-26 01:42:05 +02:00
public static $has_many = array (
2012-07-10 15:43:53 +02:00
'RelatedPages' => 'RelatedPageLink'
);
2012-04-26 01:42:05 +02:00
public static $many_many = array (
2012-07-10 15:43:53 +02:00
'CrossSubsiteLinkTracking' => 'SiteTree' // Stored separately, as the logic for URL rewriting is different
);
2012-04-26 01:42:05 +02:00
public static $belongs_many_many = array (
2012-07-10 15:43:53 +02:00
'BackCrossSubsiteLinkTracking' => 'SiteTree'
);
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 ) {
2010-03-31 00:50:37 +02:00
if ( $this -> owner -> MasterPageID ) $fields -> insertFirst ( new HeaderField ( 'This page\'s content is copied from a master page: ' . $this -> owner -> MasterPage () -> Title , 2 ));
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-03-25 18:35:01 +02:00
$fields -> removeByName ( 'URLSegment' );
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 )
);
$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' );
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
2010-03-01 04:15:07 +01: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>' ));
$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
* @ param $isTemplate boolean If this is true , then the current page will be treated as the template , and MasterPageID will be set
2007-08-16 08:38:29 +02:00
*/
2007-08-29 00:29:44 +02:00
public function duplicateToSubsite ( $subsiteID = null , $isTemplate = true ) {
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
$page = $this -> owner -> duplicate ( false );
$page -> CheckedPublicationDifferences = $page -> AddedToStage = true ;
$subsiteID = ( $subsiteID ? $subsiteID : Subsite :: currentSubsiteID ());
$page -> SubsiteID = $subsiteID ;
2007-08-29 00:29:44 +02:00
if ( $isTemplate ) $page -> MasterPageID = $this -> owner -> ID ;
2007-08-16 08:38:29 +02:00
$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 );
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 ;
}
}
}