2012-06-28 43 views
12

में उपयोगकर्ता भूमिकाओं की सूची प्राप्त करना मैं उपयोगकर्ता निर्माण के लिए एक फॉर्म बना रहा हूं, और जब मैं उसे बनाता हूं तो मैं उपयोगकर्ता को एक या कई भूमिकाएं देना चाहता हूं।Symfony2: FormBuilder

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 सूची नहीं बनाई जा सकती है।

अग्रिम धन्यवाद।

+0

मुझे लगता है कि @Mihai औरेलियन जवाब बेहतर अपने प्रश्न के लिए अनुकूल है http://stackoverflow.com/ प्रश्न/11246774/symfony2-user-roles-in-formbuilder/24926223 # 24926223 – AlexandruSerban

उत्तर

16

security.role_hierarchy.roles कंटेनर पैरामीटर एक सरणी के रूप में भूमिका पदानुक्रम रखता है। परिभाषित भूमिकाओं की सूची प्राप्त करने के लिए आप इसे सामान्यीकृत कर सकते हैं।

+11

में सीधे उपयोग करने के लिए 'RolesType' के लिए, जो इसका अर्थ नहीं प्राप्त करते हैं, उनके नियंत्रक में इसका उपयोग करें: $ भूमिकाएं = $ यह-> प्राप्त करें ('सुरक्षा। role_hierarchy '); – sepehr

+0

मेरा रिटर्न खाली हो जाता है, जब मैं 'var_dump' करता हूं तो यह 'शून्य' को भी गूंजता नहीं है, कोई विचार क्यों? –

+4

यह सुनिश्चित नहीं है कि यह कब बदला गया लेकिन 2.5 में यह 'security.role_hierarchy' – shokora

1

यह ठीक नहीं है कि आप क्या चाहते हैं लेकिन यह अपने उदाहरण से काम कर रहा है:

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, 
    )); 
} 

लेकिन एक इकाई से अपने भूमिकाएँ हो रही, हो सकता है आप डेटाबेस क्वेरी करने के लिए इकाई भंडार सामान का उपयोग कर सकते के बारे में।

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/

+0

आपके उत्तर देने के लिए धन्यवाद। मैं हमेशा डेटाबेस से भूमिकाएं प्राप्त कर सकता हूं (और शायद अगर मैं कोई अन्य रास्ता नहीं हूं), लेकिन वास्तव में मैं सुरक्षा में परिभाषित भूमिकाओं को प्राप्त करने का लक्ष्य रख रहा हूं। उन्हें उपयोगकर्ता में परिभाषित करना इसका सामना करने का एक तरीका था, लेकिन यदि आप जानते हैं कि सुरक्षा में परिभाषित भूमिकाएं कैसे प्राप्त करें, तो मैं इसे ले जाऊंगा! –

+0

बेवकूफ मुझे :) आपको शायद एक सरणी में security.yml को बदलने के लिए यामल पार्सर का उपयोग करना चाहिए जिसे आप पढ़ लेंगे। – Chopchop

-1
//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']; 
} 

यह अब तक का सबसे अच्छा तरीका मैं पाने के लिए मिल गया है:

यहाँ इकाई भंडार में queryBuilder का उपयोग कर चाहते हैं पाने के लिए एक अच्छा उदाहरण है या कॉन्फ़िगरेशन फ़ाइलों से जो मैं चाहता हूं उसे सेट करें।

बॉन साहस

+0

मैं इस सुझाव से पूरी तरह से सहमत नहीं हूं ... लेकिन यह भी मुझे इस पथ को सुधारने के लिए फ़ाइल पथ कीड़े को कड़ी मेहनत करना चाहता था। '$ pathToSecurity = __DIR__। '/../../../ ..'। '/app/config/security.yml'; ' ' – Chris

+0

एक वैश्विक चर का उपयोग करने जैसा ही होगा जो कि अच्छा ओओ स्वाद नहीं है .. कंटेनर के साथ ऐसी चीजों को इंजेक्ट करने के लिए हमेशा बेहतर होता है (कंटेनर पैरामीटर security.role_hierarchy .roles) –

11

आप इस पद्धति से प्राप्त किए भूमिकाओं की एक सूची प्राप्त कर सकते हैं:

Symfony\Component\Security\Core\Role\RoleHierarchy::getReachableRoles(array $roles) 

यह सब भूमिकाओं सरणी $roles पैरामीटर में भूमिका से पहुँच में वापस जाने के लिए लगता है। यह सिम्फनी की एक आंतरिक सेवा है, जिसका आईडी security.role_hierarchy है और यह सार्वजनिक नहीं है (आपको इसे पैरामीटर के रूप में स्पष्ट रूप से पास करना होगा, यह सेवा कंटेनर से स्वीकार्य नहीं है)।

+1

इस अच्छे उत्तर के अलावा मैंने एक [gist] बनाया (https: //gist.github।कॉम/ग्लाइडह/27edd82b6b953b0b431225de9796c697) 'प्रयोक्ताफॉर्म टाइप' –

-1

यहाँ मैं क्या किया है:

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)); 
} 

कृपया प्रतिक्रिया प्रदान करते हैं ... मैं कुछ सुझाव दूसरे से उपयोग किया है जवाब, लेकिन मुझे अभी भी लगता है कि यह सबसे अच्छा समाधान नहीं है!

7

आप इसके लिए एक सेवा कर सकते हैं और "security.role_hierarchy.roles" पैरामीटर इंजेक्ट कर सकते हैं।

सेवा परिभाषा:

acme.user.roles: 
    class: Acme\DemoBundle\Model\RolesHelper 
    arguments: ['%security.role_hierarchy.roles%'] 

सेवा वर्ग: Symfony 2.7 में

$roles = $this->get('acme.user.roles')->getRoles(); 
+1

मैं सलाह देता हूं कि हर बार 'getRoles' कहलाए जाने पर इसे रोकने से बचने के लिए कन्स्ट्रक्टर में पदानुक्रम चलना पड़ेगा। – Jonny

+0

आप सही हैं। एक बार केवल array_walk_recursive को कॉल करने के लिए उत्तर संपादित करें। –

+0

आप अभी भी हर बार 'getRoles()' कहलाते हैं। सेवा शुरू होने पर ऐसा क्यों नहीं करते? – Jonny

1

, नियंत्रकों में आपके पास:

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); 
    } 
} 

आप इस तरह अपने नियंत्रक में भूमिका मिल सकती है $-- 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); 
8

आपकी भूमिकाओं के सही प्रतिनिधित्व के लिए, आपको रिकर्सन की आवश्यकता है। भूमिकाएं अन्य भूमिकाओं का विस्तार कर सकती हैं।

मैं security.yml में उदाहरण के लिए folowing भूमिकाओं का उपयोग करें: प्रत्यावर्तन के साथ

$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); 
    } 
} 

ROLE_SUPER_ADMIN: ROLE_ADMIN 
ROLE_ADMIN:  ROLE_USER 
ROLE_TEST:  ROLE_USER 

आप के साथ इस भूमिकाओं प्राप्त कर सकते हैं आउटपुट:

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', 
), 
) 
+0

उपलब्ध है यदि 'autowire' और' autogofigure' सत्य पर सेट हैं। मैं व्यक्तिगत रूप से यह बिल्कुल पसंद नहीं करता ..! यदि नहीं, तो 'services.yml' में पहले की तरह' RolesType' सेट करें – Delphine

1

आप कुछ भूमिका के सभी विरासत में मिला भूमिकाओं पाने के लिए की जरूरत है: $this->getRoles('ROLE_ADMIN');

2

Symfony 3.3 में, आप एक RolesType.php इस प्रकार बना सकते हैं::

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 फोन

<?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]