Search code examples
phpsymfonysymfony-3.3symfony-security

Symfony voter and multiples reasons


I will use a simple situation for explain :

  • I have "news" entity
  • I have "new categories" entities

In administration, I want to check if I can delete news category.

  • If you dont have "ROLE_SUPERADMIN", you can't ;
  • If news category is linked (= used in category), you can't.

When control that ?

If I use Symfony Voters :

class NewsCategoryVoter extends Voter {

    ....

    private function canDelete(NewsCategory $newsCategory, User $user)
    {
        // Check ROLE and Count in NewsRepository if $newsCategory is used. I have not yet coded this.
        return false;
    }

I have a problem :

  • I can't get the reason why he can not remove. In twig and after is_granted('delete', category), idealy :

You can't delete because ...

Can you help me ?

Please, keep in mind that this situation is very simple. In my situation, I have many reasons (> 10) to reject a deletion or modification, almost always because of a relationship in database


Solution

  • Because the Voter is just another service, you can add whatever properties, or other classes/services you want or need to be able to store some sort of reason as to why something did, or did not happen.

    public static $reason;
    
    // in the voter, make grant/deny/abstain choices...
    if ($user->hasRole('ROLE_SUPER_ADMIN')) {
        self::$reason = "is super-admin";
        $this->log->debug("FeatureVoter | {$user} is super-admin");
        return VoterInterface::ACCESS_GRANTED;
    }
    
    // after is_granted()
    echo VoterClass::$reason;
    

    I already had logging in the voter, and so some other notification mechanism would be just as easy. Here, I've just added a static variable in the Voter, and can read it out externally. You can trivially make that an array that could be added to, (and cleared before voting started), or noting a reason why something did, or didn't happen in an external service that can be retrieved.