Webylon 3.2 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • 1c
    • exchange
      • catalog
  • auth
  • Booking
  • building
    • company
  • cart
    • shipping
    • steppedcheckout
  • Catalog
    • monument
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • Authenticator
  • BasicAuth
  • ChangePasswordForm
  • Group
  • GroupCsvBulkLoader
  • LoginAttempt
  • LoginForm
  • Member
  • Member_ChangePasswordEmail
  • Member_ForgotPasswordEmail
  • Member_GroupSet
  • Member_ProfileForm
  • Member_SignupEmail
  • Member_Validator
  • MemberAuthenticator
  • MemberCsvBulkLoader
  • MemberLoginForm
  • MemberPassword
  • NZGovtPasswordValidator
  • PasswordEncryptor
  • PasswordEncryptor_LegacyPHPHash
  • PasswordEncryptor_MySQLOldPassword
  • PasswordEncryptor_MySQLPassword
  • PasswordEncryptor_None
  • PasswordEncryptor_PHPHash
  • PasswordValidator
  • Permission
  • Permission_Group
  • PermissionCheckboxSetField
  • PermissionCheckboxSetField_Readonly
  • PermissionRole
  • PermissionRoleCode
  • Security

Interfaces

  • PermissionProvider

Exceptions

  • PasswordEncryptor_NotFoundException
  1 <?php
  2 /**
  3  * A security group.
  4  * 
  5  * @package sapphire
  6  * @subpackage security
  7  */
  8 class Group extends DataObject {
  9     
 10     static $db = array(
 11         "Title" => "Varchar",
 12         "Description" => "Text",
 13         "Code" => "Varchar",
 14         "Locked" => "Boolean",
 15         "Sort" => "Int",
 16         "IPRestrictions" => "Text",
 17         "HtmlEditorConfig" => "Varchar"
 18     );
 19     
 20     static $has_one = array(
 21         "Parent" => "Group",
 22     );
 23     
 24     static $has_many = array(
 25         "Permissions" => "Permission",
 26         "Groups" => "Group"
 27     );
 28     
 29     static $many_many = array(
 30         "Members" => "Member",
 31         "Roles" => "PermissionRole",
 32     );
 33     
 34     static $extensions = array(
 35         "Hierarchy",
 36     );
 37     
 38     function getAllChildren() {
 39         $doSet = new DataObjectSet();
 40 
 41         if ($children = DataObject::get('Group', '"ParentID" = '.$this->ID)) {
 42             foreach($children as $child) {
 43                 $doSet->push($child);
 44                 $doSet->merge($child->getAllChildren());
 45             }
 46         }
 47         
 48         return $doSet;
 49     }
 50     
 51     /**
 52      * Caution: Only call on instances, not through a singleton.
 53      *
 54      * @return FieldSet
 55      */
 56     public function getCMSFields() { 
 57         $fields = new FieldSet(
 58             new TabSet("Root",
 59                 new Tab('Members',_t('SecurityAdmin.MEMBERS','Members'),
 60                     new TextField("Title", $this->fieldLabel('Title')),
 61                     $memberList = new MemberTableField(
 62                         $this,
 63                         "Members",
 64                         $this
 65                     )
 66                 ),
 67 
 68                 $permissionsTab = new Tab('Permissions', _t('SecurityAdmin.PERMISSIONS', 'Permissions'),
 69                     new PermissionCheckboxSetField(
 70                         'Permissions',
 71                         false,
 72                         'Permission',
 73                         'GroupID',
 74                         $this
 75                     )
 76                 ),
 77 
 78                 new Tab('IP Addresses',_t('Security.IPADDRESSES', 'IP Addresses'),
 79                     new LiteralField("", _t('SecurityAdmin.IPADDRESSESHELP',"<p>You can restrict this group to a particular 
 80                         IP address range (one range per line). <br />Ranges can be in any of the following forms: <br />
 81                         203.96.152.12<br />
 82                         203.96.152/24<br />
 83                         203.96/16<br />
 84                         203/8<br /><br />If you enter one or more IP address ranges in this box, then members will only get
 85                         the rights of being in this group if they log on from one of the valid IP addresses.  It won't prevent
 86                         people from logging in.  This is because the same user might have to log in to access parts of the
 87                         system without IP address restrictions.")),
 88                     new TextareaField("IPRestrictions", _t('Security.IP_RANGES', "IP Ranges"), 10)
 89                 )
 90             )
 91         );
 92         
 93         // Only add a dropdown for HTML editor configurations if more than one is available.
 94         // Otherwise Member->getHtmlEditorConfigForCMS() will default to the 'cms' configuration.
 95         $editorConfigMap = HtmlEditorConfig::get_available_configs_map();
 96         if(count($editorConfigMap) > 1) {
 97             $fields->addFieldToTab('Root.Permissions',
 98                 new DropdownField(
 99                     'HtmlEditorConfig', 
100                     'HTML Editor Configuration', 
101                     $editorConfigMap
102                 ),
103                 'Permissions'
104             );
105         }
106 
107         if(!Permission::check('EDIT_PERMISSIONS')) {
108             $fields->removeFieldFromTab('Root', 'Permissions');
109             $fields->removeFieldFromTab('Root', 'IP Addresses');
110         }
111 
112         // Only show the "Roles" tab if permissions are granted to edit them,
113         // and at least one role exists
114         if(Permission::check('APPLY_ROLES') && DataObject::get('PermissionRole')) { 
115             $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.ROLES', 'Roles'));
116             $fields->addFieldToTab('Root.Roles', 
117                 new LiteralField( 
118                     "",  
119                     "<p>" .  
120                     _t('SecurityAdmin.ROLESDESCRIPTION', 
121                         "This section allows you to add roles to this group. Roles are logical groupings of permissions, which can be editied in the Roles tab" 
122                     ) .  
123                      "</p>" 
124                 ) 
125             );
126             
127             // Add roles (and disable all checkboxes for inherited roles)
128             $allRoles = Permission::check('ADMIN') ? DataObject::get('PermissionRole') : DataObject::get('PermissionRole', 'OnlyAdminCanApply = 0');
129             $groupRoles = $this->Roles();
130             $inheritedRoles = new DataObjectSet();
131             $ancestors = $this->getAncestors();
132             foreach($ancestors as $ancestor) {
133                 $ancestorRoles = $ancestor->Roles();
134                 if($ancestorRoles) $inheritedRoles->merge($ancestorRoles);
135             }
136             $fields->addFieldToTab(
137                 'Root.Roles',
138                 $rolesField = new CheckboxSetField('Roles', _t('Group.Roles', 'Roles'), $allRoles)
139             );
140             $rolesField->setDefaultItems($inheritedRoles->column('ID'));
141             $rolesField->setDisabledItems($inheritedRoles->column('ID'));
142         } 
143         
144         $memberList->setController($this);
145         $memberList->setPermissions(array('edit', 'delete', 'export', 'add'));
146         $memberList->setParentClass('Group');
147         $memberList->setPopupCaption(_t('SecurityAdmin.VIEWUSER', 'View User'));
148         $memberList->setRelationAutoSetting(false);
149 
150         $fields->push($idField = new HiddenField("ID"));
151         
152         $this->extend('updateCMSFields', $fields);
153         
154         return $fields;
155     }
156     
157     /**
158      *
159      * @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields
160      * 
161      */
162     function fieldLabels($includerelations = true) {
163         $labels = parent::fieldLabels($includerelations);
164         $labels['Title'] = _t('SecurityAdmin.GROUPNAME', 'Group name');
165         $labels['Description'] = _t('Group.Description', 'Description');
166         $labels['Code'] = _t('Group.Code', 'Group Code', PR_MEDIUM, 'Programmatical code identifying a group');
167         $labels['Locked'] = _t('Group.Locked', 'Locked?', PR_MEDIUM, 'Group is locked in the security administration area');
168         $labels['Sort'] = _t('Group.Sort', 'Sort Order');
169         $labels['IPRestrictions'] = _t('Group.IPRestrictions', 'IP Address Restrictions');
170         if($includerelations){
171             $labels['Parent'] = _t('Group.Parent', 'Parent Group', PR_MEDIUM, 'One group has one parent group');
172             $labels['Permissions'] = _t('Group.has_many_Permissions', 'Permissions', PR_MEDIUM, 'One group has many permissions');
173             $labels['Members'] = _t('Group.many_many_Members', 'Members', PR_MEDIUM, 'One group has many members');
174         }
175         
176         return $labels;
177     }
178     
179     /**
180      * Add a member to a group. This will create the group if the given 
181      * group code doesn't work.
182      *
183      * @param DataObject $member
184      * @param string $groupcode
185      */
186     static function addToGroupByName($member, $groupcode) {
187         $group = DataObject::get_one('Group', "\"Code\" = '" . Convert::raw2sql($groupcode). "'");
188         if($group) {
189             $member->Groups()->add($group);
190         }
191         else {
192             $group = new Group();
193             $group->Code = $groupcode;
194             $group->Title = $groupcode;
195             $group->write();
196             
197             $member->Groups()->add($group);
198         }
199     }
200     
201     /**
202      * Overloaded getter.
203      *
204      * @TODO Where is this used, why is this overloaded?
205      * 
206      * @param $limit string SQL
207      * @param $offset int
208      * @param $filter string SQL
209      * @param $sort string SQL
210      * @param $join string SQL
211      * @return ComponentSet
212      */
213     public function Members($limit = "", $offset = "", $filter = "", $sort = "", $join = "") {
214         $table = "Group_Members";
215         if($filter) $filter = is_array($filter) ? $filter : array($filter);
216         
217         if( is_numeric( $limit ) ) {
218             if( is_numeric( $offset ) )
219                 $limit = "$limit OFFSET $offset";
220             else
221                 $limit = "$limit OFFSET 0";
222         } else {
223             $limit = "";
224         }
225         
226         // Get all of groups that this group contains
227         $groupFamily = implode(", ", $this->collateFamilyIDs());
228         
229         $filter[] = "\"$table\".\"GroupID\" IN ($groupFamily)";
230         $join .= " INNER JOIN \"$table\" ON \"$table\".\"MemberID\" = \"Member\".\"ID\"" . Convert::raw2sql($join);
231         
232         $result = singleton("Member")->instance_get(
233             $filter, 
234             $sort,
235             $join, 
236             $limit,
237             "ComponentSet" // datatype
238             );
239             
240         if(!$result) $result = new ComponentSet();
241 
242         $result->setComponentInfo("many-to-many", $this, "Group", $table, "Member");
243         foreach($result as $item) $item->GroupID = $this->ID;
244         return $result;
245     }
246     
247     public function map($filter = "", $sort = "", $blank="") {
248         $ret = new SQLMap(singleton('Group')->extendedSQL($filter, $sort));
249         if($blank){
250             $blankGroup = new Group();
251             $blankGroup->Title = $blank;
252             $blankGroup->ID = 0;
253 
254             $ret->getItems()->shift($blankGroup);
255         }
256         return $ret;
257     }
258     
259     /**
260      * Return a set of this record's "family" of IDs - the IDs of
261      * this record and all its descendants.
262      * @return array
263      */
264     public function collateFamilyIDs() {
265         $familyIDs = array();
266         $chunkToAdd = array(array("ID" => $this->ID));
267         
268         while($chunkToAdd) {
269             $idList = array();
270             foreach($chunkToAdd as $item) {
271                 $idList[] = $item['ID'];
272                 $familyIDs[] = $item['ID'];
273             }
274             $idList = implode(',', $idList);
275             
276             // Get the children of *all* the groups identified in the previous chunk.
277             // This minimises the number of SQL queries necessary           
278             $sql = $this->extendedSQL("\"ParentID\" IN ($idList)", "");
279             $dbResult = $sql->execute();
280             $chunkToAdd = array();
281             foreach($dbResult as $item) $chunkToAdd[] = $item;
282         }
283         
284         return $familyIDs;
285     }
286     
287     /**
288      * Returns an array of the IDs of this group and all its parents
289      */
290     public function collateAncestorIDs() {
291         $parent = $this;
292         while(isset($parent)) {
293             $items[] = $parent->ID;
294             $parent = $parent->Parent;
295         }
296         return $items;
297     }
298     
299     /**
300      * This isn't a decendant of SiteTree, but needs this in case
301      * the group is "reorganised";
302      */
303     function cmsCleanup_parentChanged() {
304     }
305     
306     /**
307      * Override this so groups are ordered in the CMS
308      */
309     public function stageChildren() {
310         return DataObject::get('Group', "\"Group\".\"ParentID\" = " . (int)$this->ID . " AND \"Group\".\"ID\" != " . (int)$this->ID, '"Sort"');
311     }
312     
313     public function TreeTitle() {
314         if($this->hasMethod('alternateTreeTitle')) return $this->alternateTreeTitle();
315         else return htmlspecialchars($this->Title, ENT_QUOTES);
316     }
317     
318     function CMSTreeClasses($controller) {
319         $classes = $this->class;
320 
321         if(!$this->canEdit()) $classes .= " disabled";
322 
323         return $classes;
324     }
325     
326     /**
327      * Overloaded to ensure the code is always descent.
328      */
329     public function setCode($val){
330         $this->setField("Code",SiteTree::generateURLSegment($val));
331     }
332     
333     function onBeforeWrite() {
334         parent::onBeforeWrite();
335         
336         if(stripos($this->Code, _t('SecurityAdmin.NEWGROUPPREFIX','new-')) === 0) {
337             $this->setCode($this->Title);
338         }
339     }
340     
341     function onAfterDelete() {
342         parent::onAfterDelete();
343         
344         // Delete associated permissions
345         $permissions = $this->Permissions();
346         foreach ( $permissions as $permission ) {
347             $permission->delete();
348         }
349     }
350     
351     /**
352      * Checks for permission-code CMS_ACCESS_SecurityAdmin.
353      * If the group has ADMIN permissions, it requires the user to have ADMIN permissions as well.
354      * 
355      * @param $member Member
356      * @return boolean
357      */
358     public function canEdit($member = null) {
359         if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
360         
361         // decorated access checks
362         $results = $this->extend('canEdit', $member);
363         if($results && is_array($results)) if(!min($results)) return false;
364         
365         if(
366             // either we have an ADMIN
367             (bool)Permission::checkMember($member, "ADMIN")
368             || (
369                 // or a privileged CMS user and a group without ADMIN permissions.
370                 // without this check, a user would be able to add himself to an administrators group
371                 // with just access to the "Security" admin interface
372                 Permission::checkMember($member, "CMS_ACCESS_SecurityAdmin") && 
373                 !DataObject::get("Permission", "GroupID = $this->ID AND Code = 'ADMIN'")
374             )
375         ) {
376             return true;
377         }
378 
379         return false;
380     }
381     
382     /**
383      * Checks for permission-code CMS_ACCESS_SecurityAdmin.
384      * 
385      * @param $member Member
386      * @return boolean
387      */
388     public function canView($member = null) {
389         if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
390         
391         // decorated access checks
392         $results = $this->extend('canView', $member);
393         if($results && is_array($results)) if(!min($results)) return false;
394         
395         // user needs access to CMS_ACCESS_SecurityAdmin
396         if(Permission::checkMember($member, "CMS_ACCESS_SecurityAdmin")) return true;
397         
398         return false;
399     }
400     
401     public function canDelete($member = null) {
402         if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
403         
404         // decorated access checks
405         $results = $this->extend('canDelete', $member);
406         if($results && is_array($results)) if(!min($results)) return false;
407         
408         return $this->canEdit($member);
409     }
410 
411     /**
412      * Returns all of the children for the CMS Tree.
413      * Filters to only those groups that the current user can edit
414      */
415     function AllChildrenIncludingDeleted() {
416         $extInstance = $this->getExtensionInstance('Hierarchy');
417         $extInstance->setOwner($this);
418         $children = $extInstance->AllChildrenIncludingDeleted();
419         $extInstance->clearOwner();
420         
421         $filteredChildren = new DataObjectSet();
422         
423         if($children) foreach($children as $child) {
424             if($child->canView()) $filteredChildren->push($child);
425         }
426         
427         return $filteredChildren;
428     }
429     
430     /**
431      * Returns true if the given IP address is granted access to this group.
432      * For unrestricted groups, this always returns true.
433      */
434     function allowedIPAddress($ip) {
435         if(!$this->IPRestrictions) return true;
436         if(!$ip) return false;
437         
438         $ipPatterns = explode("\n", $this->IPRestrictions);
439         foreach($ipPatterns as $ipPattern) {
440             $ipPattern = trim($ipPattern);
441             if(preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/', $ipPattern, $matches)) {
442                 if($ip == $ipPattern) return true;
443             } else if(preg_match('/^([0-9]+\.[0-9]+\.[0-9]+)\/24$/', $ipPattern, $matches)
444                     || preg_match('/^([0-9]+\.[0-9]+)\/16$/', $ipPattern, $matches)
445                     || preg_match('/^([0-9]+)\/8$/', $ipPattern, $matches)) {
446                 if(substr($ip, 0, strlen($matches[1])) == $matches[1]) return true;
447             }
448         }
449         return false;
450     }
451     
452     /**
453      * Add default records to database.
454      *
455      * This function is called whenever the database is built, after the
456      * database tables have all been created.
457      */
458     public function requireDefaultRecords() {
459         parent::requireDefaultRecords();
460         
461         // Add default author group if no other group exists
462         $allGroups = DataObject::get('Group');
463         if(!$allGroups) {
464             $authorGroup = new Group();
465             $authorGroup->Code = 'content-authors';
466             $authorGroup->Title = _t('Group.DefaultGroupTitleContentAuthors', 'Content Authors');
467             $authorGroup->Sort = 1;
468             $authorGroup->write();
469             Permission::grant($authorGroup->ID, 'CMS_ACCESS_CMSMain');
470             Permission::grant($authorGroup->ID, 'CMS_ACCESS_AssetAdmin');
471             Permission::grant($authorGroup->ID, 'CMS_ACCESS_CommentAdmin');
472             Permission::grant($authorGroup->ID, 'CMS_ACCESS_ReportAdmin');
473             Permission::grant($authorGroup->ID, 'SITETREE_REORGANISE');
474         }
475     
476         // Add default admin group if none with permission code ADMIN exists
477         $adminGroups = Permission::get_groups_by_permission('ADMIN');
478         if(!$adminGroups) {
479             $adminGroup = new Group();
480             $adminGroup->Code = 'administrators';
481             $adminGroup->Title = _t('Group.DefaultGroupTitleAdministrators', 'Administrators');
482             $adminGroup->Sort = 0;
483             $adminGroup->write();
484             Permission::grant($adminGroup->ID, 'ADMIN');
485         }       
486         
487         // Members are populated through Member->requireDefaultRecords()
488     }
489 }
490     
491 ?>
[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. -
Webylon 3.2 API Docs API documentation generated by ApiGen 2.8.0