将角色列表添加到 FOS Userbundle 配置文件编辑表单
Add Role List to FOS Userbundle Profile Edit Form
此问题与 Symfony2: Getting the list of user roles in FormBuilder 类似,但那里的答案适用于任何形式,但我的问题特定于 User Bundle 创建的形式。问题是 UserBundle Controller 创建了这样的表单:
$form = $this->container->get('fos_user.profile.form');
因此我不知道如何将角色发送到我的表单类型。
我的回答与@Mihai Aurelian 在 similar question 上的回答相似。
创建了名为 Role Helper 的服务:
<?php
namespace AppBundle\Services;
/**
* Roles helper displays roles set in config.
*/
class RolesHelper
{
private $rolesHierarchy;
public function __construct($rolesHierarchy)
{
$this->rolesHierarchy = $rolesHierarchy;
}
/**
* Return roles.
*
* @return array
*/
public function getRoles()
{
$roles = array();
array_walk_recursive($this->rolesHierarchy, function($val) use (&$roles) {
$roles[] = $val;
});
return array_unique($roles);
}
}
使用 Overriding Default FOSUserBundle Forms 指令覆盖了表单类型并更新了默认构造函数以将 RolesHelper 作为参数包含在内。
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
use AppBundle\Services\RolesHelper;
class UserType extends BaseType
{
/**
* @var RolesHelper
*/
private $roles;
/**
* @param string $class The User class name
* @param RolesHelper $roles Array or roles.
*/
public function __construct($class, RolesHelper $roles)
{
parent::__construct($class);
$this->roles = $roles;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('firstName')
->add('lastName')
->add('roles', 'choice', array(
'choices' => $this->roles->getRoles(),
'required' => false,
'multiple'=>true
));
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'user_registration';
}
}
已更新services.yml
app_roles_helper:
class: AppBundle\Services\RolesHelper
arguments: ['%security.role_hierarchy.roles%']
在 services.yml 中向 app_user.registration.form.type 添加了第二个参数:
app_user.registration.form.type:
class: AppBundle\Form\Type\UserType
arguments: [%fos_user.model.user.class%, @app_roles_helper]
tags:
- { name: form.type, alias: user_registration }
我不能发表评论,所以我会发表评论作为答案。您编写 getRoles 函数的方式只会 return 数组位置作为角色,例如,如果您有一个三位置数组,它将 return 0,1,2 作为选择,而不是角色名称。然后我在这一行尝试了一些不同的东西,而不是:
array_walk_recursive($this->rolesHierarchy, function($val) use (&$roles) {
$roles[] = $val;
});
我放
array_walk_recursive($this->rolesHierarchy, function($val) use (&$roles) {
$roles[$val] = $val;
});
这解决了 return 使用数字数组位置而不是角色名称的问题。但是有一个问题,对于这样的层次结构:
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ ROLE_ADMIN, ROLE_TEST ]
它只会returnROLE_USER、ROLE_ADMIN和ROLE_TEST,但对于Symfony,ROLE_ADMIN和ROLE_SUPER_ADMIN也是角色。问题在于 array_walk_recursive 不会将其值是数组的键传递给回调函数。因为 ROLE_ADMIN 是 ARRAY(1) => ([0] => (string)ROLE_USER) 而 ROLE_SUPER_ADMIN 是 ARRAY(2) => ([0]=>(string) ROLE_ADMIN [1]=>(string)ROLE_TEST), 两者都会被忽略。
解决方案是这样做的:
public function getRoles() {
$roles = array();
foreach (array_keys($this->rolesHierarchy) as $key){
$roles[$key] = $key;
array_walk_recursive($this->rolesHierarchy[$key], function($val) use (&$roles){
$roles[$val] = $val;
});
}
return array_unique($roles);
数组键本身也被视为角色,这就是包含 $roles[$key] = $key 的原因。并且,递归到层次结构中包含的每个数组:
array_walk_recursive($this->rolesHierarchy[$key], function($val) use (&$roles){
$roles[$val] = $val;
});
此问题与 Symfony2: Getting the list of user roles in FormBuilder 类似,但那里的答案适用于任何形式,但我的问题特定于 User Bundle 创建的形式。问题是 UserBundle Controller 创建了这样的表单:
$form = $this->container->get('fos_user.profile.form');
因此我不知道如何将角色发送到我的表单类型。
我的回答与@Mihai Aurelian 在 similar question 上的回答相似。
创建了名为 Role Helper 的服务:
<?php
namespace AppBundle\Services;
/**
* Roles helper displays roles set in config.
*/
class RolesHelper
{
private $rolesHierarchy;
public function __construct($rolesHierarchy)
{
$this->rolesHierarchy = $rolesHierarchy;
}
/**
* Return roles.
*
* @return array
*/
public function getRoles()
{
$roles = array();
array_walk_recursive($this->rolesHierarchy, function($val) use (&$roles) {
$roles[] = $val;
});
return array_unique($roles);
}
}
使用 Overriding Default FOSUserBundle Forms 指令覆盖了表单类型并更新了默认构造函数以将 RolesHelper 作为参数包含在内。
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
use AppBundle\Services\RolesHelper;
class UserType extends BaseType
{
/**
* @var RolesHelper
*/
private $roles;
/**
* @param string $class The User class name
* @param RolesHelper $roles Array or roles.
*/
public function __construct($class, RolesHelper $roles)
{
parent::__construct($class);
$this->roles = $roles;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('firstName')
->add('lastName')
->add('roles', 'choice', array(
'choices' => $this->roles->getRoles(),
'required' => false,
'multiple'=>true
));
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'user_registration';
}
}
已更新services.yml
app_roles_helper:
class: AppBundle\Services\RolesHelper
arguments: ['%security.role_hierarchy.roles%']
在 services.yml 中向 app_user.registration.form.type 添加了第二个参数:
app_user.registration.form.type:
class: AppBundle\Form\Type\UserType
arguments: [%fos_user.model.user.class%, @app_roles_helper]
tags:
- { name: form.type, alias: user_registration }
我不能发表评论,所以我会发表评论作为答案。您编写 getRoles 函数的方式只会 return 数组位置作为角色,例如,如果您有一个三位置数组,它将 return 0,1,2 作为选择,而不是角色名称。然后我在这一行尝试了一些不同的东西,而不是:
array_walk_recursive($this->rolesHierarchy, function($val) use (&$roles) {
$roles[] = $val;
});
我放
array_walk_recursive($this->rolesHierarchy, function($val) use (&$roles) {
$roles[$val] = $val;
});
这解决了 return 使用数字数组位置而不是角色名称的问题。但是有一个问题,对于这样的层次结构:
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ ROLE_ADMIN, ROLE_TEST ]
它只会returnROLE_USER、ROLE_ADMIN和ROLE_TEST,但对于Symfony,ROLE_ADMIN和ROLE_SUPER_ADMIN也是角色。问题在于 array_walk_recursive 不会将其值是数组的键传递给回调函数。因为 ROLE_ADMIN 是 ARRAY(1) => ([0] => (string)ROLE_USER) 而 ROLE_SUPER_ADMIN 是 ARRAY(2) => ([0]=>(string) ROLE_ADMIN [1]=>(string)ROLE_TEST), 两者都会被忽略。
解决方案是这样做的:
public function getRoles() {
$roles = array();
foreach (array_keys($this->rolesHierarchy) as $key){
$roles[$key] = $key;
array_walk_recursive($this->rolesHierarchy[$key], function($val) use (&$roles){
$roles[$val] = $val;
});
}
return array_unique($roles);
数组键本身也被视为角色,这就是包含 $roles[$key] = $key 的原因。并且,递归到层次结构中包含的每个数组:
array_walk_recursive($this->rolesHierarchy[$key], function($val) use (&$roles){
$roles[$val] = $val;
});