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/]