I'm wondering if anyone knows of an elegant way to achieve this using the Symfony2 ACL system.
I have a Comment
entity (my domain object) which needs to be editable by ROLE_USER
but this is only allowed within 5 minutes of the comment being posted - otherwise the comment can only be edited by ROLE_ADMIN
.
Making it so that it can only be edited by ROLE_USER
and ROLE_ADMIN
is simple, just make a RoleSecurityIdentity
for each.
Now my problem occurs when I want to incorporate the time factor for ROLE_USER
. My first problem is that it needs information from the domain object, not just the ACL table but I think this is solvable by making a custom ObjectIdentity
class which can also hold the time that the Comment
was posted.
Now for the hard part
I think I need to create a custom PermissionGrantingStrategy
that knows to also look at the creation time. This has to be loaded when a Comment
type is being checked, but I don't know how to get it to load. Does anyone know if there's some kind of factory through which this sort of thing can be configured? So that if an entity has a specific PermissionGrantingStrategy
associated with it then it gets used otherwise the default is used?
I know this is a bit of a long one, many thanks if anyone knows how to achieve this as the ACL documentation seems a tad sparse at the moment. My fallback solution is to simply make some kind of service to check if a Comment can be edited and not bother with ACL at all.
I'm posting this solution so that others can see my final code but here are the pitfalls I found when implementing a Voter as Problematic suggested.
supportsAttribute: It appears that when you call the
isGranted
method on theSecurityContext
that it doesn't actually check this method before delegating avote
call to aVoterInterface
so inside yourvote
method you actually have to check the attributes yourself.supportsClass: In problematic's answer above it seemed like this method could be a key for a Factory based selection of which
VoterInterface
s can vote but actually the symfony2 documentation reads:Therefore it actually seems to pertain to whether or not the
Voter
supports the token type. To make matters worse the PHP Doc seems vague:At any rate the main problem is that this method is never checked by the
SecurityContext
before delegating the call to thevote
method of any voter - even if this method is hardcoded toreturn false
vote
will still be called!So basically the moral of the story appeared to be: check the
$attributes
and$object
coming in on thevote
method manually.My Code:
services.yml
and the voter class:
and finally template:
I hope this helps someone else in the future and a big thanks to Problematic for pointing me in the direction of Voters.
Have you considered using a voter? There's a cookbook recipe for implementing an IP blacklist voter, but it could be easily modified to handle checking for edits on Comment objects.
You can look at the default AclVoter at
Symfony\Component\Security\Acl\Voter\AclVoter
(online here), though yours can obviously augment instead of replace it and be much simpler.As a quick proof of concept: