2012-05-09 2 views
2

У меня есть пользовательская форма редактирования, где я бы хотел назначить роли, назначенные пользователю.Как передать полный список/иерархию ролей безопасности классу FormType в Symfony2?

В настоящее время у меня есть список с несколькими выборами, но у меня нет способа заполнить его иерархией ролей, определенной в security.yml.

Есть ли способ получить эту информацию в построителе форм в классе FormType?

$builder->add('roles', 'choice', array(
       'required' => true, 
       'multiple' => true, 
       'choices' => array(), 
      )); 

Оглядевшись I found, что я могу получить роль из контейнера в контроллере с:

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

Я также обнаружил, что я мог потенциально установить это как зависимость, который будет введен в FormType класс в services.xml:

<parameters> 
    <parameter key="security.role_heirarchy.roles">ROLE_GUEST</parameter> 
</parameters> 
<services> 
    <service id="base.user.form.type.user_form" class="Base\UserBundle\Form\UserType" public="false"> 
     <tag name="form.type" /> 
     <call method="setRoles"> 
      <argument>%security.role_heirarchy.roles%</argument> 
     </call> 
    </service> 
</services> 

Это, однако, не работает, и, кажется, не всегда вызывать метод setRoles.

Так как я могу заставить это работать?

ответ

9

В контроллере

$editForm = $this->createForm(new UserType(), $entity, array('roles' => $this->container->getParameter('security.role_hierarchy.roles'))); 

В UserType:

$builder->add('roles', 'choice', array(
    'required' => true, 
    'multiple' => true, 
    'choices' => $this->refactorRoles($options['roles']) 
)) 

[...] 

public function getDefaultOptions() 
{ 
    return array(
     'roles' => null 
    ); 
} 

private function refactorRoles($originRoles) 
{ 
    $roles = array(); 
    $rolesAdded = array(); 

    // Add herited roles 
    foreach ($originRoles as $roleParent => $rolesHerit) { 
     $tmpRoles = array_values($rolesHerit); 
     $rolesAdded = array_merge($rolesAdded, $tmpRoles); 
     $roles[$roleParent] = array_combine($tmpRoles, $tmpRoles); 
    } 
    // Add missing superparent roles 
    $rolesParent = array_keys($originRoles); 
    foreach ($rolesParent as $roleParent) { 
     if (!in_array($roleParent, $rolesAdded)) { 
      $roles['-----'][$roleParent] = $roleParent; 
     } 
    } 

    return $roles; 
} 
+1

'getDefaultOptions' был устаревшим в Symfony 2.1 и удалены в 2.3. Вместо этого используйте 'setDefaultOptions' (https://github.com/symfony/symfony/blob/master/UPGRADE-2.1.md#deprecations). – Tamlyn

1

Вы можете сделать свой собственный тип, а затем пройти сервисный контейнер, из которого затем можно восстановить иерархию ролей.

Во-первых, создать свой собственный тип:

class PermissionType extends AbstractType 
{ 
    private $roles; 

    public function __construct(ContainerInterface $container) 
    { 
     $this->roles = $container->getParameter('security.role_hierarchy.roles'); 
    } 
    public function getDefaultOptions(array $options) 
    { 
     return array(
       'choices' => $this->roles, 
     ); 
    ); 

    public function getParent(array $options) 
    { 
     return 'choice'; 
    } 

    public function getName() 
    { 
     return 'permission_choice'; 
    } 
} 

Затем вам нужно зарегистрировать свой тип, как сервис и установить параметры:

services: 
     form.type.permission: 
      class: MyNamespace\MyBundle\Form\Type\PermissionType 
      arguments: 
      - "@service_container" 
      tags: 
      - { name: form.type, alias: permission_choice } 

Тогда при создании формы, просто добавить * permission_choice * поле :

public function buildForm(FormBuilder $builder, array $options) 
{ 
    $builder->add('roles', 'permission_choice'); 
} 

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

class PermissionType extends AbstractType 
{ 
    private $roles; 

    public function __construct(ContainerInterface $container) 
    { 
     $roles = $container->getParameter('security.role_hierarchy.roles'); 
     $this->roles = $this->flatArray($roles); 
    } 

    private function flatArray(array $data) 
    { 
     $result = array(); 
     foreach ($data as $key => $value) { 
      if (substr($key, 0, 4) === 'ROLE') { 
       $result[$key] = $key; 
      } 
      if (is_array($value)) { 
       $tmpresult = $this->flatArray($value); 
       if (count($tmpresult) > 0) { 
        $result = array_merge($result, $tmpresult); 
       } 
      } else { 
       $result[$value] = $value; 
      } 
     } 
     return array_unique($result); 
    } 
    ... 
} 
2

Решение с $ опций массива обеспечивается webda2l не работает с Symfony 2.3. Это дает мне ошибку:

The option "roles" do not exist.

Я обнаружил, что мы можем передать параметры конструктору типа формы.

В контроллере:

$roles_choices = array(); 

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

# set roles array, displaying inherited roles between parentheses 
foreach ($roles as $role => $inherited_roles) 
{ 
    foreach ($inherited_roles as $id => $inherited_role) 
    { 
     if (! array_key_exists($inherited_role, $roles_choices)) 
     { 
      $roles_choices[$inherited_role] = $inherited_role; 
     } 
    } 

    if (! array_key_exists($role, $roles_choices)) 
    { 
     $roles_choices[$role] = $role.' ('. 
      implode(', ', $inherited_roles).')'; 
    } 
} 

# todo: set $role as the current role of the user 

$form = $this->createForm(
    new UserType(array(
     # pass $roles to the constructor 
     'roles' => $roles_choices, 
     'role' => $role 
    )), $user); 

В UserType.php:

class UserType extends AbstractType 
{ 
    private $roles; 
    private $role; 

    public function __construct($options = array()) 
    { 
     # store roles 
     $this->roles = $options['roles']; 
     $this->role = $options['role']; 
    } 
    public function buildForm(FormBuilderInterface $builder, 
     array $options) 
    { 
     // ... 
     # use roles 
     $builder->add('roles', 'choice', array(
      'choices' => $this->roles, 
      'data' => $this->role, 
     )); 
     // ... 
    } 
} 

Я взял идею из Marcello Voc, благодаря ему!

1

Ибо Symfony 2.3:

<?php 

namespace Labone\Bundle\UserBundle\Form\Type; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 
use Symfony\Component\DependencyInjection\ContainerInterface as Container; 

class PermissionType extends AbstractType 
{ 
    private $roles; 

    public function __construct(Container $container) 
    { 
     $roles = $container->getParameter('security.role_hierarchy.roles'); 
     $this->roles = $this->flatArray($roles); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'choices' => $this->roles 
     )); 
    } 

    public function getParent() 
    { 
     return 'choice'; 
    } 

    public function getName() 
    { 
     return 'permission_choice'; 
    } 

    private function flatArray(array $data) 
    { 
     $result = array(); 
     foreach ($data as $key => $value) { 
      if (substr($key, 0, 4) === 'ROLE') { 
       $result[$key] = $key; 
      } 
      if (is_array($value)) { 
       $tmpresult = $this->flatArray($value); 
       if (count($tmpresult) > 0) { 
        $result = array_merge($result, $tmpresult); 
       } 
      } else { 
       $result[$value] = $value; 
      } 
     } 
     return array_unique($result); 
    } 
} 
Смежные вопросы