it-swarm.com.de

FOS-Bundle - Wie werden Benutzer mit einer bestimmten Rolle ausgewählt?

Ich verwende das FOS-Paket und möchte alle Benutzer mit einer bestimmten ROLE aus der Datenbank abrufen.

Was ist der beste Weg, dies zu tun?

51
Visavì

Fügen Sie dies einfach in Ihr UserRepository ein oder ersetzen Sie $this->_entityName durch 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();
}

Wenn Sie FOSUser-Gruppen verwenden, sollten Sie Folgendes verwenden:

/**
 * @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();
}
89
Léo Benoist

Wenn es keine bessere Lösung gibt, denke ich, gehe ich zu einer DQL-Abfrage:

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

$users = $query->getResult();
24
Visavì

Wie @Tirithen feststellt, besteht das Problem darin, dass Sie nicht die Benutzer erhalten, die aufgrund der Rollenhierarchie eine implizite Rolle haben. Aber es gibt eine Möglichkeit, das zu umgehen!

Die Symfony-Sicherheitskomponente bietet einen Service, der uns alle untergeordneten Rollen für eine bestimmte übergeordnete Rolle gibt. Wir können einen Dienst erstellen, der fast das Gleiche tut, nur dass wir alle übergeordneten Rollen für eine bestimmte untergeordnete Rolle erhalten.

Erstellen Sie einen neuen Service:

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

Definieren Sie Ihren Service beispielsweise in yaml und fügen Sie die Rollenhierarchie hinzu:

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

Jetzt können Sie die Klasse in Ihrem eigenen Service verwenden. Durch Aufruf von $injectedService->getParentRoles(['ROLE_YOUR_ROLE']); erhalten Sie ein Array mit allen übergeordneten Rollen, die zur Berechtigung 'ROLE_YOUR_ROLE' führen. Fragen Sie nach Benutzern, die eine oder mehrere dieser Rollen haben ... profitieren Sie!

Wenn Sie beispielsweise MongoDB verwenden, können Sie Ihrem Benutzerdokument-Repository eine Methode hinzufügen:

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

Doctrine ORM mag ich nicht, aber ich bin mir sicher, dass es nicht so anders sein wird.

10
Xatoo

Wenn Sie diese Anforderung haben und Ihre Benutzerliste umfangreich ist, treten Probleme mit der Leistung auf. Ich denke, Sie sollten die Rollen in einem Feld nicht als serialisiertes Array speichern. Sie sollten eine Entitätsrolle und viele bis viele Beziehungen zur Benutzertabelle erstellen.

9
smoreno

Sie können dies einfach auf Ihrem DQL verwenden:

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

Mit QueryBuilder ist es natürlich eleganter:

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

Zum Schluss habe ich es gelöst, folgendes ist eine genaue Lösung:

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

Prost!

0
Muzafar Ali

Für den Fall, dass Sie Benutzer nach Rolle filtern müssen, indem Sie einen DQL-Filter in einer YAML-Datei verwenden (beispielsweise in EasyAdminBundle)

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