У меня есть форма редактирования пользователя, в которой я хотел бы назначить роли, назначенные пользователю.
В настоящее время у меня есть список с несколькими выборами, но у меня нет способа заполнить его иерархией роли, определенной в security.yml.
Есть ли способ получить эту информацию в построителе форм в классе FormType?
$builder->add('roles', 'choice', array( 'required' => true, 'multiple' => true, 'choices' => array(), ));
Оглядевшись, я обнаружил, что могу получить роли из контейнера в контроллере с помощью:
$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
.
Итак, как я могу заставить это работать?
В вашем контроллере
$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; }
Решение с массивом $ options, предоставленным webda2l, не работает с Symfony 2.3. Это дает мне ошибку:
Опция «роли» не существует.
Я обнаружил, что мы можем передавать параметры конструктору типа формы.
В вашем контроллере:
$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, )); // ... } }
Я понял эту мысль от Марчелло Вока , благодаря ему!
Вы можете создать свой собственный тип, а затем передать контейнер услуг, из которого вы можете получить иерархию ролей.
Сначала создайте свой собственный тип:
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); } ... }
Для 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); } }