Chi
Chi

Reputation: 1410

Symfony - use voter in entityRepository

My problem is this: I have a page /user which shows a list of all users. The page is visible only to those who are logged in and, depending on what kind of user the currently logged in user is, he sees only parts of the list. I figured that a voter would be a good solution to this (if there's a better one please let me know), but I have a problem with supportsClass. The userlist is a query in UserRepository named getAllUsers and I tried passing the securityContext to the repository so I can query if the current user has access or not. My action looks like this:

    public function listAction($limit = 50, $offset = 0) {
        $manager = $this->getDoctrine()->getManager();
        $userRepository = $manager->getRepository('SeamUserBundle:User');
        $users = $userRepository->getAllUsers($this->get('security.context'));
        return ....
    }

and in userRepository I tried this:

public function getAllUsers($securityContext) {
    ....         
    if(!$securityContext->isGranted('USER_LIST_ALL', null)) {
       //modify query
    }
    ...
}

but if I pass null as a second parameter to isGranted, the $class is now the Voter and therefore supportsClass returns false. Am I doing this the wrong way? If so - how do I do this? If not - what's missing? How do I pass the user entity to isGranted?

Thanks in advance.

Upvotes: 1

Views: 2691

Answers (1)

Jindra
Jindra

Reputation: 810

To grant permission on global basis you want to use roles instead of voters.

Diference between roles and voters:

Voter is there to tell if user can perform action on object (relation user-action-instance_of_object). Logic behind voters is up to you. You need to implement them and symfony only finds voters and collects their decision. Example: User can edit specific instance of article.

Role is there to tell if user has global permission (relation user-action). Logic behind roles is handled by symfony. You only add roles to user and require roles on $securityContext. Example: user can write new article.

Listing all users is based on what user can do hence it is job for role. You need to add role ROLE_USER_LIST_ALL to users that are allowed to list all users. You should probably do that in UserProvider when user is logging in. All you need to do is as UserInterface requires implement getRoles. Some information about defining roles in database can be found in symfony docs

Then in your UserRepository call

$securityContext->isGranted('ROLE_USER_LIST_ALL');

Notice there is not second parameter because it is global permission not related to specific object instances.

Also it isn't ideal to pass security context as param for getter. Instead it might be good idea to specify repository as service and set security context.

services:
   seam.user.repository:
    class: Seam\UserBundle\UserRepository
    factory_service: doctrine.orm.entity_manager
    factory_method: getRepository
    arguments:
      - Seam\UserBundle\User
    calls:
      - [ setSecurityContext, [@security.context] ]

Then you can retrieve it with

$container->get('seam.user.repository); 
//in controler use $this instead of $container

(You need to implemenet setSecurityContext in your UserRepository class)

Upvotes: 1

Related Questions