Search code examples
symfonysymfony5

Symfony manually $form->submit(); with multidimensional array


I'm struggling for 10 hours with Symfony 5.1.7 and $form->submit();

My goal is to create a JSON API that converts data to a simillar array. I already debugged and found following part.

Can someone please tell me what am I doing wrong here?

To test it, i have manually created a PHP array to submit.

My Code in Controller

        $form = $this->createForm(AddCommentFormType::class);

        $test = [
            'content' => 'Test',
            'media' => [
                [
                    'path' => '1.png',
                ],
                [
                    'path' => '2.png',
                ],
            ],
            '_token' => '3bF4qkiUPjKNuGnbY-ySdO6B2sCLzKcS4ar7auX3Dek',
        ];

        $form->submit($test);

AddCommentFormType

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('content', TextareaType::class, [
                'constraints' => [
                    new NotBlank(),
                    new Length([
                        'max' => 10000,
                    ]),
                ],
            ])
            ->add('media', CollectionType::class, [
                'entry_type' => MediaFormType::class,
                'constraints' => [
                    new Count([
                        'min' => 1,
                        'max' => 5,
                    ]),
                ],
            ])
            ->add('_token', HiddenType::class, [
                'mapped' => false,
                'constraints' => [
                    new NotBlank(),
                ],
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'csrf_protection' => false,
        ]);
    }

MediaFormType

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('path', TextType::class, [
                'constraints' => [
                    new NotBlank(),
                ],
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Media::class,
        ]);
    }

Validator Result

children[media].data
This collection should contain 1 element or more.   
[]


children[media]
This form should not contain extra fields.  
[▼
  [▼
    "path" => "1.png"
  ]
  [▼
    "path" => "2.png"
  ]
]

Solution

  • your form has no default data, since you create it with

    $form = $this->createForm(AddCommentFormType::class);
    

    createForm can take an additional parameter for default data. This alone is not necessarily a problem, the default is an array of the form (or something very similar, maybe empty strings instead of null)

    [
        'content' => null, 
        'media' => [], 
        '_token' => null,
    ]
    

    However, the CollectionType will not allow adding or removing elements by default. Setting it's options allow_add (and optionally allow_remove, if you ever set default values) will change that.

    So the minimal change would be:

                ->add('media', CollectionType::class, [
                    'allow_add' => true,                  // <-- this is new
                    'entry_type' => MediaFormType::class,
                    'constraints' => [
                        new Count([
                            'min' => 1,
                            'max' => 5,
                        ]),
                    ],
                ])