2012-10-04 31 views
9

Tengo 2 entidades: usuario y grupo. Tienen una relación de muchos a muchos y Group se usa para almacenar los roles de los usuarios.Symfony 2 Colección de formularios incrustados Muchos a muchos

que estoy tratando de hacer un formulario de edición del usuario mediante la adición de una colección, quiero ser capaz de añadir un nuevo papel seleccionándolo de una lista desplegable (limitado a lo que ya está en la base de datos)

UserType. php:

class UserType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('username') 
      ->add('email') 
      ->add('forename') 
      ->add('surname') 
      ->add('isActive') 
      ->add('joinDate', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) 
      ->add('lastActive', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) 
      ->add('groups', 'collection', array(
        'type' => new GroupType(), 
        'allow_add' => true, 
        )) 
     ; 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'Sfox\CoreBundle\Entity\User' 
     )); 
    } 
} 

y GroupType.php:

class GroupType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('name') 
      ->add('role'); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
       "data_class" => 'Sfox\CoreBundle\Entity\Group' 
       )); 
    } 
} 

Esto muestra los papeles en forma de cuadros de texto básicos, pero si agrego una entrada a la forma, que caerá en cascada persistir una nueva ent en Grupos y si tuviera que editar una entrada, cambiaría los datos de Grupo subyacentes.

He intentado hacer una GroupSelectType.php:

class GroupSelectType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('role', 'entity', array('class'=>'SfoxCoreBundle:Group', 'property'=>'name')); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
       "data_class" => 'Sfox\CoreBundle\Entity\Group' 
       )); 
    } 
} 

Añadiendo el campo como un tipo de "entidad", esto muestra el cuadro de selección correcta (pero con los valores por defecto) Me parece que no puede obligar a la Forma de UserType!

Todo lo que quiero que haga la forma es modificar los 'grupos' subyacentes ArrayCollection en la entidad Usuario.

¿Alguien sabe cómo puedo lograr esto?

Respuesta

14

Bueno, funcionó una solución para cualquier otra persona que luchan con problemas similares ...

tuviera que crear un tipo de formulario personalizado y declarar como un servicio para que pudiera pasar en el gestor de entidades. entonces yo tenía que hacer una dataTransformer cambiar mi grupo de objetos en un entero de forma

personalizada GroupSelectType:

class GroupSelectType extends AbstractType 

{ 
    /** 
    * @var ObjectManager 
    */ 
    private $om; 

    private $choices; 

    /** 
    * @param ObjectManager $om 
    */ 
    public function __construct(ObjectManager $om) 
    { 
     $this->om = $om; 

     // Build our choices array from the database 
     $groups = $om->getRepository('SfoxCoreBundle:Group')->findAll(); 
     foreach ($groups as $group) 
     { 
      // choices[key] = label 
      $this->choices[$group->getId()] = $group->getName() . " [". $group->getRole() ."]"; 
     } 
    } 

    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $transformer = new GroupToNumberTransformer($this->om); 
     $builder->addModelTransformer($transformer); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
       "choices" => $this->choices, 
       )); 
    } 

    public function getParent() 
    { 
     return 'choice'; 
    } 

    public function getName() 
    { 
     return 'group_select'; 
    } 
} 

En el constructor que estoy recibiendo todos los grupos disponibles y ponerlas en un "opciones" matriz que se pasa al cuadro de selección como una opción.

También notará que estoy usando un transformador de datos personalizado, esto es para cambiar groupId (que se utiliza en la representación del formulario) a una entidad de grupo. Hice el GroupSelectType un servicio, así y aprobada en la [@ doctrine.orm.entity_manager]

services.yml (config paquete):

services: 
    sfox_core.type.group_select: 
     class: Sfox\CoreBundle\Form\Type\GroupSelectType 
     arguments: [@doctrine.orm.entity_manager] 
     tags: 
      - { name: form.type, alias: group_select } 

GroupToNumberTranformer.php

class GroupToNumberTransformer implements DataTransformerInterface 
{ 
    /** 
    * @var ObjectManager 
    */ 
    private $om; 

    /** 
    * @param ObjectManager $om 
    */ 
    public function __construct(ObjectManager $om) 
    { 
     $this->om = $om; 
    } 

    /** 
    * Transforms an object (group) to a string (number). 
    * 
    * @param Group|null $group 
    * @return string 
    */ 
    public function transform($group) 
    { 
     if (null === $group) { 
      return ""; 
     } 

     return $group->getId(); 
    } 

    /** 
    * Transforms a string (number) to an object (group). 
    * 
    * @param string $number 
    * @return Group|null 
    * @throws TransformationFailedException if object (group) is not found. 
    */ 
    public function reverseTransform($number) 
    { 
     if (!$number) { 
      return null; 
     } 

     $group = $this->om 
     ->getRepository('SfoxCoreBundle:Group') 
     ->findOneBy(array('id' => $number)) 
     ; 

     if (null === $group) { 
      throw new TransformationFailedException(sprintf(
        'Group with ID "%s" does not exist!', 
        $number 
      )); 
     } 

     return $group; 
    } 
} 

Y mi UserType.php modificado - Aviso que estoy usando mi formulario personalizado tipo "group_select" ahora mientras se está ejecutando como un servicio:

class UserType extends AbstractType 
{ 
    private $entityManager; 

    public function __construct($entityManager) 
    { 
     $this->entityManager = $entityManager; 
    } 

    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $transformer = new GroupToNumberTransformer($this->entityManager); 

     $builder 
      ->add('username') 
      ->add('email') 
      ->add('forename') 
      ->add('surname') 
      ->add('isActive') 
      ->add('joinDate', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) 
      ->add('lastActive', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')); 
     $builder 
      ->add(
       $builder->create('groups', 'collection', array(
        'type' => 'group_select', 
        'allow_add' => true, 
        'options' => array(
          'multiple' => false, 
          'expanded' => false, 
          ) 
        )) 
     ); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'Sfox\CoreBundle\Entity\User' 
     )); 
    } 

    public function getName() 
    { 
     return 'sfox_corebundle_usertype'; 
    } 
} 
+0

¡Esta respuesta me ayudó muchísimo! ¡Gracias! – jcbwlkr

+0

¡Perfecto gracias! –

+0

Muy útil. Gracias – Rinat

Cuestiones relacionadas