user3714751
user3714751

Reputation: 336

Symfony: Expected argument of type "?Doctrine\Common\Collections\Collection", "array" given at property path

i have a entity called DynamicForm, which looks like this:

<?php

namespace App\Entity\Product\DynamicForm;

use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Entity;

/**
 * Class DynamicForm
 * @package App\Entity\Product
 *
 * @Entity
 * @ORM\Table(name="product_dynamic_form")
 */
class DynamicForm
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(name="id", type="integer", unique=true, nullable=false)
     */
    private ?int $id = null;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Product\DynamicForm\Component\Text", mappedBy="dynamicForm")
     * @ORM\JoinColumn(name="component_text_id", referencedColumnName="id")
     */
    private ?Collection $textComponents;

    /**
     * @return Collection|null
     */
    public function getTextComponents(): ?Collection
    {
        return $this->textComponents;
    }

    /**
     * @param Collection|null $textComponents
     *
     * @return DynamicForm
     */
    public function setTextComponents(?Collection $textComponents): DynamicForm
    {
        $this->textComponents = $textComponents;

        return $this;
    }
}

Also i created a related type for it - DynamicFormType:

<?php

namespace App\Type\Product\DynamicForm;

use App\Entity\Product\DynamicForm\DynamicForm;
use App\Type\Product\DynamicForm\Component\TextType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class DynamicFormType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('textComponents', CollectionType::class, [
                'entry_type'    => TextType::class,
                'entry_options' => ['label' => false],
                'allow_add'     => true,
                'allow_delete'  => true,
                'label'         => ' '
            ])
            ->add('submit', SubmitType::class, [
                'label' => 'form.basic.save'
            ]);
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefault('data_class', DynamicForm::class);
    }
}

The TextType entry type class from the namespace App\Type\Product\DynamicForm\Component\TextType looks like this:

<?php

namespace App\Type\Product\DynamicForm\Component;

use App\Entity\Product\DynamicForm\Component\Text;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as FormType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;

class TextType extends AbstractType
{
    private TranslatorInterface $translator;

    /**
     * TextType constructor.
     *
     * @param TranslatorInterface $translator
     */
    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('label', FormType\TextType::class, [
                'required'           => true,
                'translation_domain' => 'wedding',
                'label'              => 'setting.form.dynamic_by_user.query_to_guest'
            ])
            ->add('type', FormType\ChoiceType::class, [
                'required'                  => true,
                'translation_domain'        => 'wedding',
                'label'                     => 'setting.form.dynamic_by_user.select_type',
                'attr'                      => [
                    'class'                       => 'enriched',
                    'data-search-placeholder'     => $this->translator->trans('select.search'),
                    'data-search-no-results-text' => $this->translator->trans('select.search_no_results_found')
                ],
                'choice_translation_domain' => 'wedding',
                'choices'                   => [
                    'setting.form.dynamic_by_user.type_text'     => Text::TYPE_TEXT_FIELD,
                    'setting.form.dynamic_by_user.type_textarea' => Text::TYPE_TEXT_AREA,
                    'setting.form.dynamic_by_user.type_email'    => Text::TYPE_EMAIL_FIELD,
                    'setting.form.dynamic_by_user.type_number'   => Text::TYPE_NUMBER_FIELD,
                ]
            ]);
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefault('data_class', Text::class);
    }
}

While i try to transmit the form, the request in the controller contains the form data as you can see it, in the following screenshot: enter image description here

My problem is now that i always get the following error (while handling the request for the form via ->handleRequest($request) on created form in controller):

Expected argument of type "?Doctrine\Common\Collections\Collection", "array" given at property path "textComponents".

I have such collection settings also in other classes, but without problems - I don't know any further, can anyone please assist me or see the error?

(I am using Symfony version 5.2.9, if u need any further info just ask for it - I will give it to you as soon as possible)

Upvotes: 6

Views: 6861

Answers (2)

MT_Shikomba
MT_Shikomba

Reputation: 187

I was able to fix this by doing this, that allows us to pass a Collection or an empty array or an array of your entity which I think is Text:

/**
     * @param Collection|Text[] $textComponents
     *
     * @return DynamicForm
     */
    public function setTextComponents($textComponents): DynamicForm
    {
        $this->textComponents = $textComponents;

        return $this;
    }

Upvotes: 1

Artem
Artem

Reputation: 1646

Trying to add a constructor in your entity

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

Add addTextComponent and removeTextComponent methods intead of setTextComponents

public function addTextComponent(Text $textComponent): self
{
    $textComponent->setDynamicForm($this);
    $this->textComponents->add($textComponent);

    return $this;
}

public function removeTextComponent(Text $textComponent): self
{
    $this->textComponents->removeElement($textComponent);

    return $this;
}

Add 'by_reference' => false in the textComponents form params

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('textComponents', CollectionType::class, [
            'entry_type'    => TextType::class,
            'entry_options' => ['label' => false],
            'allow_add'     => true,
            'allow_delete'  => true,
            'label'         => ' ',
            'by_reference'  => false,
        ])
        ->add('submit', SubmitType::class, [
            'label' => 'form.basic.save'
        ]);
}

Upvotes: 7

Related Questions