Search code examples
phpsymfonysymfony6

How to pass subject to is_granted (Symfony) function in Expression and php attribute


I'm working on a project with Symfony 6.2, Doctrine 2 and php 8.

I would like to do some check on method of controller via IsGranted (php attribute). In simple word, i want to check this :

  • is_granted('ROLE_OPERATOR_USER') AND
  • is_granted(OperatorVoter::UPDATE) AND
  • is_granted(OperatorRightVoter:HAS_RIGHT, $operator)

In order to do the and, i'm using Expression. However i do not find how to pass the parameter $operator as subject to the Expression.

here my code :

    #[Route(path        : '/edit/{id}',
            name        : 'resources_operator_edit',
            requirements: ['id' => '\d+'],
            options     : ['menu' => true],
            defaults    : ['user_activity' => ['access' => true, 'name' => 'platform_user_activity.operator_edit']],
            methods     : ['GET', 'POST'])
    ]
    #[IsGranted(
        attribute: new Expression("is_granted('ROLE_GA_OPERATOR_USER') and is_granted(constant('\\\App\\\Security\\\Voter\\\OperatorVoter::UPDATE'))
    and is_granted(constant('\\\App\\\Security\\\Voter\\\OperatorRightVoter::HAS_RIGHT'), operator)"),
        subject  : new Expression('args["operator"]')
    )]
    public function edit (Request $request, Operator $operator): Response
    {
    // some code
    }

And OperatorRightVoter

class OperatorRightVoter extends Voter
{
    const HAS_RIGHT = 'operatorHAS_RIGHT';

    public function __construct (protected RequestStack $requestStack, protected Security $security)
    {
    }

    protected function supports ($attribute, $subject): bool
    {
        if ($attribute != self::HAS_RIGHT) {
            return false;
        }

        return true;
    }

    /**
     * @inheritDoc
     */
    protected function voteOnAttribute (string $attribute, $subject, TokenInterface $token): bool
    {
        $user = $token->getUser();

        // the user must be logged in; if not, deny permission
        if (!$user instanceof User) {
            return false;
        }

        dd($subject);
        dd($user->getBusinessUnit()->hasPermissionOperator($subject));
//        if ($this->security->isGranted('ROLE_GA_OPERATOR_ADMIN')) {
//            return true;
//        }
     }
}

I tried to set the subject and pass to the attribute, but it's not working for a is_granted inside a Expression. operator is not known. It's working if i pass a "build in" variable such as user. However i want to pass the variable $operator somehow. Do i do incorrectly or there is another way to do that ?

I would like to avoid if possible to do the test in the method via ->isGranted(). I would prefer to do it via php attribute. Any idea or advice please ?

Thanks


Solution

  • You should make something like:

    #[IsGranted(
            attribute: new Expression("is_granted('ROLE_GA_OPERATOR_USER') and is_granted(constant('\\\App\\\Security\\\Voter\\\OperatorVoter::UPDATE'))
        and is_granted(constant('\\\App\\\Security\\\Voter\\\OperatorRightVoter::HAS_RIGHT'), subject)"),
            subject  : 'operator'
        )]
    

    actually, in expression you should pass predefined variable 'subject' and then define subject of attribute IsGranted.