Symfony2: Getting the list of user roles in FormBu

2019-01-17 12:00发布

I'm making a form for user creation, and I want to give one or several roles to a user when I create him.

How do I get the list of roles defined in security.yml?

Here's my form builder at the moment:

public function buildForm(FormBuilder $builder, array $options)
{
    parent::buildForm($builder, $options);

    // add your custom fields
    $user = new User();
    $builder->add('regionUser');
    $builder->add('roles' ,'choice' ,array('choices' => $user->getRolesNames(),
            'required'  => true,
    ));

}

and in User.php

public function getRolesNames(){
    return array(
        "ADMIN" => "Administrateur",
        "ANIMATOR" => "Animateur",
        "USER" => "Utilisateur",        
    );
}

Of course, this solution doesn't work, because roles is defined as a bitmap in the database, therefore the choices list cannot be created.

Thanks in advance.

10条回答
对你真心纯属浪费
2楼-- · 2019-01-17 12:35

For a correct representation of your roles, you need recursion. Roles can extend other roles.

I use for the example the folowing roles in security.yml:

ROLE_SUPER_ADMIN: ROLE_ADMIN
ROLE_ADMIN:       ROLE_USER
ROLE_TEST:        ROLE_USER

You can get this roles with:

$originalRoles = $this->getParameter('security.role_hierarchy.roles');

An example with recursion:

private function getRoles($originalRoles)
{
    $roles = array();

    /**
     * Get all unique roles
     */
    foreach ($originalRoles as $originalRole => $inheritedRoles) {
        foreach ($inheritedRoles as $inheritedRole) {
            $roles[$inheritedRole] = array();
        }

        $roles[$originalRole] = array();
    }

    /**
     * Get all inherited roles from the unique roles
     */
    foreach ($roles as $key => $role) {
        $roles[$key] = $this->getInheritedRoles($key, $originalRoles);
    }

    return $roles;
}

private function getInheritedRoles($role, $originalRoles, $roles = array())
{
    /**
     * If the role is not in the originalRoles array,
     * the role inherit no other roles.
     */
    if (!array_key_exists($role, $originalRoles)) {
        return $roles;
    }

    /**
     * Add all inherited roles to the roles array
     */
    foreach ($originalRoles[$role] as $inheritedRole) {
        $roles[$inheritedRole] = $inheritedRole;
    }

    /**
     * Check for each inhered role for other inherited roles
     */
    foreach ($originalRoles[$role] as $inheritedRole) {
        return $this->getInheritedRoles($inheritedRole, $originalRoles, $roles);
    }
}

The output:

array (
  'ROLE_USER' => array(),
  'ROLE_TEST' => array(
                        'ROLE_USER' => 'ROLE_USER',
  ),
  'ROLE_ADMIN' => array(
                        'ROLE_USER' => 'ROLE_USER',
  ),
  'ROLE_SUPER_ADMIN' => array(
                        'ROLE_ADMIN' => 'ROLE_ADMIN',
                        'ROLE_USER' => 'ROLE_USER',
  ),
)
查看更多
Rolldiameter
3楼-- · 2019-01-17 12:35
//FormType
use Symfony\Component\Yaml\Parser;

function getRolesNames(){
        $pathToSecurity = /var/mydirectory/app/config/security.yml
        $yaml = new Parser();
        $rolesArray = $yaml->parse(file_get_contents($pathToSecurity ));

        return $rolesArray['security']['role_hierarchy']['ROLE_USER'];
}

This is so far the best way i found to get or set what i want from config files.

Bon courage

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-01-17 12:40

You can make a service for this and inject the "security.role_hierarchy.roles" parameter.

Service definition:

acme.user.roles:
   class: Acme\DemoBundle\Model\RolesHelper
   arguments: ['%security.role_hierarchy.roles%']

Service Class:

class RolesHelper
{
    private $rolesHierarchy;

    private $roles;

    public function __construct($rolesHierarchy)
    {
        $this->rolesHierarchy = $rolesHierarchy;
    }

    public function getRoles()
    {
        if($this->roles) {
            return $this->roles;
        }

        $roles = array();
        array_walk_recursive($this->rolesHierarchy, function($val) use (&$roles) {
            $roles[] = $val;
        });

        return $this->roles = array_unique($roles);
    }
}

You can get the roles in your controller like this:

$roles = $this->get('acme.user.roles')->getRoles();
查看更多
干净又极端
5楼-- · 2019-01-17 12:41

In Symfony 3.3, you can create a RolesType.php as follows:

<?php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;

/**
 * @author Echarbeto
 */
class RolesType extends AbstractType {

  private $roles = [];

  public function __construct(RoleHierarchyInterface $rolehierarchy) {
    $roles = array();
    array_walk_recursive($rolehierarchy, function($val) use (&$roles) {
      $roles[$val] = $val;
    });
    ksort($roles);
    $this->roles = array_unique($roles);
  }

  public function configureOptions(OptionsResolver $resolver) {
    $resolver->setDefaults(array(
        'choices' => $this->roles,
        'attr' => array(
            'class' => 'form-control',
            'aria-hidden' => 'true',
            'ref' => 'input',
            'multiple' => '',
            'tabindex' => '-1'
        ),
        'required' => true,
        'multiple' => true,
        'empty_data' => null,
        'label_attr' => array(
            'class' => 'control-label'
        )
    ));
  }

  public function getParent() {
    return ChoiceType::class;
  }

}

Then add it to the form as follows:

$builder->add('roles', RolesType::class,array(
          'label' => 'Roles'
      ));

Important is that each role must also be contained, for example: ROLE_ADMIN: [ROLE_ADMIN, ROLE_USER]

查看更多
登录 后发表回答