set role for users in edit form of sonata admin

2019-05-06 04:14发布

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.

6条回答
你好瞎i
2楼-- · 2019-05-06 04:49

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))"
]

enter image description here

This helps you find all roles, that include a specific role: enter image description here

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)));
}
查看更多
Anthone
3楼-- · 2019-05-06 04:51

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 inconfigureListFields function add this line

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

hope this will solve your problem

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-05-06 04:59

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:

enter image description here enter image description here

查看更多
祖国的老花朵
5楼-- · 2019-05-06 05:01

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

查看更多
兄弟一词,经得起流年.
6楼-- · 2019-05-06 05:06

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 :)

查看更多
够拽才男人
7楼-- · 2019-05-06 05:10

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')
查看更多
登录 后发表回答