Pacote FOS – Como selecionar usuários com uma function específica?

Estou usando o pacote FOS e desejo recuperar todos os usuários com um determinado ROLE do database.

Qual é a melhor maneira de fazer isso?

Basta adicionar isso no seu UserRepository ou replace $this->_entityName por YourUserBundle:User :

 /** * @param string $role * * @return array */ public function findByRole($role) { $qb = $this->_em->createQueryBuilder(); $qb->select('u') ->from($this->_entityName, 'u') ->where('u.roles LIKE :roles') ->setParameter('roles', '%"'.$role.'"%'); return $qb->getQuery()->getResult(); } 

Se você estiver usando grupos FOSUser você deve usar:

 /** * @param string $role * * @return array */ public function findByRole($role) { $qb = $this->_em->createQueryBuilder(); $qb->select('u') ->from($this->_entityName, 'u') ->leftJoin('u.groups', 'g') ->where($qb->expr()->orX( $qb->expr()->like('u.roles', ':roles'), $qb->expr()->like('g.roles', ':roles') )) ->setParameter('roles', '%"'.$role.'"%'); return $qb->getQuery()->getResult(); } 

Bem, se não houver uma solução melhor, acho que irei a uma consulta DQL:

 $query = $this->getDoctrine()->getEntityManager() ->createQuery( 'SELECT u FROM MyBundle:User u WHERE u.roles LIKE :role' )->setParameter('role', '%"ROLE_MY_ADMIN"%'); $users = $query->getResult(); 

Se você tiver esse requisito e sua lista de usuários for extensa, você terá problemas com o desempenho. Eu acho que você não deve armazenar os papéis em um campo como uma matriz serializada. Você deve criar um papel de entidade e muitos para muitos relacionamento com a tabela de usuários.

Como afirma @Tirithen, o problema é que você não obterá os usuários que têm uma function implícita devido à hierarquia de papéis. Mas há uma maneira de contornar isso!

O componente de segurança do Symfony fornece um serviço que nos fornece todas as funções filhas para funções pai específicas. Podemos criar um serviço que faz quase a mesma coisa, apenas nos dá todas as funções de pai para uma determinada function filho.

Crie um novo serviço:

 namespace Foo\BarBundle\Role; use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\Role; /** * ReversedRoleHierarchy defines a reversed role hierarchy. */ class ReversedRoleHierarchy extends RoleHierarchy { /** * Constructor. * * @param array $hierarchy An array defining the hierarchy */ public function __construct(array $hierarchy) { // Reverse the role hierarchy. $reversed = []; foreach ($hierarchy as $main => $roles) { foreach ($roles as $role) { $reversed[$role][] = $main; } } // Use the original algorithm to build the role map. parent::__construct($reversed); } /** * Helper function to get an array of strings * * @param array $roleNames An array of string role names * * @return array An array of string role names */ public function getParentRoles(array $roleNames) { $roles = []; foreach ($roleNames as $roleName) { $roles[] = new Role($roleName); } $results = []; foreach ($this->getReachableRoles($roles) as $parent) { $results[] = $parent->getRole(); } return $results; } } 

Defina seu serviço, por exemplo, em yaml e injete a hierarquia de papéis:

 # Provide a service that gives you all parent roles for a given role. foo.bar.reversed_role_hierarchy: class: Foo\BarBundle\Role\ReversedRoleHierarchy arguments: ["%security.role_hierarchy.roles%"] 

Agora você está pronto para usar a class em seu próprio serviço. Chamando $injectedService->getParentRoles(['ROLE_YOUR_ROLE']); você receberá uma matriz contendo todas as funções dos pais que levarão à permissão “ROLE_YOUR_ROLE”. Consulta para usuários que possuem um ou mais desses papéis … lucro!

Por exemplo, quando você usa o MongoDB, pode adicionar um método ao seu repository de documentos do usuário:

 /** * Find all users with a specific role. */ public function fetchByRoles($roles = []) { return $this->createQueryBuilder('u') ->field('roles')->in($roles) ->sort('email', 'asc'); } 

Eu não estou na Doutrina ORM, mas tenho certeza que não será tão diferente.

Você pode usar apenas isso no seu DQL:

 SELECT u FROM YourFavouriteBundle:User u WHERE u.roles [NOT] LIKE '%ROLE_YOUR_ROLE%' 

Claro que com o QueryBuilder é mais elegante:

 // $role = 'ROLE_YOUR_ROLE'; $qb->where('u.roles [NOT] LIKE :role') ->setParameter('role', "%$role%"); 

Finalmente eu resolvi isso, seguindo é uma solução exata:

 public function searchUsers($formData) { $em = $this->getEntityManager(); $usersRepository = $em->getRepository('ModelBundle:User'); $qb = $usersRepository->createQueryBuilder('r'); foreach ($formData as $field => $value) { if($field == "roles"){ $qb->andWhere(":value_$field MEMBER OF r.roles")->setParameter("value_$field", $value); }else{ $qb->andWhere("r.$field = :value_$field")->setParameter("value_$field", $value); } } return $qb->getQuery()->getResult(); } 

Felicidades!

ESTA SOLUÇÃO É MAU, mas funciona

Etapa 1: faça um loop por cada usuário
Etapa 2: verifique se o usuário tem o papel “roleadmin”
Etapa 3: crie uma nova matriz com todos os usuários a function admin:

 $allowedUsers = array(); $em = $this->getDoctrine()->getEntityManager(); $entities = $em->getRepository('YourBundle:User')->findAll(); foreach($entities as $user){ foreach($user->getRoles() as $role){ if($role == "ROLE_ADMIN"){ $allowedUsers = $user; } } } return $allowedUsers; 

Melhor solução é fazer consulta DQL como olivierw escreveu