FOS bundle - Как выбрать пользователей с определенной ролью? - программирование
Подтвердить что ты не робот

FOS bundle - Как выбрать пользователей с определенной ролью?

Я использую пакет FOS, и хочу получить всех пользователей с заданным ROLE из базы данных.

Каков наилучший способ сделать это?

4b9b3361

Ответ 1

Просто добавьте это в свой UserRepository или замените $this->_entityName на 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();
}

Если вы используете группы FOSUser, вы должны использовать:

/**
 * @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();
}

Ответ 2

Хорошо, если нет лучшего решения, я думаю, что перейду к запросу 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();

Ответ 3

Как указано в @Tirithen, проблема заключается в том, что вы не получите пользователей, у которых есть неявная роль из-за иерархии ролей. Но есть способ обойти это!

Компонент безопасности Symfony предоставляет услугу, которая дает нам все дочерние роли для определенных родительских ролей. Мы можем создать сервис, который делает почти то же самое, только он дает нам все родительские роли для данной дочерней роли.

Создайте новый сервис:

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;
    }
}

Определите свою службу, например, в yaml, и введите иерархию роли в нее:

# 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%"]

Теперь вы готовы использовать класс в своей собственной службе. Вызвав $injectedService->getParentRoles(['ROLE_YOUR_ROLE']);, вы получите массив, содержащий все родительские роли, которые приведут к разрешению "ROLE_YOUR_ROLE". Запрос для пользователей, которые имеют одну или несколько из этих ролей... прибыль!

Например, когда вы используете MongoDB, вы можете добавить метод в свой репозиторий документов пользователя:

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

Я не в ORM доктрины, но я уверен, что это будет не так.

Ответ 4

Если у вас есть это требование, и ваш список пользователей будет обширным, у вас будут проблемы с производительностью. Я думаю, вы не должны хранить роли в поле как сериализованный массив. Вы должны создать роли сущностей и много-много отношений с таблицей пользователей.

Ответ 5

Вы можете использовать именно это на своем DQL:

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

Конечно, с QueryBuilder это более элегантно:

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

Ответ 6

Наконец, я решил, что следующее точное решение:

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();
}

Ура!

Ответ 7

Если вам нужно отфильтровать пользователей по ролям, используя фильтр DQL в файле YAML (например, в EasyAdminBundle)

entities:
    Admin:
        class: App\Entity\User
        list:
            dql_filter: "entity.roles LIKE '%%ROLE_ADMIN%%'"

Ответ 8

ЭТО РЕШЕНИЕ НЕИСПРАВНО, но оно работает

Шаг 1: Петля через каждого пользователя
Шаг 2. Проверьте, имеет ли пользователь роль "roleadmin"
Шаг 3: создайте новый массив со всеми пользователями роль 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;

Лучшее решение - сделать DQL-запрос как olivierw написал