The form's view data is expected to be an instance of MyEntity but is an instance of ArrayCollection
Asked Answered
E

3

5

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?

Eolithic answered 27/7, 2016 at 11:41 Comment(2)
A purchase can have more then one address correct? If so then use @DOZ solution but always add at least one address to purchase so the address form is displayed. $purchase->setAddress(new Address());Cockney
@Cockney thank you, that information also helpsEolithic
F
7

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

Fosque answered 27/7, 2016 at 12:14 Comment(3)
thanks for helping, I've tried with ->add('addresses', CollectionType::class, array( 'entry_type' => AddressType::class)) but then only the purchase form get's displayedEolithic
yes you have to add some javascript to display address form, see this : symfony.com/doc/current/cookbook/form/…Fosque
Thanks again, now I see. I might have to re think about my Entities. I consider it's bad practice to use javascript to have a form complete in DOM. Like it showed up before, in my opinion is actually better because the form is complete without javascript. The problem is I'm not able to flush the data to the database. I don't think is good practice to solve that problem with javascript...?!Eolithic
P
1

I got similar error in a Symfony 7 app: The form's view data is expected to be a "App\Entity\Comment", but it is a "array". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "array" to an instance of "App\Entity\Comment".

It was because I wrote this in the Controller:

$form = $this->createForm(CommentType::class, [
    'action' => $this->generateUrl('blog_add_comment', ['blog' => $blog->getId()])
]);

To fix the error I added null as the second argument:

$form = $this->createForm(CommentType::class, null, [
    'action' => $this->generateUrl('blog_add_comment', ['blog' => $blog->getId()])
]);
Portamento answered 21/6 at 5:35 Comment(0)
B
0

I had the same issue, in my case the solution was to properly specify the data_class in the appropriate Type's configureOptions() method, like this:

   public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => SomeEntity::class,
        ]);
    }
Biotype answered 21/8 at 15:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.