Symfony - form - many to many relation - collection type

南楼画角 提交于 2019-12-10 12:15:51

问题


Here is the situation:

I have an entity Property

class Property
{
    /**
     * @ORM\Id
     * @ORM\Column(type="string")
     * @ORM\GeneratedValue(strategy="UUID")
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="PropertyEquipment", inversedBy="properties")
     */
    protected $propertyEquipments;

    public function __construct()
    {
        $this->propertyEquipments = new ArrayCollection();
    }

    public function getId()
    {
        return $this->id;
    }

    public function addPropertyEquipment(\AppBundle\Entity\PropertyEquipment $propertyEquipment)
    {
        $this->propertyEquipments[] = $propertyEquipment;

        return $this;
    }

    public function removePropertyEquipment(\AppBundle\Entity\PropertyEquipment $propertyEquipment)
    {
        $this->propertyEquipments->removeElement($propertyEquipment);
    }

    public function getPropertyEquipments()
    {
        return $this->propertyEquipments;
    }
}

And the entity PropertyEquipment:

class PropertyEquipment
{

    /**
     * @ORM\Id
     * @ORM\Column(type="string")
     * @ORM\GeneratedValue(strategy="UUID")
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="Property", mappedBy="propertyEquipments")
     */
    protected $properties;

    /**
     * @ORM\Column(type="string", length=100)
     * @Gedmo\Translatable
     */
    protected $equipmentName;


    public function __construct()
    {
        $this->properties = new ArrayCollection();
    }

    /**
     * Get id
     *
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return mixed
     */
    public function getEquipmentName()
    {
        return $this->equipmentName;
    }

    /**
     * @param mixed $equipmentName
     */
    public function setEquipmentName($equipmentName)
    {
        $this->equipmentName = $equipmentName;
    }

    public function addProperty(Property $property)
    {
        $this->properties[] = $property;

        return $this;
    }

    public function removeProperty(Property $property)
    {
        $this->properties->removeElement($property);
    }

    public function getProperties()
    {
        return $this->properties;
    }
}

The form PropertyCreation

class PropertyCreation extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            //with this I see the values coming from DB in the template
            ->add("propertyEquipments", PropertyEquipmentCreation::class)

            //with this it's empty :/
            /*->add("propertyEquipments", CollectionType::class, array(
                "entry_type" => PropertyEquipmentCreation::class,
            ))*/
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Property::class
        ));
    }
}

Here is the form PropertyEquipmentCreation:

class PropertyEquipmentCreation extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder      
            ->add('propertyEquipment', EntityType::class, [
                'class' => 'AppBundle\Entity\PropertyEquipment',
                'choice_label' => 'equipmentName',
                'expanded' => true,
                'multiple' => true
            ]);
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => PropertyEquipment::class,
        ]);
    }
}

And the controller

public function createPropertyAction(Request $request)
{
    $property = new Property();

    $form = $this->createForm(PropertyCreation::class, $property);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->persist($property);
        $entityManager->flush();

        return $this->redirectToRoute('homepage');
    }
    return $this->render('form/owner_create_property.html.twig', ["form" => $form->createView()]);
}

My error:

Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "AppBundle\Entity\Property#$propertyEquipments", got "Doctrine\Common\Collections\ArrayCollection" instead.

Must I transform these with something like class PropertyEquipmentTransformer implements DataTransformerInterface?


回答1:


I think you should use getParent() function in PropertyEquipmentCreation and inherit from EntityType::class then put all your field configs in the configureOptions() function (remove the buildForm function) and it should work.

You are having this problem because it is a compound form in your implementation and no simple form and symfony is unable to resolve which field created inside the subform needs to be used as source for the entity field




回答2:


First !

Big thanks to Nickolaus !

Here is the solution (PropertyEquipmentCreation):

namespace AppBundle\Form\Type;

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;


class PropertyEquipmentCreation extends AbstractType
{

/**
 * @param OptionsResolver $resolver
 */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'class' => 'AppBundle\Entity\PropertyEquipment',
        'choice_label' => 'equipmentName',
        'expanded' => true,
        'multiple' => true,
    ]);
}

public function getParent()
{
    return EntityType::class;
}
}

And for (PropertyCreation)

<?php


namespace AppBundle\Form;


use AppBundle\Form\Type\PropertyEquipmentCreation;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class PropertyCreation extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('description', TextareaType::class)
        ->add('name', TextType::class)
        ->add("propertyEquipments", PropertyEquipmentCreation::class)
        ->add('save', SubmitType::class);
}

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => Property::class
    ));
}
}

Many thanks !




回答3:


Try using Doctrine ArrayCollection instead of ArrayCollections:

$this->propertyEquipments = new \Doctrine\Common\Collections\ArrayCollection();

This should work!



来源:https://stackoverflow.com/questions/39751434/symfony-form-many-to-many-relation-collection-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!