symfony icon indicating copy to clipboard operation
symfony copied to clipboard

[Form] FormFactory::createNamed renders duplicate HTML attributes in form rendering

Open albangonzalez opened this issue 2 years ago • 6 comments

Symfony version(s) affected

6.2.9

Description

Creating a simple FormType class and instancianting it with FormFactory::createNamed in a Controller will render an HTML form and the nested div with duplicate attributes if both conditions are satisfied:

  • $name parameter is an empty string
  • $options array is passed with values in "attr" option

How to reproduce

Create a simple FormType

<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class DummyType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('field_name')
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            // Configure your form options here
        ]);
    }
}

Create a controller

<?php

namespace App\Controller;

use App\Form\DummyType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DummyController extends AbstractController
{
    #[Route('/', name: 'app_dummy')]
    public function index(FormFactoryInterface $formFactory): Response
    {
        $form = $formFactory->createNamed('', DummyType::class, null, [
            'attr' => [ 
                'id' => 'my_dummy_id',
                'class' => 'my_dummy_class'
            ]
        ]);

        return $this->render('dummy/index.html.twig', [
            'form' => $form,
        ]);
    }
}

Render form in template

{{ form(form) }}

Actual form rendering

<form method="post" id="my_dummy_id" class="my_dummy_class">
    <div id="my_dummy_id" class="my_dummy_class">
        <div>
            <label for="field_name" class="required">Field name</label>
            <input type="text" id="field_name" name="field_name" required="required">
        </div>
        <input type="hidden" id="_token" name="_token" value="">
    </div>
</form>

HTML class and id attributes are rendered for the form and nested div elements with duplicate values.

Possible Solution

No response

Additional Context

No response

albangonzalez avatar Apr 24 '23 23:04 albangonzalez

Bug Reproducer repo: https://github.com/albangonzalez/symfony_issue_50145

albangonzalez avatar Apr 24 '23 23:04 albangonzalez

FYI, in the past there has been some discussion around this behaviour: #7709

xabbuh avatar Apr 27 '23 10:04 xabbuh

Hey, thanks for your report! There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

carsonbot avatar Oct 28 '23 13:10 carsonbot

Friendly ping? Should this still be open? I will close if I don't hear anything.

carsonbot avatar Nov 11 '23 13:11 carsonbot

Hey @carsonbot , yes this is still relevant. Just ran into this issue last week.

zyberspace avatar Nov 11 '23 14:11 zyberspace

My solution was to create a custom form theme and call {{form_rest(form)}}. In this example I was overriding form_div_layout.html.twig

{%- block form -%}
    {{ form_start(form) }}
    {{- form_rest(form) -}}
    {{ form_end(form) }}
{%- endblock form -%}

leevigraham avatar May 07 '24 05:05 leevigraham

I am closing here as no matter what solution we chose to mitigate the behaviour reported here it would always break backwards compatibility for some users (see the related discussion in #7709). On the other hand if you really need to pass attributes to the root form that shouldn't be rendered twice, you can always adapt the form theme to your needs and be done. Thank you for understanding.

xabbuh avatar Aug 05 '24 09:08 xabbuh