ユーザー作成用のフォームを作成しています。ユーザーを作成するときに、ユーザーに1つまたは複数の役割を与えたいと考えています。
security.yml
で定義されているロールのリストを取得するにはどうすればよいですか?
現時点でのフォームビルダーは次のとおりです。
public function buildForm(FormBuilder $builder, array $options)
{
parent::buildForm($builder, $options);
// add your custom fields
$user = new User();
$builder->add('regionUser');
$builder->add('roles' ,'choice' ,array('choices' => $user->getRolesNames(),
'required' => true,
));
}
そしてUser.php
public function getRolesNames(){
return array(
"ADMIN" => "Administrateur",
"ANIMATOR" => "Animateur",
"USER" => "Utilisateur",
);
}
もちろん、この解決策は機能しません。roles
はデータベースでビットマップとして定義されているため、choices
リストを作成できません。
前もって感謝します。
security.role_hierarchy.roles
コンテナパラメータは、ロール階層を配列として保持します。これを一般化して、定義されたロールのリストを取得できます。
このメソッドから到達可能なロールのリストを取得できます。
Symfony\Component\Security\Core\Role\RoleHierarchy::getReachableRoles(array $roles)
配列$roles
パラメータの役割から到達可能なすべての役割を返すようです。これはSymfonyの内部サービスであり、そのIDはsecurity.role_hierarchy
であり、パブリックではありません(明示的にパラメーターとして渡す必要があります。サービスコンテナーからアクセスすることはできません)。
役割を正しく表現するには、再帰が必要です。ロールは他のロールを拡張できます。
Security.ymlの以下のロールの例を使用します:
ROLE_SUPER_ADMIN: ROLE_ADMIN
ROLE_ADMIN: ROLE_USER
ROLE_TEST: ROLE_USER
この役割は次の方法で取得できます。
$originalRoles = $this->getParameter('security.role_hierarchy.roles');
再帰の例:
private function getRoles($originalRoles)
{
$roles = array();
/**
* Get all unique roles
*/
foreach ($originalRoles as $originalRole => $inheritedRoles) {
foreach ($inheritedRoles as $inheritedRole) {
$roles[$inheritedRole] = array();
}
$roles[$originalRole] = array();
}
/**
* Get all inherited roles from the unique roles
*/
foreach ($roles as $key => $role) {
$roles[$key] = $this->getInheritedRoles($key, $originalRoles);
}
return $roles;
}
private function getInheritedRoles($role, $originalRoles, $roles = array())
{
/**
* If the role is not in the originalRoles array,
* the role inherit no other roles.
*/
if (!array_key_exists($role, $originalRoles)) {
return $roles;
}
/**
* Add all inherited roles to the roles array
*/
foreach ($originalRoles[$role] as $inheritedRole) {
$roles[$inheritedRole] = $inheritedRole;
}
/**
* Check for each inhered role for other inherited roles
*/
foreach ($originalRoles[$role] as $inheritedRole) {
return $this->getInheritedRoles($inheritedRole, $originalRoles, $roles);
}
}
出力:
array (
'ROLE_USER' => array(),
'ROLE_TEST' => array(
'ROLE_USER' => 'ROLE_USER',
),
'ROLE_ADMIN' => array(
'ROLE_USER' => 'ROLE_USER',
),
'ROLE_SUPER_ADMIN' => array(
'ROLE_ADMIN' => 'ROLE_ADMIN',
'ROLE_USER' => 'ROLE_USER',
),
)
このためのサービスを作成し、「security.role_hierarchy.roles」パラメーターを注入できます。
サービス定義:
acme.user.roles:
class: Acme\DemoBundle\Model\RolesHelper
arguments: ['%security.role_hierarchy.roles%']
サービスクラス:
class RolesHelper
{
private $rolesHierarchy;
private $roles;
public function __construct($rolesHierarchy)
{
$this->rolesHierarchy = $rolesHierarchy;
}
public function getRoles()
{
if($this->roles) {
return $this->roles;
}
$roles = array();
array_walk_recursive($this->rolesHierarchy, function($val) use (&$roles) {
$roles[] = $val;
});
return $this->roles = array_unique($roles);
}
}
次のように、コントローラのロールを取得できます。
$roles = $this->get('acme.user.roles')->getRoles();
Symfony 3.3では、次のようにRolesType.phpを作成できます:
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
/**
* @author Echarbeto
*/
class RolesType extends AbstractType {
private $roles = [];
public function __construct(RoleHierarchyInterface $rolehierarchy) {
$roles = array();
array_walk_recursive($rolehierarchy, function($val) use (&$roles) {
$roles[$val] = $val;
});
ksort($roles);
$this->roles = array_unique($roles);
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'choices' => $this->roles,
'attr' => array(
'class' => 'form-control',
'aria-hidden' => 'true',
'ref' => 'input',
'multiple' => '',
'tabindex' => '-1'
),
'required' => true,
'multiple' => true,
'empty_data' => null,
'label_attr' => array(
'class' => 'control-label'
)
));
}
public function getParent() {
return ChoiceType::class;
}
}
次に、次のようにフォームに追加します。
$builder->add('roles', RolesType::class,array(
'label' => 'Roles'
));
重要なのは、各ロールも含まれている必要があることです。例:ROLE_ADMIN:[ROLE_ADMIN、ROLE_USER]
特定の役割のすべての継承された役割を取得する必要がある場合:
_use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
private function getRoles($role)
{
$hierarchy = $this->container->getParameter('security.role_hierarchy.roles');
$roleHierarchy = new RoleHierarchy($hierarchy);
$roles = $roleHierarchy->getReachableRoles([new Role($role)]);
return array_map(function(Role $role) { return $role->getRole(); }, $roles);
}
_
次に、この関数を呼び出します:$this->getRoles('ROLE_ADMIN');
Symfony 2.7では、コントローラーで$ this-> getParameters()を使用してロールを取得する必要があります:
$roles = array();
foreach ($this->getParameter('security.role_hierarchy.roles') as $key => $value) {
$roles[] = $key;
foreach ($value as $value2) {
$roles[] = $value2;
}
}
$roles = array_unique($roles);
これはまさにあなたが望むものではありませんが、それはあなたの例を機能させます:
use Vendor\myBundle\Entity\User;
public function buildForm(FormBuilder $builder, array $options)
{
parent::buildForm($builder, $options);
// add your custom fields
$user = new User();
$builder->add('regionUser');
$builder->add('roles' ,'choice' ,array('choices' => User::getRolesNames(),
'required' => true,
));
}
ただし、エンティティからロールを取得することに関しては、エンティティリポジトリの要素を使用してデータベースにクエリを実行できます。
queryBuilderを使用してエンティティリポジトリに必要なものを取得する良い例を次に示します。
public function buildForm(FormBuilder $builder, array $options)
{
parent::buildForm($builder, $options);
// add your custom fields
$user = new User();
$builder->add('regionUser');
$builder->add('roles' ,'entity' array(
'class'=>'Vendor\MyBundle\Entity\User',
'property'=>'roles',
'query_builder' => function (\Vendor\MyBundle\Entity\UserRepository $repository)
{
return $repository->createQueryBuilder('s')
->add('orderBy', 's.sort_order ASC');
}
)
);
}
http://inchoo.net/tools-frameworks/symfony2-entity-field-type/