2

I have a Doctrine Entity that uses a Doctrine embeddable.

I want to create a form to edit the Entity and the Embeddable.

My Entity:

/**
 * MyEntity
 *
 * @ORM\Table(name="my_entities")
 * @ORM\Entity(repositoryClass="\AppBundle\Entity\MyEntityRepository")
 * @ORM\HasLifecycleCallbacks
 */
class MyEntity
{
    ...

    /**
     * @var MyEmbeddableInfo
     *
     * @ORM\Embedded(class="AppBundle\Entity\Embeddable\MyInfoEmbeddable")
     */
    private $myInfo;

    ...

My Embeddable:

/**
 * @ORM\Embeddable
 */
class MyInfoEmbeddable
{
    /**
     * @var string
     *
     * @ORM\Column(name="info1", type="string", nullable=true)
     *
     * @Assert\NotBlank(groups={"setUp"})
     */
    private $info1;

    /**
     * @var string
     *
     * @ORM\Column(name="info2", type="string", nullable=true)
     *
     * @Assert\NotBlank(groups={"setUp"})
     */
    private $info2;

    /**
     * @var
     *
     * @ORM\Column(name="info3", type="string", nullable=true)
     *
     * @Assert\NotBlank(groups={"setUp"})
     */
    private $info3;

    ...

WHAT I'VE TRIED

I found this question here on Stackoverflow and it seems the user had my same problem, but the difference is that I never get that Warning as I simply don't understand the basic procedure to create a form for the embeddable object.

I make two tests: one passing directly the embeddable object to the MyEntityType form builder and one creating a MyInfoType() form type.

TEST 1: PASS DIRECTLY THE EMBEDDABLE OBJECT

This is the code of my MyEntityTypeclass:

class MyEntityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ...
            ->add('myInfo', 'entity', ['class' => '\AppBundle\Entity\Embeddable\MyInfoEmbeddable'])
            ...
    }

    public function getName()
    {
        return 'MyEntity';
    }
}

This solutions throws a RuntimeException:

Class \AppBundle\Entity\Embeddable\MyInfoEmbeddable seems not to be a managed Doctrine entity. Did you forget to map it?

TEST 2: PASSING THE MyInfoType OBJECT

The second test I make is using a form type (as suggested in the linked SO question):

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ...
            ->add('myInfo', new MyInfoType())
            ...
    }

And this is the code of MyInfoType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('infoField1', 'text', ['required' => false])
        ->add('infoField2', 'text', ['required' => false])
        ->add('infoField3', 'choice', [
                'choices'   => [
                    '' => '',
                    'choice1' => 'Choice 1',
                    'choice2' => 'Choice 2',
                    'choice3' => 'Choice 3'
                ],
                'required' => false
            ]
        );
}

This, instead, returns a Symfony\Component\PropertyAccess\Exception\NoSuchIndexException:

Cannot read index infoField1 from object of type AppBundle\Entity\Embeddable\MyInfoEmbeddable because it doesn't implement \ArrayAccess.

So, this solution doesn't work, too.

My goal is to create a form for MyEntity and in this form create also the fields to update MyInfoEmbeddable.

Which is the correct procedure to follow?

Community
  • 1
  • 1
Aerendir
  • 6,152
  • 9
  • 55
  • 108

2 Answers2

4

Instead of this in your main form:

$builder->add('myInfo', new MyInfoType(), 
['data_class' => '\AppBundle\Entity\Embeddable\MyInfoEmbeddable'])

You can add this in your MyInfoType form (which, I believe, linked with embeddable entity):

public function configureOptions(OptionsResolver $resolver)
{
   $resolver->setDefaults([
      'data_class' => '\AppBundle\Entity\Embeddable\MyInfoEmbeddable',
   ]);
}

And then simple invoke embeddable form type in your main form like this:

$builder->add('myInfo', new MyInfoType())
Vasiliy Toporov
  • 814
  • 12
  • 27
2

After some other searches with different keywords I came up with this answer here on SO that helped me to solve problem.

I were really near to the solution. I simply omitted a required parameter to make the form be built.

The solution is to pass the data_class parameter to the add() method of the FormBuilder:

...
$builder
    ->add('myInfo', new MyInfoType(), ['data_class' => '\AppBundle\Entity\Embeddable\MyInfoEmbeddable'])
...
Community
  • 1
  • 1
Aerendir
  • 6,152
  • 9
  • 55
  • 108
  • 1
    I know, this is a quastion of taste, but I suggest to move 'data_class' attribute from the field invoking in your main form to configureOptions method of your embeddable form. – Vasiliy Toporov Feb 23 '17 at 12:59
  • Can you write an answer to clarify what do you mean? – Aerendir Feb 23 '17 at 13:15