Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Formularios dinámicos con la misma entidad en Symfony 3

16 de febrero de 2016

Estoy usando el bundle stof/doctrine-extensions-bundle en Symfony 3 para crear una jerarquía de categorías. Quiero crear un formulario dinámico, de forma que cuando elija una categoría me muestre las subcategorías (con Ajax).

El ejemplo que aparece en la documentación lo he probado y funciona con diferentes entidades, por ejemplo que aparezcan las ciudades cuando seleccionas provincias, ambas en entidades diferentes.

Pero con la misma entidad Category me aparece el error:

Entities passed to the choice field must be managed.
Maybe persist them in the entity manager?

Mi código es como en la documentación Symfony, excepto que obtengo las subcategorías con el siguiente $formModifier:

$formModifier = function (FormInterface $form, Category $category = null) {
    $children = null === $category ? array() : $category->getChildren();
 
    $form->add('children', EntityType::class, array(
        'class'       => 'AppBundle:Category',
        'placeholder' => '',
        'em' => 'ManagerRegistry',
        'choices' => $children
    ));
};

La entidad es igual que por defecto del bundle Doctrine Extensions.

He probado varias cosas pero siempre me dice que la opción choices tiene que persistirse, imagino que es porque es la misma entidad. También he probado inyectando un entity manager y probando consultas y persistiendo, pero sin éxito.

¿Cómo podría obtener las subcategorías cuando selecciono las categorías en una misma entidad?


Respuestas

#1

Al parecer, se trata de un error de Symfony:

  • En este issue hay una discusión sobre esto.
  • Este Pull Request ha corregido el problema y estará disponible en las próximas versiones de Symfony.
  • En esta respuesta de StackOverflow se habla sobre una posible alternativa.

@javiereguiluz

17 febrero 2016, 9:09
#2

Gracias Javier.

Al final he inyectado un Entity Manager en el Type y he utilizado el ChoiceType, no se si es lo más correcto pero funcionar funciona.

También me daba un error al intentar obtener la categoría con $data->getCategory():

"Error: Call to a member function getCategory() on null"

por lo que he tenido que añadir el condicional if($data).

class SearchSubType extends AbstractType
{
    protected $em;
 
    public function __construct(ObjectManager $em)
    {
        $this->em = $em;
    }
 
    public function getCategories()
    {
        $categories = $this->em->getRepository('AppBundle:Category')->getRootNodes();
        return $categories;
    }
 
    public function getChildren(Category $category)
    {
        return $children = $category->getChildren();
    }
 
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('category', ChoiceType::class, array(
                'choices' => $this->getCategories(),
                'choice_label' => function ($value, $key, $index){
                    return $value;
                }
            ));
 
        $formModifier = function (FormInterface $form, $data = null) {
 
            if($data === null) {
                $data = new Category;
            }
 
            $children = null === $data->getCategory() ? array() : $this->getChildren($data->getCategory());
 
            $form->add('subcategory', ChoiceType::class, array(
                'choices' => $children,
                'choice_label' => function ($value, $key, $index){
                    return $value;
                }
            ));
        };
 
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {
                $data = $event->getData();
 
                $formModifier($event->getForm(), $data);
            }
        );
 
        $builder->get('category')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {
 
                $category = $event->getForm()->getData();
 
                $formModifier($event->getForm()->getParent(), $category);
            }
        );
    }
}

@diegotham

17 febrero 2016, 12:12