FOS包 - 如何选择具有特定角色的用户?

时间:2012-01-26 10:40:57

标签: symfony

我正在使用FOS捆绑包,我想从数据库中检索具有给定ROLE的所有用户。

这样做的最佳方式是什么?

7 个答案:

答案 0 :(得分:94)

只需在您的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();
}

答案 1 :(得分:24)

好吧,如果没有更好的解决方案,我想我会转到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();

答案 2 :(得分:10)

正如@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');
}

我没有进入Doctrine ORM,但我确信它不会如此不同。

答案 3 :(得分:9)

如果您有此要求并且您的用户列表范围很广,则会遇到性能问题。我认为你不应该将角色作为序列化数组存储在字段中。您应该创建一个实体角色以及与users表的多对多关系。

答案 4 :(得分:0)

您可以在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%");

答案 5 :(得分:0)

最后我解决了它,以下是一个精确的解决方案:

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

干杯!

答案 6 :(得分:0)

如果您需要使用YAML文件(例如,在EasyAdminBundle中)中的DQL过滤器按角色过滤用户,则

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