Issues

ZF-1356: add method to get parent resource and methods get all parents of roles or resources

Description


    /**
     * @param Zend_Acl_Resource_Interface|string $resource
     * @return Zend_Acl_Resource_Interface|null
     */
    public function getParent($resource) {
        $resourceId = $this->get($resource)->getResourceId();
        return $this->_resources[ $resourceId ]['parent'];
    }
    
    /**
     * @param Zend_Acl_Resource_Interface|string $resource
     * @return array([ string => Zend_Acl_Resource_Interface[, ...]])
     */
    public function getAllParents($resource) {
        $resource = $this->get($resource);
        
        $parents = array();
        do {
            $parent = $this->getParent($resource);
            if (!$parent) {
                break;
            } else {
                $resource = $parent;
                $parents[ $parent->getResourceId() ] = $parent;
            }
        } while (true);
        
        return $parents;
    }
    
    // This method must implemented in Zend_Acl_Role_Registry
    public function getAllParentRoles($role) {
        $role = $this->getRole($role);
        
        $parents = $this->_getRoleRegistry()->getParents($role);
        foreach ($parents as $role) {
            $parents = array_merge($parents, $this->getAllParentRoles($role));
        }
        
        return $parents;
    }

Comments

Assigning to Darby.


    /**
     * Returns all the Roles 
     * 
     * @uses   Zend_Acl_Role_Registry::getAll()
     * @return Zend_Acl_Role_Interface[]
     */
    public function getRoleAll()
    {
        return $this->_getRoleRegistry()->getAll();
    }
    
    /**
     * Returns an array with the given Role's parents
     *
     * @uses Zend_Acl_Role_Registry::getParents()
     * @return array()
     */
    public function getRoleParents($role) 
    {
        return $this->_getRoleRegistry()->getParents($role);
    }
    
    /**
     * Returns an array with all the given Role's parents and ancestors, parsed BF
     *
     * @param Zend_Acl_Role_Interface|string $role
     * @return array
     */
    public function getRoleAllParents($role) 
    {
        return $this->_getRoleRegistry()->getAllParents($role);
    }

//
//
//


    /**
     * Returns parent resource for a given resource
     * 
     * @param Zend_Acl_Resource_Interface|string $resource
     * @return Zend_Acl_Resource_Interface|null
     */
    public function getParent($resource) {
        $resourceId = $this->get($resource)->getResourceId();
        return $this->_resources[ $resourceId ]['parent'];
    }
    
    /**
     * Returns child resources for a given resource
     *
     * @param Zend_Acl_Resource_Interface|string $resource
     * @throws Zend_Acl_Exception
     * @return Zend_Acl_Resource_Interface[]
     */
    public function getChildren( $resource )
    {
        if($resource == null){
            $resourceId = null;
        } else {
            if ($resource instanceof Zend_Acl_Resource_Interface) {
                $resourceId = $resource->getResourceId();
            } else {
                $resourceId = (string) $resource;
            }

            if (!$this->has($resource)) {
                require_once 'Zend/Acl/Exception.php';
                throw new Zend_Acl_Exception("Resource '$resourceId' not found");
            }
        }

        $children = array();
        
        if($resourceId == null)
        {
            foreach($this->_resources as $currentResourceId => $currentResource) {
                if($currentResource['parent'] == null) {
                    $children[$currentResourceId] = $currentResource['instance'];
                }
            }
        }
        else {
            $children = $this->_resources[$resourceId]['children'];
        }

        return $children;
    }


    /**
     * returns all the roles in the registry
     * 
     * @return Zend_Acl_Role_Interface
     */
    public function getAll()
    {
        $roles = array();
        
        foreach($this->_roles as $currentRole)
        {
            $roles[] = $currentRole['instance'];
        }
        return $roles;
    }

    /**
     * Returns an array of an existing Role's parents, parsed in BF fashion
     *
     * @param Zend_Acl_Role_Interface|string $role
     * @return array
     */
    public function getAllParents($role) 
    {   
        $parents = $this->getParents($role);
        
        foreach ($parents as $role) {
            $parents = array_merge($parents, $this->getAllParents($role));
        }
        
        return $parents;
    }

There should also be some methods for retrieving Role children. I'm working on those, and will post them here.

Resources are organized into a tree. Therefore, at most one parent resource can exist for any given resource.

Roles are organized into a directed acyclic graph (DAG). Therefore, a role may have zero, one, or more than one parent roles.

I see that the intent is to fetch all ancestors (i.e., parents, grandparents, and so on) of a role or resource. Though this is fine, the results hide the actual data structure. For example, it is not apparent whether a returned "parent" resource is actually a parent, the parent of a parent, and so on.

Further, for what purpose is such information useful, I'm curious? That is, what use case requirements do these new methods help to meet?

It seems logical to be able to interrogate the Acl object once created, to meet the needs of (say) a CMS, where roles, resources and permissions vary dynamically to match the structure of the content.

A typical use case would be listing all the Roles defined in the Acl:


//users will be stored in the DB, in order to also allow authorization using Zend_Auth
class Pornlist_Db_Users_Row extends Zend_Db_Table_Row_Abstract implements Zend_Acl_Role_Interface
{
//
//
//
}

foreach($acl->getRoleAll() as $role)
        {
                // we don't want to display users stored in the Acl
            if($role instanceof MyApp_Acl_Role_User) continue;
            
            $parents = $acl->getRoleParents($role);
            
            $parents_data = array();
            foreach($parents as $parent)
            {
                $parents_data[] = $parent->getRoleId();
            }
            
            $role_data[] = array( 
                'name'      => $role->getRoleId(),
                'parents'   => $parents_data, 
                'actions'   => array(
                    'delete'    => '/admin/aclroles/delete/id/'.$role->getRoleId(),
                    'edit'      => '/admin/aclroles/edit/id/'.$role->getRoleId(),
                )
            );
        }

While this is a worthwhile feature, the ZF team will not develop this feature, but if a community member would like to pick up and develop it, they may make an assignment of it.

Reassigned to component maintainer