12

So I have my controller action similar to this

$task1 = new Task();
$form1 = $this->createForm(new MyForm(), $task1);

$task2 = new Task();
$form2 = $this->createForm(new MyForm(), $task2);

And let's say my MyForm has two fields

//...
$builder->add('name', 'text');
$builder->add('note', 'text');
//...

It seems like since the two forms are of the same type MyForm, when rendered in the views, their fields have the same name and IDs (the 'name' fields of two forms share the same name and id; the same goes for the 'note' fields), because of which Symfony may not bind the forms' data correctly. Does anyone know any solution to this?

0x56794E
  • 20,883
  • 13
  • 42
  • 58

4 Answers4

19
// your form type
class myType extends AbstractType
{
   private $name = 'default_name';
   ...
   //builder and so on
   ...
   public function getName(){
       return $this->name;
   }

   public function setName($name){
       $this->name = $name;
   }

   // or alternativ you can set it via constructor (warning this is only a guess)

  public function __constructor($formname)
  {
      $this->name = $formname;
      parent::__construct();
  }

}

// you controller

$entity  = new Entity();
$request = $this->getRequest();

$formType = new myType(); 
$formType->setName('foobar');
// or new myType('foobar'); if you set it in the constructor

$form    = $this->createForm($formtype, $entity);

now you should be able to set a different id for each instance of the form you crate.. this should result in <input type="text" id="foobar_field_0" name="foobar[field]" required="required> and so on.

Flask
  • 4,966
  • 1
  • 20
  • 39
10

I would use a static to create the name

// your form type

    class myType extends AbstractType
    {
        private static $count = 0;
        private $suffix;
        public function __construct() {
            $this->suffix = self::$count++;
        }
        ...
        public function getName() {
            return 'your_form_'.$this->suffix;
        }
    }

Then you can create as many as you want without having to set the name everytime.

Stéphan Champagne
  • 1,259
  • 12
  • 12
  • 1
    This is the best answer. – Stan Jan 21 '15 at 12:46
  • It's a good answer, thx. But I'm wondering if it can scale correctly with a large amount of user ? – Thomas Leduc Feb 08 '15 at 16:04
  • @ThomasLeduc It's very unlikely the amount of users will be an issue with this kind of pattern. The variable $count will be initialized just once per request and incremented as many times as you have form created in one request. Even if you had thousands of forms, the variable shouldn't be an issue (but you would then have other kind of issues I guess) – Julien Apr 26 '16 at 12:14
6

EDIT: Do not do that! See this instead: http://stackoverflow.com/a/36557060/6268862

In Symfony 3.0:

class MyCustomFormType extends AbstractType
{
    private $formCount;

    public function __construct()
    {
        $this->formCount = 0;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        ++$this->formCount;
        // Build your form...
    }

    public function getBlockPrefix()
    {
        return parent::getBlockPrefix().'_'.$this->formCount;
    }
}

Now the first instance of the form on the page will have "my_custom_form_0" as its name (same for fields' names and IDs), the second one "my_custom_form_1", ...

peamak
  • 239
  • 5
  • 7
  • I should note that this is probably note the best idea because when you will submit your form, the count will be initialized and therefore the form will **not** actually be submitted (difference between the form name and the data in the request). One should instead use the createNamedBuilder method as explained here: http://stackoverflow.com/a/36557060/6268862 – peamak May 11 '16 at 13:57
  • in Symfony3, a constructor is not allowed anymore in a formtype – Zwen2012 Nov 24 '16 at 11:00
0

create a single dynamic name :

const NAME = "your_name";

public function getName()
{
    return self::NAME . '_' . uniqid();
}

your name is always single

Snoozer
  • 585
  • 1
  • 8
  • 16