I can create a form which works fine but getting errors when trying to flush data to the database:
The controller action looks like this:
$purchase = new Purchase();
$form = $this->createFormBuilder($purchase)
->add('addresses', AddressType::class)
->add('quantity', IntegerType::class)
->add('toBeDeliveredAt', DateType::class)
->add('comment', TextareaType::class)
->add('save', SubmitType::class, array('label' => 'Submit'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($purchase);
$em->flush();
}
Class AddressType looks like this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class)
->add('firstname', TextType::class)
->add('lastname', TextType::class)
->add('street', TextType::class)
->add('city', TextType::class)
->add('zipcode', TextType::class)
->add('country', TextType::class)
->add('phone', TextType::class)
->add('email', EmailType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'XxxBundle\Entity\Address'
));
}
But that gives me the following error:
The form's view data is expected to be an instance of class XxxBundle\Entity\Address, but is an instance of class Doctrine\Common\Collections\ArrayCollection. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class Doctrine\Common\Collections\ArrayCollection to an instance of XxxBundle\Entity\Address.
If I set the data_class
option to null I get
Warning: spl_object_hash() expects parameter 1 to be object, string given
How can I add a view transformer that transforms an instance of class ArrayCollection to an instance of Address?
Addresses
is an array collection so you have to use it as an collection in your form like this :
$builder->add('addresses', CollectionType::class, array(
'entry_type' => AddressType::class
));
Instead of this :
$builder->add('addresses', AddressType::class)
In this way you embed Address Form into Purchase Form
You can see the doc about embed a collection of form here
Explanations (sorry for my bad English) :
You have to think about object.
In your Purchase Entity you have a collection of Address because a Purchase object can have many address that is to say to persist Purchase object you have to give a collection of addresses.
So when you built your Purshase form, Symfony expects an array collection for addresses input. It is what I wrote above. With this, if you are in the case where you want to add a new Purchase object, when you go to view the form, to display fields corresponding to the Address, you have to do this into your form:
<ul class="addresses">
{# iterate over each existing address and render these fields #}
{% for address in form.addresses %}
<li>{{ form_row(address.title) }}</li>
//do this for all the others fields ...
{% endfor %}
</ul>
But if you want to add many address dynamically, you have to do 2 things :
First, you have to do add 'allow_add' => true
in the form builder
$builder->add('addresses', CollectionType::class, array(
'entry_type' => AddressType::class,
'allow_add' => true,
));
Second, the allow_add
also makes a "prototype" variable available to you in the form html generated : this is where Javascript come in :)
To do work this, you have to write some Javascript and you can see a good example here
I hope that it's clearer