69

I am creating a form in the following manner:

$form = $this->createFormBuilder($breed)
             ->add('species', 'entity', array(
                  'class' => 'BFPEduBundle:Item',
                  'property' => 'name',
                  'query_builder' => function(ItemRepository $er){
                      return $er->createQueryBuilder('i')
                                ->where("i.type = 'species'")
                                ->orderBy('i.name', 'ASC');
                  }))
             ->add('breed', 'text', array('required'=>true))
             ->add('size', 'textarea', array('required' => false))
             ->getForm()

How can I set a default value for the species listbox?


Thank you for your response, I apologise, I think I should rephrase my question. Once I have a value that I retrieve from the model, how do I set that value as SELECTED="yes" for the corresponding value in the species choice list?

So, that select option output from the TWIG view would appear like so:

<option value="174" selected="yes">Dog</option>
Gordon
  • 312,688
  • 75
  • 539
  • 559
Matt G
  • 1,332
  • 2
  • 13
  • 25

12 Answers12

115

You can define the default value from the 'data' attribute. This is part of the Abstract "field" type (http://symfony.com/doc/2.0/reference/forms/types/field.html)

$form = $this->createFormBuilder()
            ->add('status', 'choice', array(
                'choices' => array(
                    0 => 'Published',
                    1 => 'Draft'
                ),
                'data' => 1
            ))
            ->getForm();

In this example, 'Draft' would be set as the default selected value.

bentidy
  • 1,159
  • 2
  • 7
  • 2
  • This worked for me. I provided an array of defaults in the 'data' attribute and that worked also. Thanks! – Nils Luxton Mar 05 '12 at 17:23
  • 3
    This doesn't seem to work for radio buttons. It could be just me. – Jason Swett Mar 29 '12 at 15:44
  • 2
    The data must refer to the key of the choices array. If you have multiple choices : array('foo1' => 'bar1', 'foo2' => 'bar2',...) then you must specify 'data' => array('foo1', 'foo2',...). Jason, maybe that's what your problem was. – Julien Jun 18 '12 at 16:21
  • I think this should be the preferred answer. It's very easy to use. – Alvin Bunk May 15 '16 at 02:54
  • This will override the value taken from Entity if you pass any Entity to your form (for edit page for example), not a good way – Vincent Decaux Sep 07 '19 at 12:21
60

If you use Cristian's solution, you'll need to inject the EntityManager into your FormType class. Here is a simplified example:

class EntityType extends AbstractType{
    public function __construct($em) {
        $this->em = $em;
    }

    public function buildForm(FormBuilderInterface $builder, array $options){
         $builder
             ->add('MyEntity', 'entity', array(
                     'class' => 'AcmeDemoBundle:Entity',
                     'property' => 'name',
                     'query_builder' => function(EntityRepository $er) {
                         return $er->createQueryBuilder('e')
                             ->orderBy('e.name', 'ASC');
                     },
                     'data' => $this->em->getReference("AcmeDemoBundle:Entity", 3)
        ));
    }
}

And your controller:

 // ...    

 $form = $this->createForm(new EntityType($this->getDoctrine()->getManager()), $entity);

// ...

From Doctrine Docs:

The method EntityManager#getReference($entityName, $identifier) lets you obtain a reference to an entity for which the identifier is known, without loading that entity from the database. This is useful, for example, as a performance enhancement, when you want to establish an association to an entity for which you have the identifier.

Community
  • 1
  • 1
Carrie Kendall
  • 11,124
  • 5
  • 61
  • 81
23

the solution: for type entity use option "data" but value is a object. ie:

$em = $this->getDoctrine()->getEntityManager();

->add('sucursal', 'entity', array
(

    'class' => 'TestGeneralBundle:Sucursal',
    'property'=>'descripcion',
    'label' => 'Sucursal',
    'required' => false,
    'data'=>$em->getReference("TestGeneralBundle:Sucursal",3)           

))
kleopatra
  • 51,061
  • 28
  • 99
  • 211
7

I think you should simply use $breed->setSpecies($species), for instance in my form I have:

$m = new Member();
$m->setBirthDate(new \DateTime);
$form = $this->createForm(new MemberType, $m);

and that sets my default selection to the current date. Should work the same way for external entities...

Kjir
  • 4,437
  • 4
  • 29
  • 34
  • My problem is exactly like this with a DateType - but my story is to add "" => "Choose..." as the default selected option to force a sane selection for a birthdate. I can make Choose show up in the options, just not default it, Every way I try it, Symfony complains that it expects an argument of DateTime type. I'm on an older version of Symfony2; I think they improved it with the new placeholder option. – phpguru Apr 01 '15 at 18:34
5

If you want to pass in an array of Doctrine entities, try something like this (Symfony 3.0+):

protected $entities;
protected $selectedEntities;

public function __construct($entities = null, $selectedEntities = null)
{
    $this->entities = $entities;
    $this->selectedEntities = $selectedEntities;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('entities', 'entity', [
        'class' => 'MyBundle:MyEntity',
        'choices' => $this->entities,
        'property' => 'id',
        'multiple' => true,
        'expanded' => true,
        'data' => $this->selectedEntities,
    ]);
}
Jonathan
  • 13,947
  • 17
  • 94
  • 123
  • 1
    Nice solution, works great when rendering entities as checkboxes and when I need set some them checked, based on a certain property value of the entity. – TheGhost Sep 21 '15 at 07:46
  • won't work in Symfony 2.8+ were you need to give the classname instead of the object –  Jan 31 '17 at 11:01
3

I don't think you should use the data option, because this does more than just setting a default value. You're also overriding any data that's being passed to the form during creation. So basically, you're breaking support for that feature. - Which might not matter when you're letting the user create data, but does matter when you want to (someday) use the form for updating data.

See http://symfony.com/doc/current/reference/forms/types/choice.html#data

I believe it would be better to pass any default data during form creation. In the controller.

For example, you can pass in a class and define the default value in your class itself. (when using the default Symfony\Bundle\FrameworkBundle\Controller\Controller)

$form = $this->createForm(AnimalType::class, [
    'species' => 174 // this id might be substituted by an entity
]);

Or when using objects:

$dog = new Dog();
$dog->setSpecies(174); // this id might be substituted by an entity

$form = $this->createForm(AnimalType::class, $dog);

Even better when using a factory: (where dog probably extends from animal)

$form = $this->createForm(AnimalType::class, DogFactory::create());

This will enable you to separate form structure and content from each other and make your form reusable in more situations.


Or, use the preferred_choices option, but this has the side effect of moving the default option to the top of your form.

See: http://symfony.com/doc/current/reference/forms/types/choice.html#preferred-choices

$builder->add(
    'species', 
    'entity', 
    [
        'class' => 'BFPEduBundle:Item',
        'property' => 'name',
        'query_builder' => ...,
        'preferred_choices' => [174] // this id might be substituted by an entity
     ]
 );
Maurice
  • 4,829
  • 7
  • 41
  • 50
2

From the docs:

public Form createNamed(string|FormTypeInterface $type, string $name, mixed $data = null, array $options = array())

mixed $data = null is the default options. So for example I have a field called status and I implemented it as so:

$default = array('Status' => 'pending');

$filter_form = $this->get('form.factory')->createNamedBuilder('filter', 'form', $default)
        ->add('Status', 'choice', array(
            'choices' => array(
                '' => 'Please Select...',
                'rejected' => 'Rejected',
                'incomplete' => 'Incomplete',
                'pending' => 'Pending',
                'approved' => 'Approved',
                'validated' => 'Validated',
                'processed' => 'Processed'
            )
        ))->getForm();
Hard-Boiled Wonderland
  • 1,359
  • 3
  • 17
  • 32
2

Setting default choice for symfony2 radio button

            $builder->add('range_options', 'choice', array(
                'choices' => array('day'=>'Day', 'week'=>'Week', 'month'=>'Month'),
                'data'=>'day', //set default value 
                'required'=>true,
                'empty_data'=>null,
                'multiple'=>false,
                'expanded'=> true                   
        ))
SudarP
  • 906
  • 10
  • 12
2

I'm not sure what you are doing wrong here, when I build a form using form classes Symfony takes care of selecting the correct option in the list. Here's an example of one of my forms that works.

In the controller for the edit action:

$entity = $em->getRepository('FooBarBundle:CampaignEntity')->find($id);

if (!$entity) {
throw $this->createNotFoundException('Unable to find CampaignEntity entity.');
}


$editForm = $this->createForm(new CampaignEntityType(), $entity);
$deleteForm = $this->createDeleteForm($id);

return $this->render('FooBarBundle:CampaignEntity:edit.html.twig', array(
        'entity'      => $entity,
        'edit_form'   => $editForm->createView(),
        'delete_form' => $deleteForm->createView(),
    ));

The campaign entity type class (src: Foo\BarBundle\Form\CampaignEntityType.php):

namespace Foo\BarBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Doctrine\ORM\EntityRepository;

class CampaignEntityType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
        ->add('store', 'entity', array('class'=>'FooBarBundle:Store', 'property'=>'name', 'em'=>'my_non_default_em','required'  => true, 'query_builder' => function(EntityRepository $er) {return $er->createQueryBuilder('s')->orderBy('s.name', 'ASC');}))
        ->add('reward');
    }
    public function getName()
    {
        return 'foo_barbundle_campaignentitytype';
    }
}
Chris
  • 754
  • 9
  • 16
  • I think I may be building the forms incorrectly, thank you so much for your example, I will give this a go and let you know how it goes! – Matt G Nov 18 '11 at 05:37
  • Hi Chris, I'm a little confused how you seem to create two forms inside the one view, would it be possible for you to post an example of the twig template and how you address the two forms inside your twig template? – Matt G Nov 23 '11 at 00:47
  • Sorry for the delay in response... didn't see your comment :( For the edit/delete form here is what I have in my twig `
    {{ form_widget(edit_form) }}

    {{ form_widget(delete_form) }}
    `
    – Chris Nov 29 '11 at 23:07
  • and here is the createDeleteForm function as well `private function createDeleteForm($id) { return $this->createFormBuilder(array('id' => $id)) ->add('id', 'hidden') ->getForm() ; }` – Chris Nov 29 '11 at 23:11
1

The form should map the species->id value automatically to the selected entity select field. For example if your have a Breed entity that has a OnetoOne relationship with a Species entity in a join table called 'breed_species':

class Breed{

    private $species;

    /**
    * @ORM\OneToOne(targetEntity="BreedSpecies", mappedBy="breed")
    */
    private $breedSpecies;

    public function getSpecies(){
       return $breedSpecies->getSpecies();
    }

    private function getBreedSpecies(){
       return $this->$breedSpecies;
    }
}

The field 'species' in the form class should pick up the species->id value from the 'species' attribute object in the Breed class passed to the form.

Alternatively, you can explicitly set the value by explicitly passing the species entity into the form using SetData():

    $breedForm = $this->createForm( new BreedForm(), $breed );
    $species   = $breed->getBreedSpecies()->getSpecies();

    $breedForm->get('species')->setData( $species );

    return $this->render( 'AcmeBundle:Computer:edit.html.twig'
                        , array( 'breed'     => $breed
                               , 'breedForm' => $breedForm->createView()
            )
    );
Onshop
  • 2,915
  • 1
  • 27
  • 17
0

You can either define the right default value into the model you want to edit with this form or you can specify an empty_data option so your code become:

$form = $this
    ->createFormBuilder($breed)
    ->add(
        'species',
        'entity',
        array(
            'class'         => 'BFPEduBundle:Item',
            'property'      => 'name',
            'empty_data'    => 123,
            'query_builder' => function(ItemRepository $er) {
                return $er
                    ->createQueryBuilder('i')
                    ->where("i.type = 'species'")
                    ->orderBy('i.name', 'ASC')
                ;
            }
        )
    )
    ->add('breed', 'text', array('required'=>true))
    ->add('size', 'textarea', array('required' => false))
    ->getForm()
;
Herzult
  • 3,429
  • 22
  • 15
-1

You can use "preferred_choices" and "push" the name you want to select to the top of the list. Then it will be selected by default.

'preferred_choices' => array(1), //1 is item number

entity Field Type

repincln
  • 2,029
  • 5
  • 24
  • 34
  • 4
    using the preferred_choices property does push the name to the top of the list but it isn't then selected by default. Because I have a default value set in the TWIG template like so: {{ form_widget(form.species, { 'empty_value': 'Please select...'}) }} the 'Please Select...' value is selected by default and if you click the listbox the 'preferred_choice' item is then the first selection available under that – Matt G Nov 18 '11 at 05:26
  • Yes, this might be nice to know, but it doesn't seem like an answer to what was asked. – Jason Swett Mar 29 '12 at 15:42