Search code examples
phpzend-frameworkinheritanceroleszend-acl

Zend_Acl find all inherited roles


I got chain of roles:

acl.roles.guest  = null
acl.roles.member = "guest"
acl.roles.admin  = "member"
acl.roles.owner  = "admin"

in .....Controller/Action/Helper/Acl.php I have stored _acl object

Is it a way to get list of my role and parents ?

$this->_acl->getParents ( 'admin' )

should return

admin, member, guest

as array, or string (eg comma delimited)


Solution

  • You can use

    • getRoles() - Returns an array of registered roles.

    and then check each of these with

    • inheritsRole() - Returns true if and only if $role inherits from $inherit

    See the API docs Zend_Acl at http://framework.zend.com/apidoc/core/Zend_Acl/Zend_Acl.html

    Example

    $parents = array();
    foreach ($acl->getRoles() as $inherit) {
        if ($acl->inheritsRole('owner', $inherit)) {
            $parents[] = $inherit;
        }
    }
    

    which would then return something like

    Array
    (
        [0] => guest
        [1] => member
        [2] => admin
    )
    

    Alternative

    There actually is a getParents() method in Zend_Acl_Role_Registry, but there doesn't seem to be a way to access that through the public interface of Zend_Acl. See the sourcecode

    It is trivial to extend Zend_Acl to have a method getParentsForRole() though:

    class My_Acl extends Zend_Acl
    {
        public function getParentsForRole($role)
        {
            return $this->_getRoleRegistry()->getParents($role);
        }
    }
    

    This does only return the immediate parents though, e.g. for 'owner' it returns 'admin', so you might want to add another method to fetch all the parents recursively down to the last one:

    class My_Acl extends Zend_Acl
    {
        public function getAllParentsForRole($role, $parents = array())
        {
            foreach ($this->getParentsForRole($role) as $parentName => $parentRole) {
                if (FALSE === isset($parents[$parentName])) {
                    $parents[$parentName] = $parentRole;
                    $parents = $this->getAllParentsForRole($parentRole, $parents);
                }
            }
            return $parents;
        }
    
        public function getParentsForRole($role)
        {
            return $this->_getRoleRegistry()->getParents($role);
        }
    }
    

    Example

    $acl = new My_Acl;
    $acl->addRole('guest');
    $acl->addRole('other');
    $acl->addRole('member', 'guest');
    $acl->addRole('admin', 'member');
    $acl->addRole('owner', array('admin', 'other'));
    
    print_r($acl->getAllParentsForRole('owner'));
    

    would result in

    Array
    (
        [admin] => Zend_Acl_Role Object
            (
                [_roleId:protected] => admin
            )
    
        [member] => Zend_Acl_Role Object
            (
                [_roleId:protected] => member
            )
    
        [guest] => Zend_Acl_Role Object
            (
                [_roleId:protected] => guest
            )
    
        [other] => Zend_Acl_Role Object
            (
                [_roleId:protected] => other
            )    
    )
    

    which is in accordance with what a single call to getParents would return. If you dont need that, you can also just use the foreach code from the first example, e.g.

    class My_Acl extends Zend_Acl
    {
        public function getAllParentsForRole($role)
        {
            $parents = array();
            foreach ($this->getRoles() as $inherit) {
                if($this->inheritsRole($role, $inherit)) {
                    $parents[] = $inherit;
                }
            }
            return $parents;
        }
    }