2009-10-29 00:03:35 +01:00
< ? php
2010-02-23 01:55:02 +01:00
/**
* 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 .
*
2010-02-23 01:57:03 +01:00
* The field can gets its assignment data either from { @ link Group } or { @ link PermissionRole } records .
*
2012-04-12 08:02:46 +02:00
* @ package framework
2010-02-23 01:55:02 +01:00
* @ subpackage security
*/
class PermissionCheckboxSetField extends FormField {
2009-11-21 12:05:13 +01:00
/**
* @ var Array Filter certain permission codes from the output .
* Useful to simplify the interface
*/
protected $hiddenPermissions = array ();
2010-02-23 01:55:02 +01:00
/**
2011-10-26 08:09:04 +02:00
* @ var SS_List
2010-02-23 01:55:02 +01:00
*/
2010-02-23 01:57:03 +01:00
protected $records = null ;
2010-02-23 01:55:02 +01:00
/**
* @ 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
2011-10-26 08:09:04 +02:00
* @ param Group | SS_List $records One or more { @ link Group } or { @ link PermissionRole } records
2010-02-23 01:57:03 +01:00
* used to determine permission checkboxes .
* Caution : saveInto () can only be used with a single record , all inherited permissions will be marked readonly .
2010-02-23 01:55:02 +01:00
* Setting multiple groups only makes sense in a readonly context . ( Optional )
*/
2012-09-19 12:07:39 +02:00
public function __construct ( $name , $title , $managedClass , $filterField , $records = null ) {
2009-10-29 00:03:35 +01:00
$this -> filterField = $filterField ;
$this -> managedClass = $managedClass ;
2010-02-23 01:55:02 +01:00
2011-05-02 09:14:05 +02:00
if ( $records instanceof SS_List ) {
2010-02-23 01:57:03 +01:00
$this -> records = $records ;
2011-05-02 09:14:05 +02:00
} elseif ( $records instanceof Group ) {
2011-05-05 12:40:24 +02:00
$this -> records = new ArrayList ( array ( $records ));
2010-02-23 01:57:03 +01:00
} elseif ( $records ) {
2011-10-26 08:09:04 +02:00
throw new InvalidArgumentException ( '$record should be either a Group record, or a SS_List of Group records' );
2010-02-23 01:55:02 +01:00
}
// Get all available codes in the system as a categorized nested array
$this -> source = Permission :: get_codes ( true );
parent :: __construct ( $name , $title );
2009-10-29 00:03:35 +01:00
}
2009-11-21 12:05:13 +01:00
/**
* @ param Array $codes
*/
2012-09-19 12:07:39 +02:00
public function setHiddenPermissions ( $codes ) {
2009-11-21 12:05:13 +01:00
$this -> hiddenPermissions = $codes ;
}
/**
* @ return Array
*/
2012-09-19 12:07:39 +02:00
public function getHiddenPermissions () {
2009-11-21 12:05:13 +01:00
return $this -> hiddenPermissions ;
}
2009-10-29 00:03:35 +01:00
2012-09-19 12:07:39 +02:00
public function Field ( $properties = array ()) {
2012-03-24 04:38:57 +01:00
Requirements :: css ( FRAMEWORK_DIR . '/css/CheckboxSetField.css' );
Requirements :: javascript ( FRAMEWORK_DIR . '/javascript/PermissionCheckboxSetField.js' );
2009-10-29 00:03:35 +01:00
2010-02-23 01:55:02 +01:00
$uninheritedCodes = array ();
2010-02-23 01:57:03 +01:00
$inheritedCodes = array ();
2011-05-05 12:40:24 +02:00
$records = ( $this -> records ) ? $this -> records : new ArrayList ();
2010-02-23 01:57:03 +01:00
// Get existing values from the form record (assuming the formfield name is a join field on the record)
2009-10-29 00:03:35 +01:00
if ( is_object ( $this -> form )) {
$record = $this -> form -> getRecord ();
2010-02-23 01:57:38 +01:00
if (
$record
&& ( is_a ( $record , 'Group' ) || is_a ( $record , 'PermissionRole' ))
&& ! $records -> find ( 'ID' , $record -> ID )
) {
2010-02-23 01:57:03 +01:00
$records -> push ( $record );
2009-10-29 00:03:35 +01:00
}
}
2010-02-23 01:55:02 +01:00
// Get all 'inherited' codes not directly assigned to the group (which is stored in $values)
2010-02-23 01:57:03 +01:00
foreach ( $records as $record ) {
2010-02-23 01:55:02 +01:00
// Get all uninherited permissions
2010-02-23 01:57:03 +01:00
$relationMethod = $this -> name ;
foreach ( $record -> $relationMethod () as $permission ) {
if ( ! isset ( $uninheritedCodes [ $permission -> Code ])) $uninheritedCodes [ $permission -> Code ] = array ();
2012-05-01 21:44:54 +02:00
$uninheritedCodes [ $permission -> Code ][] = _t (
'PermissionCheckboxSetField.AssignedTo' , 'assigned to "{title}"' ,
array ( 'title' => $record -> Title )
2010-02-23 01:57:03 +01:00
);
2010-02-23 01:55:02 +01:00
}
2010-02-23 01:57:03 +01:00
// Special case for Group records (not PermissionRole):
// Determine inherited assignments
if ( is_a ( $record , 'Group' )) {
// Get all permissions from roles
if ( $record -> Roles () -> Count ()) {
foreach ( $record -> Roles () as $role ) {
foreach ( $role -> Codes () as $code ) {
if ( ! isset ( $inheritedCodes [ $code -> Code ])) $inheritedCodes [ $code -> Code ] = array ();
2012-05-01 21:44:54 +02:00
$inheritedCodes [ $code -> Code ][] = _t (
'PermissionCheckboxSetField.FromRole' ,
'inherited from role "{title}"' ,
'A permission inherited from a certain permission role' ,
array ( 'title' => $role -> Title )
2010-02-23 01:58:24 +01:00
);
2010-02-23 01:57:03 +01:00
}
2009-11-03 02:00:54 +01:00
}
}
2010-02-23 01:55:02 +01:00
2010-02-23 01:57:03 +01:00
// Get from parent groups
$parentGroups = $record -> getAncestors ();
if ( $parentGroups ) {
foreach ( $parentGroups as $parent ) {
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 ();
2012-05-01 21:44:54 +02:00
$inheritedCodes [ $code -> Code ][] = _t (
'PermissionCheckboxSetField.FromRoleOnGroup' ,
'inherited from role "%s" on group "%s"' ,
'A permission inherited from a role on a certain group' ,
array ( 'roletitle' => $role -> Title , 'grouptitle' => $parent -> Title )
2010-02-23 01:58:24 +01:00
);
2010-02-23 01:57:03 +01:00
}
2009-11-03 02:00:54 +01:00
}
}
2010-02-23 01:57:03 +01:00
if ( $parent -> Permissions () -> Count ()) {
foreach ( $parent -> Permissions () as $permission ) {
if ( ! isset ( $inheritedCodes [ $permission -> Code ])) $inheritedCodes [ $permission -> Code ] = array ();
2010-02-23 01:58:24 +01:00
$inheritedCodes [ $permission -> Code ][] =
2012-05-01 21:44:54 +02:00
_t (
'PermissionCheckboxSetField.FromGroup' ,
'inherited from group "{title}"' ,
'A permission inherited from a certain group' ,
array ( 'title' => $parent -> Title )
2010-02-23 01:58:24 +01:00
);
2010-02-23 01:57:03 +01:00
}
2009-11-03 02:00:54 +01:00
}
}
}
}
}
2010-02-23 01:55:02 +01:00
$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 ) {
2009-10-29 00:03:35 +01:00
$options .= " <li><h5> $categoryName </h5></li> " ;
foreach ( $permissions as $code => $permission ) {
2009-11-21 12:05:13 +01:00
if ( in_array ( $code , $this -> hiddenPermissions )) continue ;
2011-03-30 06:31:24 +02:00
if ( in_array ( $code , Permission :: $hidden_permissions )) continue ;
2010-02-23 01:55:02 +01:00
2009-10-29 00:03:35 +01:00
$value = $permission [ 'name' ];
$odd = ( $odd + 1 ) % 2 ;
$extraClass = $odd ? 'odd' : 'even' ;
2010-02-23 01:55:02 +01:00
$extraClass .= ' val' . str_replace ( ' ' , '' , $code );
2012-02-27 22:14:02 +01:00
$itemID = $this -> id () . '_' . preg_replace ( '/[^a-zA-Z0-9]+/' , '' , $code );
2009-11-03 02:00:54 +01:00
$checked = $disabled = $inheritMessage = '' ;
2010-02-23 01:57:03 +01:00
$checked = ( isset ( $uninheritedCodes [ $code ]) || isset ( $inheritedCodes [ $code ])) ? ' checked="checked"' : '' ;
2010-12-08 00:53:42 +01:00
$title = $permission [ 'help' ] ? 'title="' . htmlentities ( $permission [ 'help' ], ENT_COMPAT , 'UTF-8' ) . '" ' : '' ;
2009-11-03 02:00:54 +01:00
2010-02-23 01:55:02 +01:00
if ( isset ( $inheritedCodes [ $code ])) {
// disable inherited codes, as any saving logic would be too complicate to express in this interface
2009-11-03 02:00:54 +01:00
$disabled = ' disabled="true"' ;
2010-02-23 01:58:24 +01:00
$inheritMessage = ' (' . join ( ', ' , $inheritedCodes [ $code ]) . ')' ;
2010-02-23 01:57:03 +01:00
} elseif ( $this -> records && $this -> records -> Count () > 1 && isset ( $uninheritedCodes [ $code ])) {
// If code assignments are collected from more than one "source group",
// show its origin automatically
$inheritMessage = ' (' . join ( ', ' , $uninheritedCodes [ $code ]) . ')' ;
2009-11-03 02:00:54 +01:00
}
2012-09-26 03:19:26 +02:00
2010-02-23 01:57:03 +01:00
// If the field is readonly, always mark as "disabled"
if ( $this -> readonly ) $disabled = ' disabled="true"' ;
$inheritMessage = '<small>' . $inheritMessage . '</small>' ;
2012-09-26 03:19:26 +02:00
// If the field is readonly, add a span that will replace the disabled checkbox input
if ( $this -> readonly ) {
$options .= " <li class= \" $extraClass\ " > " .
" <input id= \" $itemID\ " $disabled name = \ " $this->name [ $code ] \" type= \" checkbox \" value= \" $code\ " $checked class = \ " checkbox \" /> " .
" <label { $title } for= \" $itemID\ " >< span class = \ " ui-button-icon-primary ui-icon btn-icon-accept \" ></span> $value $inheritMessage </label> " .
" </li> \n " ;
} else {
$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 " ;
}
2009-10-29 00:03:35 +01:00
}
}
}
2012-09-26 03:19:26 +02:00
if ( $this -> readonly ) {
return " <ul id= \" { $this -> id () } \" class= \" optionset checkboxsetfield { $this -> extraClass () } \" > \n <li class= \" help \" >Assigning groups to this user will adjust the permissions they have. See the groups section for details of permissions on individual groups.</li> $options </ul> \n " ;
} else {
return " <ul id= \" { $this -> id () } \" class= \" optionset checkboxsetfield { $this -> extraClass () } \" > \n $options </ul> \n " ;
}
2009-10-29 00:03:35 +01:00
}
2009-12-10 04:26:30 +01:00
/**
* Update the permission set associated with $record DataObject
*
* @ param DataObject $record
*/
2012-09-19 12:07:39 +02:00
public function saveInto ( DataObjectInterface $record ) {
2009-10-29 00:03:35 +01:00
$fieldname = $this -> name ;
$managedClass = $this -> managedClass ;
2009-12-09 23:53:59 +01:00
// remove all permissions and re-add them afterwards
$permissions = $record -> $fieldname ();
foreach ( $permissions as $permission ) {
$permission -> delete ();
}
2009-10-29 00:03:35 +01:00
if ( $fieldname && $record && ( $record -> has_many ( $fieldname ) || $record -> many_many ( $fieldname ))) {
2012-03-06 00:58:44 +01:00
if ( ! $record -> ID ) $record -> write (); // We need a record ID to write permissions
2009-10-29 00:03:35 +01:00
$idList = array ();
if ( $this -> value ) foreach ( $this -> value as $id => $bool ) {
if ( $bool ) {
$perm = new $managedClass ();
$perm -> { $this -> filterField } = $record -> ID ;
$perm -> Code = $id ;
$perm -> write ();
}
}
}
}
2010-02-23 01:57:03 +01:00
/**
* @ return PermissionCheckboxSetField_Readonly
*/
2012-09-19 12:07:39 +02:00
public function performReadonlyTransformation () {
2010-02-23 01:57:03 +01:00
$readonly = new PermissionCheckboxSetField_Readonly (
$this -> name ,
$this -> title ,
$this -> managedClass ,
$this -> filterField ,
$this -> records
);
return $readonly ;
}
/**
* Retrieves all permission codes for the currently set records
*
* @ return array
*/
2012-09-19 12:07:39 +02:00
public function getAssignedPermissionCodes () {
2010-02-23 01:57:03 +01:00
if ( ! $this -> records ) return false ;
// TODO
return $codes ;
}
}
/**
* Readonly version of a { @ link PermissionCheckboxSetField } -
* uses the same structure , but has all checkboxes disabled .
*
2012-04-12 08:02:46 +02:00
* @ package framework
2010-02-23 01:57:03 +01:00
* @ subpackage security
*/
class PermissionCheckboxSetField_Readonly extends PermissionCheckboxSetField {
protected $readonly = true ;
2012-09-19 12:07:39 +02:00
public function saveInto ( DataObjectInterface $record ) {
2010-02-23 01:57:03 +01:00
return false ;
}
2012-02-27 22:14:02 +01:00
}