Пакет FOS - Как выбрать пользователей с определенной ролью? - PullRequest
52 голосов
/ 26 января 2012

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

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

Ответы [ 7 ]

96 голосов
/ 22 мая 2013

Просто добавьте это в свой 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();
}
24 голосов
/ 29 января 2012

Что ж, если нет лучшего решения, думаю, я перейду к 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();
10 голосов
/ 06 января 2015

Как утверждает @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, но я уверен, что она не будет такой особенной.

9 голосов
/ 26 января 2012

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

0 голосов
/ 17 декабря 2018

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

entities:
    Admin:
        class: App\Entity\User
        list:
            dql_filter: "entity.roles LIKE '%%ROLE_ADMIN%%'"
0 голосов
/ 07 марта 2016

Наконец я решил, вот точное решение:

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

Ура! * * 1004

0 голосов
/ 04 марта 2015

Вы можете использовать только это на своем 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%");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...