Hi,

Aldemar Bernal wrote:
http://devzone.zend.com/article/3509-Zend_Acl-and-MVC-Integration-Part-I-Basic-Use http://devzone.zend.com/article/3510-Zend_Acl-and-MVC-Integration-Part-II-Advanced-Use

Yeah these articles were useful when I read them earlier.

The most useful bit is at the end of the second link where you do the kind of check I'm interested in, but it is done very much in the controller rather than the acl itself.

I appreciate that I'm being quite pedantic here, but I'd rather have the controller set some sort of data on the resource object itself and have this checked in an assertion in the ACL (the semantics are very similar, just a slight architectural difference). In my previous example I suggested a static method but really you'd probably want to piggy back a resource implementation onto some other object (see below for my example).

Why do I want to do it this way?

Well I want to be able to define roles dynamically. In my app I have a way to list all the resources available and for each resource, what privileges and assertions apply to them.

This way a role can be defined very specifically and tailored to individual needs. By putting the test itself in the controller I cannot have this degree of control. If the controller sets a value on the resource and it is up to the assert() method to do the test, the flexibility is maintained (e.g. if the current user's ACL has or does not have the assert applied to it).



To elaborate: In your example you have:

    public function editAction()
    {
        /** Load article by id */
        $article = new Article($this->_request->id);

        /** Validate if the user is the owner or an Admin */
if (($article->author != $this->_application->loggedUser) && ($this->_application->currentRole != 'admin')) {
            $this->_acl->denyAccess();
        }

        ...
    }


Here the action itself has special knowledge of how your ACL operates and imeplements ACL features manually (the allowing of admins to access all articles). But I would propose something a little bit different but which leveraged the power of the ACL system and use and assert.

The assert would be something like:


class My_Article_Access
  implements Zend_Acl_Assert_Interface
{
  public function assert(
    Zend_Acl $acl,
    Zend_Acl_Role_Interface $role = null,
    Zend_Acl_Resource $resource = null,
    $privilege = null)
  {
    /** This assert requires that $resource is and Article object.
      * We cannot do this in the argument definition as it would no
      * longer match the interface.
      * Obviously article implements Zend_Acl_Resource_Interface */
    if (!($resource instanceof Article))
      return false; // or throw....

    $app = new Zend_Session_Namespace('myApplication');

    return ($app->loggedUser == $resource->author);
  }
}



and the editAction becomes something like:
(NB, I've assumed the Zend_Acl object is available via $this->_application->acl)


    public function editAction()
    {
        /** Load article by id */
        $article = new Article($this->_request->id);

        /** NB Article also implements Zend_Acl_Resource
          * and obviously knows it's own id  */

        /** Inject the article ID into the resource */
        if (!$this->_application->acl->isAllowed(
              $this->_application->currentRole,
              $article,
              'edit'))
        {
          $this->_acl->denyAccess();
        }

        ...
    }



I think this is a better approach than in your example as it means that the knowledge of the role and what it means is kept out of your controller and action logic. It's kept inside the ACL system which is where IMO it belongs.


What do you think?

Col (who hopes he's explained it well enough!)



--

Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/

Day Job:
  Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
  Mandriva Linux Contributor [http://www.mandriva.com/]
  PulseAudio Hacker [http://www.pulseaudio.org/]
  Trac Hacker [http://trac.edgewall.org/]

Reply via email to