简体   繁体   中英

set role for users in edit form of sonata admin

I'm using Symfony 2.1 for a project. I use the FOSUserBundle for managing users & SonataAdminBundle for administration usage.

I have some questions about that:

  1. As an admin, I want to set roles from users in users edit form. How can I have access to roles in role_hierarchy ? And how can I use them as choice fields so the admin can set roles to users?

  2. When I show roles in a list, it is shown as string like this:

     [0 => ROLE_SUPER_ADMIN] [1 => ROLE_USER] 

    How can I change it to this?

     ROLE_SUPER_ADMIN, ROLE_USER 

    I mean, having just the value of the array.

Based on the answer of @parisssss although it was wrong, here is a working solution. The Sonata input field will show all the roles that are under the given role if you save one role.

On the other hand, in the database will be stored only the most important role. But that makes absolute sense in the Sf way.

protected function configureFormFields(FormMapper $formMapper) {
// ..
$container = $this->getConfigurationPool()->getContainer();
$roles = $container->getParameter('security.role_hierarchy.roles');

$rolesChoices = self::flattenRoles($roles);

$formMapper
    //...
    ->add('roles', 'choice', array(
           'choices'  => $rolesChoices,
           'multiple' => true
        )
    );

And in another method:

/**
 * Turns the role's array keys into string <ROLES_NAME> keys.
 * @todo Move to convenience or make it recursive ? ;-)
 */
protected static function flattenRoles($rolesHierarchy) 
{
    $flatRoles = array();
    foreach($rolesHierarchy as $roles) {

        if(empty($roles)) {
            continue;
        }

        foreach($roles as $role) {
            if(!isset($flatRoles[$role])) {
                $flatRoles[$role] = $role;
            }
        }
    }

    return $flatRoles;
}

See it in action:

在此输入图像描述在此输入图像描述

As for the second question I added a method in the User class that looks like this

/**
 * @return string
 */
 public function getRolesAsString()
 {
     $roles = array();
     foreach ($this->getRoles() as $role) {
        $role = explode('_', $role);
        array_shift($role);
        $roles[] = ucfirst(strtolower(implode(' ', $role)));
     }

     return implode(', ', $roles);
 }

And then you can declare in your configureListFields function:

->add('rolesAsString', 'string')

i found an answer for my first question!(but the second one in not answered yet..) i add the roles like below in configureFormFields function :

  protected function configureFormFields(FormMapper $formMapper) {
  //..
 $formMapper
 ->add('roles','choice',array('choices'=>$this->getConfigurationPool()->getContainer()->getParameter('security.role_hierarchy.roles'),'multiple'=>true ));
}

I would be very happy if anyone answers the second question :)

Romain Bruckert's solution is almost perfect, except that it doesn't allow to set roles, which are roots of role hierrarchy. For instance ROLE_SUPER_ADMIN. Here's the fixed method flattenRoles, which also returns root roles:

protected static function flattenRoles($rolesHierarchy)
{
    $flatRoles = [];
    foreach ($rolesHierarchy as $key => $roles) {
        $flatRoles[$key] = $key;
        if (empty($roles)) {
            continue;
        }

        foreach($roles as $role) {
            if(!isset($flatRoles[$role])) {
                $flatRoles[$role] = $role;
            }
        }
    }

    return $flatRoles;
}

Edit: TrtG already posted this fix in comments

Just to overplay it a bit, here is my enhanced version of Romain Bruckert and Sash which gives you an array like this:

array:4 [▼
  "ROLE_USER" => "User"
  "ROLE_ALLOWED_TO_SWITCH" => "Allowed To Switch"
  "ROLE_ADMIN" => "Admin (User, Allowed To Switch)"
  "ROLE_SUPER_ADMIN" => "Super Admin (Admin (User, Allowed To Switch))"
]

在此输入图像描述

This helps you find all roles , that include a specific role: 在此输入图像描述

I know its much code, it could be done much better, but maybe it helps somebody or you can at least use pieces of this code.

/**
 * Turns the role's array keys into string <ROLES_NAME> keys.
 * @param array $rolesHierarchy
 * @param bool $niceName
 * @param bool $withChildren
 * @param bool $withGrandChildren
 * @return array
 */
protected static function flattenRoles($rolesHierarchy, $niceName = false, $withChildren = false, $withGrandChildren = false)
{
    $flatRoles = [];
    foreach ($rolesHierarchy as $key => $roles) {
        if(!empty($roles)) {
            foreach($roles as $role) {
                if(!isset($flatRoles[$role])) {
                    $flatRoles[$role] = $niceName ? self::niceRoleName($role) : $role;
                }
            }
        }
        $flatRoles[$key] = $niceName ? self::niceRoleName($key) : $key;
        if ($withChildren && !empty($roles)) {
            if (!$recursive) {
                if ($niceName) {
                    array_walk($roles, function(&$item) { $item = self::niceRoleName($item);});
                }
                $flatRoles[$key] .= ' (' . join(', ', $roles) . ')';
            } else {
                $childRoles = [];
                foreach($roles as $role) {
                    $childRoles[$role] = $niceName ? self::niceRoleName($role) : $role;
                    if (!empty($rolesHierarchy[$role])) {
                        if ($niceName) {
                            array_walk($rolesHierarchy[$role], function(&$item) { $item = self::niceRoleName($item);});
                        }
                        $childRoles[$role] .= ' (' . join(', ', $rolesHierarchy[$role]) . ')';
                    }
                }
                $flatRoles[$key] .= ' (' . join(', ', $childRoles) . ')';
            }
        }
    }
    return $flatRoles;
}

/**
 * Remove underscors, ROLE_ prefix and uppercase words
 * @param string $role
 * @return string
 */
protected static function niceRoleName($role) {
    return ucwords(strtolower(preg_replace(['/\AROLE_/', '/_/'], ['', ' '], $role)));
}

The second answer is below. Add lines in sonata admin yml file .

sonata_doctrine_orm_admin:
    templates:
        types:
            list:
                user_roles: AcmeDemoBundle:Default:user_roles.html.twig

and in user_roles.html.twig files add below lines

{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}

{% block field %}
    {% for row in value %}
        {{row}}
        {% if not loop.last %}
        ,
        {% endif %}
    {% endfor %}
{% endblock %}

then into your admin controller and in configureListFields function add this line

->add('roles', 'user_roles')

hope this will solve your problem

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM