1 <?php
2 3 4 5 6 7
8 class Subsite extends DataObject implements PermissionProvider {
9
10 11 12 13
14 static $disable_subsite_filter = false;
15
16 17 18 19
20 static $force_subsite = null;
21
22 static $write_hostmap = true;
23 static $default_sort = "\"Title\" ASC";
24
25 static $db = array(
26 'Title' => 'Varchar(255)',
27 'RedirectURL' => 'Varchar(255)',
28 'DefaultSite' => 'Boolean',
29 'Theme' => 'Varchar',
30 'Language' => 'Varchar(6)',
31
32
33
34 'IsPublic' => 'Boolean'
35 );
36
37 static $has_one = array(
38 );
39
40 static $has_many = array(
41 'Domains' => 'SubsiteDomain',
42 );
43
44 static $belongs_many_many = array(
45 "Groups" => "Group",
46 );
47
48 static $defaults = array(
49 'IsPublic' => 1
50 );
51
52 static $searchable_fields = array(
53 'Title' => array(
54 'title' => 'Subsite Name'
55 ),
56 'Domains.Domain' => array(
57 'title' => 'Domain name'
58 ),
59 'IsPublic' => array(
60 'title' => 'Active subsite',
61 ),
62 );
63
64 static $summary_fields = array(
65 'Title' => 'Subsite Name',
66 'PrimaryDomain' => 'Primary Domain',
67 'IsPublic' => 'Active subsite',
68 );
69
70
71 protected static $mainsite_language = 'ru_RU';
72
73 static function set_mainsite_language($val) {
74 self::$mainsite_language = $val;
75 }
76
77 static function get_mainsite_language() {
78 return self::$mainsite_language;
79 }
80
81
82 83 84 85 86
87 protected static $allowed_themes = array();
88
89 90 91
92 static $mainsite_domain = 'localhost';
93
94 static function set_mainsite_domain($domain){
95 self::$mainsite_domain = $domain;
96 }
97 static function get_mainsite_domain() {
98 return self::$mainsite_domain;
99 }
100
101 static function set_allowed_domains($domain){
102 user_error('Subsite::set_allowed_domains() is deprecated; it is no longer necessary '
103 . 'because users can now enter any domain name', E_USER_NOTICE);
104 }
105
106 static function set_allowed_themes($themes) {
107 self::$allowed_themes = $themes;
108 }
109
110 111 112
113 function allowedThemes() {
114 if($themes = $this->stat('allowed_themes')) {
115 return ArrayLib::valuekey($themes);
116 } else {
117 $themes = array();
118 $themes[''] = _t('Subsite.NotSelected');
119 if(is_dir('../themes/')) {
120 foreach(scandir('../themes/') as $theme) {
121 if($theme[0] == '.') continue;
122 $theme = strtok($theme,'_');
123 $themes[$theme] = $theme;
124 }
125 ksort($themes);
126 }
127 return $themes;
128 }
129 }
130
131 public function getLanguage() {
132 if($this->getField('Language')) {
133 return $this->getField('Language');
134 } else {
135 return i18n::get_locale();
136 }
137 }
138
139 function onBeforeDelete() {
140 parent::onBeforeDelete();
141
142 if ($this->Domains()->Count()) {
143 foreach($this->Domains() as $domain) {
144 $domain->delete();
145 }
146 }
147 }
148
149 150 151 152 153
154 public function onAfterWrite() {
155 Subsite::writeHostMap();
156 }
157
158 159 160 161 162
163 function domain() {
164 if($this->ID) {
165 $domains = DataObject::get("SubsiteDomain", "\"SubsiteID\" = $this->ID", "\"IsPrimary\" DESC",
166 "", 1);
167 if($domains) {
168 $domain = $domains->First()->Domain;
169
170
171 $domain = preg_replace("/\\.\\*\$/",".$_SERVER[HTTP_HOST]", $domain);
172 $domain = preg_replace("/^\\*\\./","subsite.", $domain);
173 $domain = str_replace('.www.','.', $domain);
174 return $domain;
175 }
176
177
178 } else {
179 return $_SERVER['HTTP_HOST'];
180 }
181 }
182
183 function getPrimaryDomain() {
184 return $this->domain();
185 }
186
187 function absoluteBaseURL() {
188 return "http://" . $this->domain() . Director::baseURL();
189 }
190
191 192 193
194 function getCMSFields() {
195 $domainTable = new TableField("Domains", "SubsiteDomain",
196 array("Domain" => "Domain (use * as a wildcard)", "IsPrimary" => "Primary domain?"),
197 array("Domain" => "TextField", "IsPrimary" => "CheckboxField"),
198 "SubsiteID", $this->ID);
199
200 $languageSelector = new DropdownField('Language', 'Language', i18n::get_common_locales());
201
202 $fields = new FieldSet(
203 new TabSet('Root',
204 new Tab('Configuration',
205 new HeaderField($this->getClassName() . ' configuration', 2),
206 new TextField('Title', 'Name of subsite:', $this->Title),
207
208 new HeaderField("Domains for this subsite"),
209 $domainTable,
210 $languageSelector,
211
212 new CheckboxField('DefaultSite', 'Default site', $this->DefaultSite),
213 new CheckboxField('IsPublic', 'Enable public access', $this->IsPublic),
214
215 new DropdownField('Theme','Theme', $this->allowedThemes(), $this->Theme)
216 )
217 ),
218 new HiddenField('ID', '', $this->ID),
219 new HiddenField('IsSubsite', '', 1)
220 );
221
222 $this->extend('updateCMSFields', $fields);
223 return $fields;
224 }
225
226 227 228
229 function getClassName() {
230 return $this->class;
231 }
232
233 function getCMSActions() {
234 return new FieldSet(
235 new FormAction('callPageMethod', "Create copy", null, 'adminDuplicate')
236 );
237 }
238
239 function adminDuplicate() {
240 $newItem = $this->duplicate();
241 $JS_title = Convert::raw2js($this->Title);
242 return <<<JS
243 statusMessage('Created a copy of $JS_title', 'good');
244 $('Form_EditForm').loadURLFromServer('admin/subsites/show/$newItem->ID');
245 JS;
246 }
247
248 249 250 251 252 253 254
255 static function currentSubsite() {
256
257 return DataObject::get_by_id('Subsite', self::currentSubsiteID());
258 }
259
260 261 262 263 264 265 266 267 268 269 270 271 272
273 static function currentSubsiteID() {
274 if(isset($_REQUEST['SubsiteID'])) $id = (int)$_REQUEST['SubsiteID'];
275 else $id = Session::get('SubsiteID');
276
277 if($id === NULL) {
278 $id = self::getSubsiteIDForDomain();
279 Session::set('SubsiteID', $id);
280 }
281
282 return (int)$id;
283 }
284
285 286 287 288 289
290 static function changeSubsite($subsite) {
291 if(is_object($subsite)) $subsiteID = $subsite->ID;
292 else $subsiteID = $subsite;
293
294 Session::set('SubsiteID', (int)$subsiteID);
295
296
297 if (is_object($subsite) && $subsite->Language != '') {
298 if (array_key_exists($subsite->Language, i18n::$common_locales)) {
299 i18n::set_locale($subsite->Language);
300 }
301 elseif (isset(i18n::$likely_subtags[$subsite->Language])) {
302 i18n::set_locale(i18n::$likely_subtags[$subsite->Language]);
303 }
304 }
305
306
307 if($subsiteID != self::currentSubsiteID()) Permission::flush_permission_cache();
308 }
309
310 311 312
313 public function activate() {
314 Subsite::changeSubsite($this);
315 }
316
317 318 319
320 function canEdit() {
321 return true;
322 }
323
324 public function Lang() {
325 return i18n::get_lang_from_locale($this->Language);
326 }
327
328 329 330 331 332 333 334 335
336 static function getSubsiteIDForDomain($host = null, $returnMainIfNotFound = true) {
337 if($host == null) $host = $_SERVER['HTTP_HOST'];
338
339 $host = str_replace('www.','',$host);
340 $SQL_host = Convert::raw2sql($host);
341
342 $matchingDomains = DataObject::get("SubsiteDomain", "'$SQL_host' LIKE replace(\"SubsiteDomain\".\"Domain\",'*','%')",
343 "\"IsPrimary\" DESC", "INNER JOIN \"Subsite\" ON \"Subsite\".\"ID\" = \"SubsiteDomain\".\"SubsiteID\" AND
344 \"Subsite\".\"IsPublic\"=1");
345
346 if($matchingDomains) {
347 $subsiteIDs = array_unique($matchingDomains->column('SubsiteID'));
348 if(sizeof($subsiteIDs) > 1) user_error("Multiple subsites match '$host'", E_USER_WARNING);
349 return $subsiteIDs[0];
350 }
351
352
353 if ($default = DataObject::get_one('Subsite', "\"DefaultSite\" = 1")) {
354 return $default->ID;
355 }
356
357
358 return 0;
359 }
360
361 function getMembersByPermission($permissionCodes = array('ADMIN')){
362 if(!is_array($permissionCodes))
363 user_error('Permissions must be passed to Subsite::getMembersByPermission as an array', E_USER_ERROR);
364 $SQL_permissionCodes = Convert::raw2sql($permissionCodes);
365
366 $SQL_permissionCodes = join("','", $SQL_permissionCodes);
367
368 return DataObject::get(
369 'Member',
370 "\"Group\".\"SubsiteID\" = $this->ID AND \"Permission\".\"Code\" IN ('$SQL_permissionCodes')",
371 '',
372 "LEFT JOIN \"Group_Members\" ON \"Member\".\"ID\" = \"Group_Members\".\"MemberID\"
373 LEFT JOIN \"Group\" ON \"Group\".\"ID\" = \"Group_Members\".\"GroupID\"
374 LEFT JOIN \"Permission\" ON \"Permission\".\"GroupID\" = \"Group\".\"ID\""
375 );
376
377 }
378
379 static function hasMainSitePermission($member = null, $permissionCodes = array('ADMIN')) {
380 if(!is_array($permissionCodes))
381 user_error('Permissions must be passed to Subsite::hasMainSitePermission as an array', E_USER_ERROR);
382
383 if(!$member && $member !== FALSE) $member = Member::currentMember();
384
385 if(!$member) return false;
386
387 if(!in_array("ADMIN", $permissionCodes)) $permissionCodes[] = "ADMIN";
388
389 $SQLa_perm = Convert::raw2sql($permissionCodes);
390 $SQL_perms = join("','", $SQLa_perm);
391 $memberID = (int)$member->ID;
392
393 $groupCount = DB::query("
394 SELECT COUNT(\"Permission\".\"ID\")
395 FROM \"Permission\"
396 INNER JOIN \"Group\" ON \"Group\".\"ID\" = \"Permission\".\"GroupID\" AND \"Group\".\"AccessAllSubsites\" = 1
397 INNER JOIN \"Group_Members\" ON \"Group_Members\".\"GroupID\" = \"Permission\".\"GroupID\"
398 WHERE \"Permission\".\"Code\" IN ('$SQL_perms')
399 AND \"MemberID\" = {$memberID}
400 ")->value();
401
402 return ($groupCount > 0);
403
404 }
405
406 407 408
409 function duplicate() {
410 $newTemplate = parent::duplicate();
411
412 $oldSubsiteID = Session::get('SubsiteID');
413 self::changeSubsite($this->ID);
414
415 416 417 418 419 420
421 $stack = array(array(0,0));
422 while(count($stack) > 0) {
423 list($sourceParentID, $destParentID) = array_pop($stack);
424
425 $children = Versioned::get_by_stage('Page', 'Live', "\"ParentID\" = $sourceParentID", '');
426
427 if($children) {
428 foreach($children as $child) {
429 $childClone = $child->duplicateToSubsite($newTemplate, false);
430 $childClone->ParentID = $destParentID;
431 $childClone->writeToStage('Stage');
432 $childClone->publish('Stage', 'Live');
433 array_push($stack, array($child->ID, $childClone->ID));
434 }
435 }
436 }
437
438 self::changeSubsite($oldSubsiteID);
439
440 return $newTemplate;
441 }
442
443
444 445 446 447 448 449 450 451 452 453
454 function accessible_sites($permCode, $includeMainSite = false, $mainSiteTitle = "Main site", $member = null) {
455
456 if(!$member) $member = Member::currentUser();
457 if(!$member) return new DataObjectSet();
458 if(!is_object($member)) $member = DataObject::get_by_id('Member', $member);
459
460 if(is_array($permCode)) $SQL_codes = "'" . implode("', '", Convert::raw2sql($permCode)) . "'";
461 else $SQL_codes = "'" . Convert::raw2sql($permCode) . "'";
462
463 $templateClassList = "'" . implode("', '", ClassInfo::subclassesFor("Subsite_Template")) . "'";
464
465 $subsites = DataObject::get(
466 'Subsite',
467 "\"Subsite\".\"Title\" != ''",
468 '',
469 "LEFT JOIN \"Group_Subsites\"
470 ON \"Group_Subsites\".\"SubsiteID\" = \"Subsite\".\"ID\"
471 INNER JOIN \"Group\" ON \"Group\".\"ID\" = \"Group_Subsites\".\"GroupID\"
472 OR \"Group\".\"AccessAllSubsites\" = 1
473 INNER JOIN \"Group_Members\"
474 ON \"Group_Members\".\"GroupID\"=\"Group\".\"ID\"
475 AND \"Group_Members\".\"MemberID\" = $member->ID
476 INNER JOIN \"Permission\"
477 ON \"Group\".\"ID\"=\"Permission\".\"GroupID\"
478 AND \"Permission\".\"Code\" IN ($SQL_codes, 'ADMIN')"
479 );
480
481 $rolesSubsites = DataObject::get(
482 'Subsite',
483 "\"Subsite\".\"Title\" != ''",
484 '',
485 "LEFT JOIN \"Group_Subsites\"
486 ON \"Group_Subsites\".\"SubsiteID\" = \"Subsite\".\"ID\"
487 INNER JOIN \"Group\" ON \"Group\".\"ID\" = \"Group_Subsites\".\"GroupID\"
488 OR \"Group\".\"AccessAllSubsites\" = 1
489 INNER JOIN \"Group_Members\"
490 ON \"Group_Members\".\"GroupID\"=\"Group\".\"ID\"
491 AND \"Group_Members\".\"MemberID\" = $member->ID
492 INNER JOIN \"Group_Roles\"
493 ON \"Group_Roles\".\"GroupID\"=\"Group\".\"ID\"
494 INNER JOIN \"PermissionRole\"
495 ON \"Group_Roles\".\"PermissionRoleID\"=\"PermissionRole\".\"ID\"
496 INNER JOIN \"PermissionRoleCode\"
497 ON \"PermissionRole\".\"ID\"=\"PermissionRoleCode\".\"RoleID\"
498 AND \"PermissionRoleCode\".\"Code\" IN ($SQL_codes, 'ADMIN')"
499 );
500
501 if(!$subsites && $rolesSubsites) return $rolesSubsites;
502
503 if($rolesSubsites) foreach($rolesSubsites as $subsite) {
504 if(!$subsites->containsIDs(array($subsite->ID))) {
505 $subsites->push($subsite);
506 }
507 }
508
509
510 if(!$subsites) $subsites = new DataObjectSet();
511 if($includeMainSite) {
512 if(!is_array($permCode)) $permCode = array($permCode);
513 if(self::hasMainSitePermission($member, $permCode)) {
514 $mainSite = new Subsite();
515 $mainSite->Title = $mainSiteTitle;
516 $subsites->insertFirst($mainSite);
517 }
518 }
519
520 return $subsites;
521 }
522
523 524 525 526 527 528 529
530 static function writeHostMap($file = null) {
531 if (!self::$write_hostmap) return;
532
533 if (!$file) $file = Director::baseFolder().'/assets/_host-map.php';
534 $hostmap = array();
535
536 $subsites = DataObject::get('Subsite');
537
538 if ($subsites) foreach($subsites as $subsite) {
539 $domains = $subsite->Domains();
540 if ($domains) foreach($domains as $domain) {
541 $hostmap[str_replace('www.', '', $domain->Domain)] = $subsite->domain();
542 }
543 if ($subsite->DefaultSite) $hostmap['default'] = $subsite->domain();
544 }
545
546 $data = "<?php \n";
547 $data .= "// Generated by Subsite::writeHostMap() on " . date('d/M/y') . "\n";
548 $data .= '$subsiteHostmap = ' . var_export($hostmap, true) . ';';
549
550 if (is_writable(dirname($file)) || is_writable($file)) {
551 file_put_contents($file, $data);
552 }
553 }
554
555
556
557
558
559 560 561
562 function adminSearchFields() {
563 return new FieldSet(
564 new TextField('Name', 'Sub-site name')
565 );
566 }
567
568 function providePermissions() {
569 return array(
570 'SUBSITE_ASSETS_CREATE_SUBSITE' => array(
571 'name' => _t('Subsite.MANAGE_ASSETS', 'Manage assets for subsites'),
572 'category' => _t('Permissions.PERMISSIONS_CATEGORY', 'Roles and access permissions'),
573 'help' => _t('Subsite.MANAGE_ASSETS_HELP', 'Ability to select the subsite to which an asset folder belongs. Requires "Access to Files & Images."'),
574 'sort' => 300
575 )
576 );
577 }
578
579 static function get_from_all_subsites($className, $filter = "", $sort = "", $join = "", $limit = "") {
580 $oldState = self::$disable_subsite_filter;
581 self::$disable_subsite_filter = true;
582 $result = DataObject::get($className, $filter, $sort, $join, $limit);
583 self::$disable_subsite_filter = $oldState;
584 return $result;
585 }
586
587 588 589
590 static function disable_subsite_filter($disabled = true) {
591 self::$disable_subsite_filter = $disabled;
592 }
593
594 function importDomain($domain, $record) {
595 if (!$this->ID) {
596 $this->write();
597 }
598 if (!$d = DataObject::get_one('SubsiteDomain', "Domain='" . Convert::raw2sql($domain) . "'")) {
599 $d = new SubsiteDomain();
600 }
601 $d->Domain = $domain;
602 $d->IsPrimary = 1;
603 $d->SubsiteID = $this->ID;
604 $d->write();
605 }
606 }
607
608 609 610 611 612
613 class Subsite_Template extends Subsite {
614 615 616
617 function createInstance($title, $domain = null) {
618 $intranet = Object::create('Subsite');
619 $intranet->Title = $title;
620 $intranet->TemplateID = $this->ID;
621 $intranet->write();
622
623 if($domain) {
624 $intranetDomain = Object::create('SubsiteDomain');
625 $intranetDomain->SubsiteID = $intranet->ID;
626 $intranetDomain->Domain = $domain;
627 $intranetDomain->write();
628 }
629
630 $oldSubsiteID = Session::get('SubsiteID');
631 self::changeSubsite($this->ID);
632
633 634 635 636 637 638
639 $stack = array(array(0,0));
640 while(count($stack) > 0) {
641 list($sourceParentID, $destParentID) = array_pop($stack);
642
643 $children = Versioned::get_by_stage('SiteTree', 'Live', "\"ParentID\" = $sourceParentID", '');
644
645 if($children) {
646 foreach($children as $child) {
647 $childClone = $child->duplicateToSubsite($intranet);
648 $childClone->ParentID = $destParentID;
649 $childClone->writeToStage('Stage');
650 $childClone->publish('Stage', 'Live');
651 array_push($stack, array($child->ID, $childClone->ID));
652 }
653 }
654 }
655
656 self::changeSubsite($oldSubsiteID);
657
658 return $intranet;
659 }
660 }
661 ?>
662
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-