我有一个用户编辑表单,我想管理分配给用户的角色。
目前我有一个多选列表,但我没办法用security.yml中定义的角色层次填充它。
我是否有某种方法可以将此信息提供给FormType类中的表单生成器?
$builder->add('roles', 'choice', array(
'required' => true,
'multiple' => true,
'choices' => array(),
));
环顾I found我可以从控制器中的容器中获取角色:
$roles = $this->container->getParameter('security.role_hierarchy.roles');
我还发现我可以将它设置为在services.xml中注入FormType类的依赖项:
<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
方法。
那我怎么能让它发挥作用呢?
答案 0 :(得分: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 :(得分:2)
webda2l提供的带有$ options数组的解决方案不适用于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,
));
// ...
}
}
我从Marcello Voc接受了这个想法,谢谢他!
答案 2 :(得分: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 * field:
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);
}
...
}
答案 3 :(得分: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);
}
}