Я создаю форму для создания пользователя, и я хочу дать одну или несколько ролей пользователю, когда я его создам.
Как получить список ролей, определенных в 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)
Кажется, он возвращает все роли, доступные из ролей в параметре array $roles
. Это внутренняя служба Symfony, идентификатор которой является security.role_hierarchy
и не является общедоступным (вы должны явно передать его как параметры, это не доступно из Service Container).
Вы можете сделать сервис для этого и ввести параметр «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();
Для правильного представления ваших ролей вам нужна рекурсия. Роли могут распространять другие роли.
Я использую для примера следующие роли в 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', ), )
В 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]
В 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/
Если вам нужно получить все унаследованные роли определенной роли:
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); }
Затем назовите этот functon: $this->getRoles('ROLE_ADMIN');
//FormType use Symfony\Component\Yaml\Parser; function getRolesNames(){ $pathToSecurity = /var/mydirectory/app/config/security.yml $yaml = new Parser(); $rolesArray = $yaml->parse(file_get_contents($pathToSecurity )); return $rolesArray['security']['role_hierarchy']['ROLE_USER']; }
Это пока что лучший способ найти или установить то, что я хочу, из файлов конфигурации.
Божество
Вот что я сделал:
FormType:
use FTW\GuildBundle\Entity\User; class UserType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('username') ->add('email') ->add('enabled', null, array('required' => false)) ->add('roles', 'choice', array( 'choices' => User::getRoleNames(), 'required' => false,'label'=>'Roles','multiple'=>true )) ->add('disableNotificationEmails', null, array('required' => false)); }
В объекте:
use Symfony\Component\Yaml\Parser; ... static function getRoleNames() { $pathToSecurity = __DIR__ . '/../../../..' . '/app/config/security.yml'; $yaml = new Parser(); $rolesArray = $yaml->parse(file_get_contents($pathToSecurity)); $arrayKeys = array(); foreach ($rolesArray['security']['role_hierarchy'] as $key => $value) { //never allow assigning super admin if ($key != 'ROLE_SUPER_ADMIN') $arrayKeys[$key] = User::convertRoleToLabel($key); //skip values that are arrays --- roles with multiple sub-roles if (!is_array($value)) if ($value != 'ROLE_SUPER_ADMIN') $arrayKeys[$value] = User::convertRoleToLabel($value); } //sort for display purposes asort($arrayKeys); return $arrayKeys; } static private function convertRoleToLabel($role) { $roleDisplay = str_replace('ROLE_', '', $role); $roleDisplay = str_replace('_', ' ', $roleDisplay); return ucwords(strtolower($roleDisplay)); }
Пожалуйста, предоставьте отзыв … Я использовал некоторые предложения из других ответов, но я все еще чувствую, что это не лучшее решение!