Sometimes, I have a page where I want to react to a complex combination of different rules, which altogether amount to just a single thing: 'can the current user do this?'.
At the moment, most of those checks are directly within my controller, so I'd have for example:
if($this->isGranted('DRAFT_EDITOR', $draft) && $now < $deadline && $draft->getStatus() != Draft::STATUS_FINAL) {...}
Those sorts of if conditions get pretty long, and could potentially end up being repeated throughout the code, all achieving precisely the same thing. So I wanted to abstract these out into Voters, so that I could just say:
if($this->isGranted('DRAFT_CAN_EDIT') {}
That would then go to a DraftCanEdit voter which would encapsulate all those checks from the IF statement at the top of this post in one place, and make it easy to change the rules for what makes a draft editable, harder to accidentally miss a condition or mess one up somewhere and create vulnerabilities, etc.
The problem is that voters can't call isGranted(), because it's considered a circular reference just to inject into a voter the security.authorization_checker service.
To me, a Voter calling isGranted seems semantically fine as a form of voter inheritance, and so long as the Voter doesn't support the attribute/subject that it passes to isGranted, shouldn't actually result in any kind of circular reference issues.
Of course, I could duplicate the DraftEditorVoter logic inside the DraftCanEditVoter, or I could instantiate a DraftEditorVoter inside DraftCanEditVoter, but neither of these seem ideal, not just for reasons of code duplication but also because I actually have two voters that, together, determine if someone is a DRAFT_EDITOR or not.
I also am aware I could encapsulate the IF conditions by just making my own non-Voter object and using it directly like that but think that may be a bit of an anti-pattern.
DraftEditorVoter
into yourDraftCanEditVoter
voter? Also, ain't voters designed to come to a common conclusion? Like, at least one has to vote yes, or at least 50% have to vote yes, or none has to vote no. - Joshua