Zend_Acl and storing roles and resources in a DB
Tuesday, May 8, 2007 12:44:56 PM
I've talked with a few people about using Zend_Acl and how to best approach the issue of resources, roles and users.
It isn't immediately obvious how one should do this:
- Create roles and resources in code?
- Load them from a database?
Creating roles/resources in code
The first of the above two, creating roles and resources in code is probably the best approach when the site in question is small and there aren't many roles or they don't change often. It's few SQL queries less and the database relations are simpler.We simply define the resources and roles in code. Then, to see if an user has access to a resource we just check his role. This can be done by simply saving the user's role in the user database table as text so it will be loaded with the users other info.
Loading roles/resources from a DB
This approach is slightly more complicated.For this you should create a custom Acl class inheriting from Zend_Acl. Have its constructor load the details from the DB.
For the database structure, you need three tables
id
login
password
role_id
id
name
role_id
id
name
inherit_id
In the users table you need to store the ID of the user's role and in resources table the ID of the role required to access it. The inherit_id column in roles table should store the ID of the role that role inherits from, if any.
Example code
Here's an example Acl class for using with a database.
class ResAcl extends Zend_Acl
{
public function __construct($db)
{
$sql = 'SELECT id,
name,
role_id
FROM resources';
$resources = $db->GetAll($sql);
$sql = 'SELECT roles.id,
roles.name,
inherits.name AS inherit_name
FROM roles
LEFT JOIN roles AS inherits ON inherits.id = roles.inherit_id
ORDER BY roles.inherit_id ASC';
$roles = $db->GetAll($sql);
//Loop roles and put them in an assoc array by ID
$roleArray = array();
foreach($roles as $r)
{
$role = new Zend_Acl_Role($r['name']);
//If inherit_name isn't null, have the role
//inherit from that, otherwise no inheriting
if($r['inherit_name'] !== null)
$this->addRole($role,$r['inherit_name']);
else
$this->addRole($role);
$roleArray[$r['id']] = $role;
}
foreach($resources as $r)
{
$resource = new Zend_Acl_Resource($r['name']);
$role = $roleArray[$r['role_id']];
$this->add($resource);
$this->allow($role,$resource);
}
}
}
This class uses ADODB. I also wrote an example ADODB class for using with Zend_Auth which can be used to load users to use with this code with some minor modifications.
The name column in the roles table isn't absolutely necessary: You could refer to the roles in Acl by just their ID column too, but if you're writing an admin panel it's probably much nicer to present users with a clear text name for the role instead of some weird ID number thingy.
For loading the users' roles, you will have to JOIN the roles.name column by the role_id in the users table.







Anonymous # Wednesday, May 9, 2007 1:36:59 PM
Janizomg # Wednesday, May 9, 2007 9:10:38 PM
You could for example have an additional table with columns id, resource_id, role_id, mode. The mode field would store either "allow" or "deny". If you need more specific action based roles, you could add similar tables for actions as we had for resources in the article.
For more specialized access checks with assertions you'll probably have to add them in your Acl class yourself. For your issue this is probably the case.
Have a look at ZF Manual's ACL assertions page. It should be a good place to start. I might write about this later, too.
Anonymous # Tuesday, June 19, 2007 10:24:11 AM
Anonymous # Saturday, July 14, 2007 5:38:25 PM
Anonymous # Wednesday, September 5, 2007 12:39:41 PM
Janizomg # Wednesday, September 5, 2007 10:52:45 PM
Anonymous # Wednesday, September 19, 2007 3:02:22 PM
Anonymous # Sunday, April 20, 2008 4:44:58 PM
Anonymous # Monday, May 5, 2008 8:30:15 PM
Anonymous # Wednesday, May 14, 2008 8:27:54 AM
Janizomg # Wednesday, May 14, 2008 12:23:42 PM
Anonymous # Monday, September 8, 2008 2:06:58 PM
Anonymous # Wednesday, February 17, 2010 11:49:15 AM
Anonymous # Wednesday, February 24, 2010 4:50:09 AM
Anonymous # Thursday, December 2, 2010 5:07:00 PM
Anonymous # Friday, May 6, 2011 4:52:18 AM
Anonymous # Monday, May 9, 2011 11:20:57 PM
Anonymous # Thursday, July 7, 2011 12:36:15 PM