How can I pass a full security roles list/hierarchy to a FormType class in Symfony2?

前端 未结 4 1399
刺人心
刺人心 2021-01-14 06:42

I have a user edit form where I would like to administer the roles assigned to a user.

Currently I have a multi-select list, but I have no way of populating it with

相关标签:
4条回答
  • 2021-01-14 07:19

    You can make your own type and then pass service container, from which you can then retrieve role hierarchy.

    First, create your own type:

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

    Then you need to register your type as service and set parameters:

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

    Then during creation of form, simply add *permission_choice* field:

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

    If you want to get only single list of roles without hierarchy, then you need to flat hierarchy somehow. One of possible solution is this:

    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);
        }
        ...
    }
    
    0 讨论(0)
  • 2021-01-14 07:25

    For to 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);
        }
    }
    
    0 讨论(0)
  • 2021-01-14 07:37

    The solution with $options array provided by webda2l does not work with Symfony 2.3. It gives me an error:

    The option "roles" do not exist.

    I found that we can pass parameters to the form type constructor.

    In your controller :

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

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

    I took the idea from Marcello Voc, thanks to him!

    0 讨论(0)
  • 2021-01-14 07:39

    In your controller

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

    In 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;
    }
    
    0 讨论(0)
提交回复
热议问题