Version: current

      1 <?php
      2 /**
      3  * Extension for the Group object to add subsites support
      4  *
      5  * @package subsites
      6  */
      7 class GroupSubsites extends DataObjectDecorator implements PermissionProvider {
      8
      9     function extraStatics() {
     10         if(!method_exists('DataObjectDecorator', 'load_extra_statics')) {
     11             if($this->owner->class != 'Group') return null;
     12         }
     13         return array(
     14             'db' => array(
     15                 'AccessAllSubsites' => 'Boolean',
     16             ),
     17             'many_many' => array(
     18                 'Subsites' => 'Subsite',
     19             ),
     20             'defaults' => array(
     21                 'AccessAllSubsites' => 1,
     22             ),
     23         );
     24     }
     25
     26
     27     /**
     28      * Migrations for GroupSubsites data.
     29      */
     30     function requireDefaultRecords() {
     31         // Migration for Group.SubsiteID data from when Groups only had a single subsite
     32         $groupFields = DB::getConn()->fieldList('Group');
     33
     34         // Detection of SubsiteID field is the trigger for old-style-subsiteID migration
     35         if(isset($groupFields['SubsiteID'])) {
     36             // Migrate subsite-specific data
     37             DB::query('INSERT INTO "Group_Subsites" ("GroupID", "SubsiteID")
     38                 SELECT "ID", "SubsiteID" FROM "Group" WHERE "SubsiteID" > 0');
     39
     40             // Migrate global-access data
     41             DB::query('UPDATE "Group" SET "AccessAllSubsites" = 1 WHERE "SubsiteID" = 0');
     42
     43             // Move the field out of the way so that this migration doesn't get executed again
     44             DB::getConn()->renameField('Group', 'SubsiteID', '_obsolete_SubsiteID');
     45
     46         // No subsite access on anything means that we've just installed the subsites module.
     47         // Make all previous groups global-access groups
     48         } else if(!DB::query('SELECT "Group"."ID" FROM "Group"
     49             LEFT JOIN "Group_Subsites" ON "Group_Subsites"."GroupID" = "Group"."ID" AND "Group_Subsites"."SubsiteID" > 0
     50             WHERE "AccessAllSubsites" = 1
     51             OR "Group_Subsites"."GroupID" IS NOT NULL ')->value()) {
     52
     53             DB::query('UPDATE "Group" SET "AccessAllSubsites" = 1');
     54         }
     55     }
     56
     57     function updateCMSFields(&$fields) {
     58         if($this->owner->canEdit() ){
     59             // i18n tab
     60             $fields->findOrMakeTab('Root.Subsites',_t('GroupSubsites.SECURITYTABTITLE','Subsites'));
     61
     62             $subsites = Subsite::accessible_sites(array('ADMIN', 'SECURITY_SUBSITE_GROUP'), true);
     63             $subsiteMap = $subsites->toDropdownMap();
     64
     65             // Interface is different if you have the rights to modify subsite group values on
     66             // all subsites
     67             if(isset($subsiteMap[0])) {
     68                 $fields->addFieldToTab("Root.Subsites", new OptionsetField("AccessAllSubsites",
     69                     _t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'),
     70                     array(
     71                         1 => _t('GroupSubsites.ACCESSALL', "All subsites"),
     72                         0 => _t('GroupSubsites.ACCESSONLY', "Only these subsites"),
     73                     )
     74                 ));
     75
     76                 unset($subsiteMap[0]);
     77                 $fields->addFieldToTab("Root.Subsites", new CheckboxSetField("Subsites", "",
     78                     $subsiteMap));
     79
     80             } else {
     81                 if (sizeof($subsiteMap) <= 1) {
     82                     $fields->addFieldToTab("Root.Subsites", new ReadonlyField("SubsitesHuman",
     83                         _t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'),
     84                         reset($subsiteMap)));
     85                 } else {
     86                     $fields->addFieldToTab("Root.Subsites", new CheckboxSetField("Subsites",
     87                         _t('GroupSubsites.ACCESSRADIOTITLE', 'Give this group access to'),
     88                         $subsiteMap));
     89                 }
     90             }
     91         }
     92     }
     93
     94     /**
     95      * If this group belongs to a subsite,
     96      * append the subsites title to the group title
     97      * to make it easy to distinguish in the tree-view
     98      * of the security admin interface.
     99      */
    100     function alternateTreeTitle() {
    101         if($this->owner->AccessAllSubsites) {
    102             return htmlspecialchars($this->owner->Title, ENT_QUOTES) . ' <i>(global group)</i>';
    103         } else {
    104             $subsites = Convert::raw2xml(implode(", ", $this->owner->Subsites()->column('Title')));
    105             return htmlspecialchars($this->owner->Title) . " <i>($subsites)</i>";
    106         }
    107     }
    108
    109     /**
    110      * Update any requests to limit the results to the current site
    111      */
    112     function augmentSQL(SQLQuery &$query) {
    113         if(Subsite::$disable_subsite_filter) return;
    114         if(Cookie::get('noSubsiteFilter') == 'true') return;
    115
    116         // If you're querying by ID, ignore the sub-site - this is a bit ugly...
    117         if(!$query->filtersOnID()) {
    118
    119             if($context = DataObject::context_obj()) $subsiteID = (int)$context->SubsiteID;
    120             else $subsiteID = (int)Subsite::currentSubsiteID();
    121
    122             // Don't filter by Group_Subsites if we've already done that
    123             $hasGroupSubsites = false;
    124             foreach($query->from as $item) if(strpos($item, 'Group_Subsites') !== false) {
    125                 $hasGroupSubsites = true;
    126                 break;
    127             }
    128
    129             if(!$hasGroupSubsites) {
    130                 if($subsiteID) {
    131                     $query->leftJoin("Group_Subsites", "\"Group_Subsites\".\"GroupID\"
    132                         = \"Group\".\"ID\" AND \"Group_Subsites\".\"SubsiteID\" = $subsiteID");
    133                     $query->where[] = "(\"Group_Subsites\".\"SubsiteID\" IS NOT NULL OR
    134                         \"Group\".\"AccessAllSubsites\" = 1)";
    135                 } else {
    136                     $query->where[] = "\"Group\".\"AccessAllSubsites\" = 1";
    137                 }
    138             }
    139
    140             // WORKAROUND for databases that complain about an ORDER BY when the column wasn't selected (e.g. SQL Server)
    141             if(!$query->select[0] == 'COUNT(*)') {
    142                 $query->orderby = "\"AccessAllSubsites\" DESC" . ($query->orderby ? ', ' : '') . $query->orderby;
    143             }
    144         }
    145     }
    146
    147     function onBeforeWrite() {
    148         // New record test approximated by checking whether the ID has changed.
    149         // Note also that the after write test is only used when we're *not* on a subsite
    150         if($this->owner->isChanged('ID') && !Subsite::currentSubsiteID()) {
    151             $this->owner->AccessAllSubsites = 1;
    152         }
    153     }
    154
    155     function onAfterWrite() {
    156         // New record test approximated by checking whether the ID has changed.
    157         // Note also that the after write test is only used when we're on a subsite
    158         if($this->owner->isChanged('ID') && $currentSubsiteID = Subsite::currentSubsiteID()) {
    159             $subsites = $this->owner->Subsites();
    160             $subsites->add($currentSubsiteID);
    161         }
    162     }
    163
    164     function alternateCanEdit() {
    165         // Find the sites that this group belongs to and the sites where we have appropriate perm.
    166         $accessibleSites = Subsite::accessible_sites('CMS_ACCESS_SecurityAdmin')->column('ID');
    167         $linkedSites = $this->owner->Subsites()->column('ID');
    168
    169         // We are allowed to access this site if at we have CMS_ACCESS_SecurityAdmin permission on
    170         // at least one of the sites
    171         return (bool)array_intersect($accessibleSites, $linkedSites);
    172     }
    173
    174     function providePermissions() {
    175         return array(
    176             'SECURITY_SUBSITE_GROUP' => array(
    177                 'name' => _t('GroupSubsites.MANAGE_SUBSITES', 'Manage subsites for groups'),
    178                 'category' => _t('Permissions.PERMISSIONS_CATEGORY', 'Roles and access permissions'),
    179                 'help' => _t('GroupSubsites.MANAGE_SUBSITES_HELP', 'Ability to limit the permissions for a group to one or more subsites.'),
    180                 'sort' => 200
    181             )
    182         );
    183     }
    184
    185 }
    186
    187 ?>
    188

[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. -