Permalink
Browse files

ENHANCEMENT Allowing PermissionCheckboxSetField to inspect multiple g…

…roup records for existing permissions

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@99584 467b73ca-7a2a-4603-9d3b-597d59a354a9
  • Loading branch information...
1 parent 246e866 commit 19336e2fcbc1aed81af45eb43a83be1efdd4b45a @chillu chillu committed Feb 22, 2010
Showing with 93 additions and 63 deletions.
  1. +2 −16 security/Group.php
  2. +91 −47 security/PermissionCheckboxSetField.php
View
@@ -35,20 +35,6 @@ class Group extends DataObject {
"Hierarchy",
);
- function getAllParents() {
- $doSet = new DataObjectSet();
-
- $parentID = $this->ParentID;
-
- while($parentID) {
- $parent = DataObject::get_by_id('Group', $parentID);
- $doSet->push($parent);
- $parentID = $parent->ParentID;
- }
-
- return $doSet;
- }
-
/**
* Caution: Only call on instances, not through a singleton.
*
@@ -110,7 +96,7 @@ public function getCMSFields() {
$fields->removeFieldFromTab('Root', 'Permissions');
$fields->removeFieldFromTab('Root', 'IP Addresses');
} else {
- // $parentGroups = $this->getAllParents();
+ // $parentGroups = $this->getAncestors();
// if ($parentGroups) {
// foreach ($parentGroups as $parent) {
// if ($parent->Permissions()->Count()) {
@@ -135,7 +121,7 @@ public function getCMSFields() {
$roleData = Permission::check('ADMIN') ? DataObject::get('PermissionRole') : DataObject::get('PermissionRole', 'OnlyAdminCanApply = 0');
$fields->addFieldToTab('Root.' . _t('SecurityAdmin.ROLES', 'Roles'), new CheckboxSetField('Roles', 'Roles', $roleData));
- // $parentGroups = $this->getAllParents();
+ // $parentGroups = $this->getAncestors();
// if ($parentGroups) {
// foreach ($parentGroups as $parent) {
// if ($parent->Roles()->Count()) {
@@ -1,18 +1,56 @@
<?php
-
-class PermissionCheckboxSetField extends CheckboxSetField {
+/**
+ * Shows a categorized list of available permissions (through {@link Permission::get_codes()}).
+ * Permissions which are assigned to a given {@link Group} record
+ * (either directly, inherited from parent groups, or through a {@link PermissionRole})
+ * will be checked automatically. All checkboxes for "inherited" permissions will be readonly.
+ *
+ * @package sapphire
+ * @subpackage security
+ */
+class PermissionCheckboxSetField extends FormField {
/**
* @var Array Filter certain permission codes from the output.
* Useful to simplify the interface
*/
protected $hiddenPermissions = array();
- function __construct($name, $title, $managedClass, $filterField, $record = null) {
+ /**
+ * @var DataObjectSet
+ */
+ protected $groups = null;
+
+ /**
+ * @var array Array Nested array in same notation as {@link CheckboxSetField}.
+ */
+ protected $source = null;
+
+ /**
+ * @param String $name
+ * @param String $title
+ * @param String $managedClass
+ * @param String $filterField
+ * @param Group|DataObjectSet $groups One or more {@link Group} records used to determine permission checkboxes.
+ * Caution: saveInto() can only be used with a single group, all inherited permissions will be marked readonly.
+ * Setting multiple groups only makes sense in a readonly context. (Optional)
+ */
+ function __construct($name, $title, $managedClass, $filterField, $groups = null) {
$this->filterField = $filterField;
$this->managedClass = $managedClass;
- $this->record = $record;
- parent::__construct($name, $title, Permission::get_codes(true));
+
+ if(is_a($groups, 'DataObjectSet')) {
+ $this->groups = $groups;
+ } elseif(is_a($groups, 'Group')) {
+ $this->groups = new DataObjectSet($groups);
+ } elseif($groups) {
+ throw new InvalidArgumentException('$group should be either a Group record, or a DataObjectSet of Group records');
+ }
+
+ // Get all available codes in the system as a categorized nested array
+ $this->source = Permission::get_codes(true);
+
+ parent::__construct($name, $title);
}
/**
@@ -31,86 +69,92 @@ function getHiddenPermissions() {
function Field() {
Requirements::css(SAPPHIRE_DIR . '/css/CheckboxSetField.css');
-
- $source = $this->source;
- $values = array();
- // Get values from the join, if available
+ // Get existing values from the form record (assuming the formfield name is a join field on the record)
+ $uninheritedCodes = array();
if(is_object($this->form)) {
$record = $this->form->getRecord();
if ($record && $record->hasMethod($this->name)) {
$funcName = $this->name;
$join = $record->$funcName();
-
- if($join) {
- foreach($join as $joinItem) {
- $values[] = $joinItem->Code;
- }
+ if($join) foreach($join as $joinItem) {
+ $uninheritedCodes[$joinItem->Code] = $joinItem->Code;
}
}
}
- $odd = 0;
- $options = '';
-
- $inheritedItems = array();
- if ($this->record) {
- if ($this->record->Roles()->Count()) {
- foreach($this->record->Roles() as $role) {
+ // Get all 'inherited' codes not directly assigned to the group (which is stored in $values)
+ $inheritedCodes = array();
+ if($this->groups) foreach($this->groups as $group) {
+ // Get all uninherited permissions
+ foreach($group->Permissions() as $permission) {
+ $uninheritedCodes[$permission->Code] = $permission->Code;
+ }
+
+ // Get all permissions from roles
+ if ($group->Roles()->Count()) {
+ foreach($group->Roles() as $role) {
foreach($role->Codes() as $code) {
- if (!isset($inheritedItems[$code->Code])) $inheritedItems[$code->Code] = array();
- $inheritedItems[$code->Code][] = 'from role '.$role->Title;
+ if (!isset($inheritedCodes[$code->Code])) $inheritedCodes[$code->Code] = array();
+ // TODO i18n
+ $inheritedCodes[$code->Code][] = 'from role '.$role->Title;
}
}
}
-
- $parentGroups = $this->record->getAllParents();
+
+ // Get from parent groups
+ $parentGroups = $group->getAncestors();
if ($parentGroups) {
foreach ($parentGroups as $parent) {
- if ($parent->Roles()->Count()) {
- foreach($parent->Roles() as $role) {
- if ($role->Codes()) {
- foreach($role->Codes() as $code) {
- if (!isset($inheritedItems[$code->Code])) $inheritedItems[$code->Code] = array();
- $inheritedItems[$code->Code][] = 'role '.$role->Title.' on group '.$parent->Title;
- }
+ if (!$parent->Roles()->Count()) continue;
+ foreach($parent->Roles() as $role) {
+ if ($role->Codes()) {
+ foreach($role->Codes() as $code) {
+ if (!isset($inheritedCodes[$code->Code])) $inheritedCodes[$code->Code] = array();
+ // TODO i18n
+ $inheritedCodes[$code->Code][] = 'role '.$role->Title.' on group '.$parent->Title;
}
}
}
if ($parent->Permissions()->Count()) {
foreach($parent->Permissions() as $permission) {
- if (!isset($inheritedItems[$permission->Code])) $inheritedItems[$permission->Code] = array();
- $inheritedItems[$permission->Code][] = 'group '.$parent->Title;
+ if (!isset($inheritedCodes[$permission->Code])) $inheritedCodes[$permission->Code] = array();
+ // TODO i18n
+ $inheritedCodes[$permission->Code][] = 'group '.$parent->Title;
}
}
}
}
}
-
- if($source) {
- foreach($source as $categoryName => $permissions) {
+
+ $odd = 0;
+ $options = '';
+ if($this->source) {
+ // loop through all available categorized permissions and see if they're assigned for the given groups
+ foreach($this->source as $categoryName => $permissions) {
$options .= "<li><h5>$categoryName</h5></li>";
foreach($permissions as $code => $permission) {
if(in_array($code, $this->hiddenPermissions)) continue;
- $key = $code;
+
$value = $permission['name'];
$odd = ($odd + 1) % 2;
$extraClass = $odd ? 'odd' : 'even';
- $extraClass .= ' val' . str_replace(' ', '', $key);
- $itemID = $this->id() . '_' . ereg_replace('[^a-zA-Z0-9]+', '', $key);
+ $extraClass .= ' val' . str_replace(' ', '', $code);
+ $itemID = $this->id() . '_' . ereg_replace('[^a-zA-Z0-9]+', '', $code);
$checked = $disabled = $inheritMessage = '';
-
- $checked = in_array($key, $values) ? ' checked="checked"' : '';
-
- $title = $permission['help'] ? 'title="'.htmlentities($permission['help']).'" ' : '';
+ $checked = in_array($code, $uninheritedCodes) ? ' checked="checked"' : '';
+ $title = $permission['help'] ? 'title="' . htmlentities($permission['help']) . '" ' : '';
- if (isset($inheritedItems[$code])) {
+ if (isset($inheritedCodes[$code])) {
+ // disable inherited codes, as any saving logic would be too complicate to express in this interface
$disabled = ' disabled="true"';
- $inheritMessage = ' inherited from '.join(', ', $inheritedItems[$code]).'';
+ // TODO i18n
+ $inheritMessage = ' inherited from ' . join(', ', $inheritedCodes[$code]) . '';
$options .= "<li class=\"$extraClass\"><label {$title}for=\"$itemID\">$value is $inheritMessage</label></li>\n";
} else {
- $options .= "<li class=\"$extraClass\"><input id=\"$itemID\"$disabled name=\"$this->name[$key]\" type=\"checkbox\" value=\"$key\"$checked class=\"checkbox\" /> <label {$title}for=\"$itemID\">$value$inheritMessage</label></li>\n";
+ // uninherited (and hence editable) code checkbox
+ $options .= "<li class=\"$extraClass\"><input id=\"$itemID\"$disabled name=\"$this->name[$code]\" type=\"checkbox\" value=\"$code\"$checked class=\"checkbox\" /> <label {$title}for=\"$itemID\">$value$inheritMessage</label></li>\n";
}
}
}

0 comments on commit 19336e2

Please sign in to comment.