This question came up while designing a dedicated ACL system for a custom application, but I think it applies to ACL systems in general, as I haven't found out how to tackle this problem by looking at some of the mainstream systems, like Zend_ACL
.
In my application, the permissions are granted dynamically, for example: a user gets view permissions on an activity because he is a member of the team the activity is linked to. This builds on the assumption that you always have an Employee
(user) that wants to perform an action (view/edit/etc) on an Item
(one of the objects in my application, eg Activity, Team, etc). This is sufficient for my targeted use;
$Activity = new Activity( $_POST['activity_id'] );
$Acl = new Acl( $Activity );
if ( !$Acl->check( 'edit' ) {
throw new AclException('no permission to edit');
}
My Acl
class contains all the business rules to grant the permissions, and they're created 'on the fly' (although sometimes cached for performance reasons);
/**
* Check the permissions on a given activity.
* @param Activity $Activity
* @param int $permission (optional) check for a specific permission
* @return mixed integer containing all the permissions, or a bool when $permission is set
*/
public function checkActivity( Activity $Activity, $permission = null ) {
$permissions = 0;
if ( $Activity->owner_actor_id == $this->Employee->employee_id ) {
$permissions |= $this->activity['view'];
$permissions |= $this->activity['remove'];
$permissions |= $this->activity['edit'];
} elseif ( in_array( $this->Employee->employee_id, $Activity->contributor_ids_arr ) ) {
$permissions |= $this->activity['view'];
} else {
/**
* Logged in user is not the owner of the activity, he can contribute
* if he's in the team the activity is linked to
*/
if ( $Activity->getTeam()->isMember( $this->Employee ) ) {
$permissions |= $this->activity['view'];
}
}
return ( $permission ? ( ( $permission & $permissions ) === $permission ) : $permissions );
}
This system works fine as-is.
The problem with this approach arises when you want to 'reverse' the ACL rules. For instance, "fetch all activities that I'm allowed to edit". I don't want to put any logic like WHERE owner_actor_id = $Employee->employee_id
in the code that needs the activities, because this is the responsibility of the Acl
class and it should be kept centralized. With the current implementation, I have no other option that to fetch all activities in the code, and then assert them one by one. This is of course a very inefficient approach.
So what I'm looking for is some ideas on a good architecture (or a pointer to an existing ACL implementation or some relevant design patterns) to create an ACL system that can somehow do both hasPermission( $Item, $permission )
and fetchAllItems( $permission )
, ideally with the same set of business rules.
Thank you all in advance!
I've looked at the Zend_ACL
implementation, but that focuses more on general permissions. I also found the following questions here on SO:
But unfortunately they don't seem to answer the question either.
fetchAllItems()
method in theAcl
class? I am not sure I really understand the question. – Pretender