Symfony2: Получение списка ролей пользователей в FormBuilder


Я создаю форму для создания пользователя и хочу предоставить пользователю одну или несколько ролей при его создании.

Как мне получить список ролей, определенных в security.yml?

Вот мой конструктор форм на данный момент:

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,
    ));

}

И в User.php

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

Конечно, это решение не работает, потому что roles определяется как растровое изображение в базе данных, поэтому список choices не может быть создан.

Заранее благодарю.

Author: Mun Mun Das, 2012-06-28

10 answers

security.role_hierarchy.roles параметр контейнера содержит иерархию ролей в виде массива. Вы можете обобщить его, чтобы получить список определенных ролей.

 16
Author: Mun Mun Das, 2012-06-28 17:18:32

Вы можете получить список доступных ролей с помощью этого метода:

Symfony\Component\Security\Core\Role\RoleHierarchy::getReachableRoles(array $roles)

Похоже, что он возвращает все роли, доступные из параметров ролей в массиве $roles. Это внутренняя служба Symfony, идентификатор которой security.role_hierarchy и не является общедоступным (вы должны явно передать его в качестве параметров, он недоступен из контейнера службы).

 11
Author: AlterPHP, 2016-01-17 22:44:02

Для правильного представления ваших ролей вам нужна рекурсия. Роли могут расширять другие роли.

Я использую для примера следующие роли в security.yml:

ROLE_SUPER_ADMIN: ROLE_ADMIN
ROLE_ADMIN:       ROLE_USER
ROLE_TEST:        ROLE_USER

Вы можете получить эти роли с помощью:

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

Пример с рекурсией:

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

Вывод:

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',
  ),
)
 8
Author: Tim Hovius, 2017-04-10 08:16:05

Для этого можно создать службу и ввести параметр "security.role_hierarchy.roles".

Определение услуги:

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

Класс обслуживания:

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

Вы можете получить роли в своем контроллере следующим образом:

$roles = $this->get('acme.user.roles')->getRoles();
 7
Author: Mihai Aurelian, 2016-08-31 09:00:36

В Symfony 3.3 вы можете создать RolesType.php следующим образом:

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

}

Затем добавьте его в форму следующим образом:

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

Важно то, что каждая роль также должна содержаться, например: РОЛЕВОЙ_АДМИН: [РОЛЕВОЙ_АДМИН, РОЛЕВОЙ_ПОЛЬЗОВАТЕЛЬ]

 2
Author: Echarbeto, 2017-10-25 00:17:52

В Symfony 2.7 в контроллерах вы должны использовать $this->getParameters(), чтобы получить роли:

$roles = array();
foreach ($this->getParameter('security.role_hierarchy.roles') as $key => $value) {
    $roles[] = $key;

    foreach ($value as $value2) {
        $roles[] = $value2;
    }
}
$roles = array_unique($roles);
 1
Author: Jonathan Delorme, 2015-11-20 13:56:25

Это не совсем то, что вы хотите, но это заставляет ваш пример работать:

use Vendor\myBundle\Entity\User;

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

Но что касается получения ваших ролей от сущности, возможно, вы можете использовать материалы хранилища сущностей для запроса базы данных.

Вот хороший пример того, как получить то, что нужно, используя QueryBuilder в хранилище сущностей:

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

    // add your custom fields
    $user = new User();
    $builder->add('regionUser');
    $builder->add('roles' ,'entity' array(
                 'class'=>'Vendor\MyBundle\Entity\User',
                 'property'=>'roles',
                 'query_builder' => function (\Vendor\MyBundle\Entity\UserRepository $repository)
                 {
                     return $repository->createQueryBuilder('s')
                            ->add('orderBy', 's.sort_order ASC');
                 }
                )
          );
}

Http://inchoo.net/tools-frameworks/symfony2-entity-field-type/

 1
Author: Chopchop, 2016-01-17 23:39:22

Если вам нужно получить все унаследованные роли определенной роли:

use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;

private function getRoles($role)
{
    $hierarchy = $this->container->getParameter('security.role_hierarchy.roles');
    $roleHierarchy = new RoleHierarchy($hierarchy);
    $roles = $roleHierarchy->getReachableRoles([new Role($role)]);
    return array_map(function(Role $role) { return $role->getRole(); }, $roles);
}

Затем вызовите эту функцию: $this->getRoles('ROLE_ADMIN');

 1
Author: Alexey Pavlov, 2016-12-21 10:24:12
//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'];
}

Это пока лучший способ, который я нашел, чтобы получить или установить то, что я хочу, из конфигурационных файлов.

Приятного мужества

 -1
Author: Chopchop, 2012-06-28 15:22:07

Вот что я сделал:

Тип формы:

use FTW\GuildBundle\Entity\User;

class UserType extends AbstractType
{

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('username')
        ->add('email')
        ->add('enabled', null, array('required' => false))
        ->add('roles', 'choice', array(
        'choices' => User::getRoleNames(),
        'required' => false,'label'=>'Roles','multiple'=>true
    ))
        ->add('disableNotificationEmails', null, array('required' => false));
}

В сущности:

use Symfony\Component\Yaml\Parser; ...

static function getRoleNames()
{
    $pathToSecurity = __DIR__ . '/../../../..' . '/app/config/security.yml';
    $yaml = new Parser();
    $rolesArray = $yaml->parse(file_get_contents($pathToSecurity));
    $arrayKeys = array();
    foreach ($rolesArray['security']['role_hierarchy'] as $key => $value)
    {
        //never allow assigning super admin
        if ($key != 'ROLE_SUPER_ADMIN')
            $arrayKeys[$key] = User::convertRoleToLabel($key);
        //skip values that are arrays --- roles with multiple sub-roles
        if (!is_array($value))
            if ($value != 'ROLE_SUPER_ADMIN')
                $arrayKeys[$value] = User::convertRoleToLabel($value);
    }
    //sort for display purposes
    asort($arrayKeys);
    return $arrayKeys;
}

static private function convertRoleToLabel($role)
{
    $roleDisplay = str_replace('ROLE_', '', $role);
    $roleDisplay = str_replace('_', ' ', $roleDisplay);
    return ucwords(strtolower($roleDisplay));
}

Пожалуйста, предоставьте отзыв... Я использовал некоторые предложения из других ответов, но я все еще чувствую, что это не лучшее решение!

 -1
Author: Chris, 2013-01-22 02:09:19