2012-06-28 2 views
12

Я создаю форму для создания пользователя, и я хочу дать одну или несколько ролей пользователю, когда я его создаю.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 не может быть создан.

Заранее спасибо.

+0

Я думаю @Mihai Аврелиан ответ лучше всего подходит для вашего вопроса http://stackoverflow.com/ вопросы/11246774/symfony2-get-the-list-of-user-role-in-formbuilder/24926223 # 24926223 – AlexandruSerban

ответ

16

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

+11

для тех, кто не понимает, что это означает, используйте это в своем контроллере: $ role = $ this-> get ('security. role_hierarchy '); – sepehr

+0

mine возвращает пустую, когда я 'var_dump', это даже не echo' null', любая идея почему? –

+4

Не уверен, когда это изменилось, но в 2.5 это «security.role_hierarchy» – shokora

1

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

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/

+0

Спасибо за ответ. Я всегда могу получить роли из базы данных (и, возможно, я буду, если нет другого пути), но я на самом деле нацелен на получение тех ролей, которые я определил в безопасности. Определение их в User было всего лишь способом справиться с этим, но если вы знаете, как получить роли, определенные в безопасности, я возьму это! –

+0

Глупый я :) Вы, возможно, должны использовать парсер Yaml для преобразования security.yml в массив, который вы будете читать. – Chopchop

-1
//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']; 
} 

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

Bon мужество

+0

Я не совсем согласен с этим предложением ... но также хотел улучшить это, потому что жесткое кодирование пути к файлу меня пугает. '$ pathToSecurity = __DIR__. '/../../../ ..'. '/app/config/security.yml'; ' ' – Chris

+0

будет таким же, как с использованием глобальной переменной, которая не имеет хорошего оо-вкуса. Всегда лучше вводить такие вещи в контейнер (контейнер параметр security.role_hierarchy .roles) –

11

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

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

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

+1

В дополнение к этому хорошему ответу я создал [gist] (https: //gist.github.com/Glideh/27edd82b6b953b0b431225de9796c697) для 'RolesType' для использования непосредственно в' UserFormType' –

-1

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

FormType:

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

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

7

Вы можете сделать сервис для этого и ввести параметр «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(); 
+1

Я предлагаю пройти иерархию в конструкторе, чтобы не делать этого каждый раз, когда вызывается 'getRoles'. – Jonny

+0

Вы правы. Отредактировал ответ только для вызова array_walk_recursive один раз. –

+0

Вы все еще делаете это каждый раз, когда вызывается 'getRoles()'. Почему бы не сделать это при запуске службы? – Jonny

1

В 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); 
8

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

я использую для примера на следующие роли в 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', 
), 
) 
+0

Доступно, если для параметров 'autowire' и' autogofigure' установлено значение true. Мне лично это совсем не нравится ..! Если нет, установите свой 'RolesType', как и прежде, в' services.yml' – Delphine

1

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

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

Затем вызовите эту functon: $this->getRoles('ROLE_ADMIN');

2

В 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' 
    )); 

Важно то, что каждая роль должна также содержаться, например: ROLE_ADMIN: [ROLE_ADMIN, ROLE_USER]

Смежные вопросы