Buy

Form: Default Data

Now, what if we wanted some default data to appear on the form? Well, we can just pass the data as the first argument to createFormBuilder:

// src/Yoda/UserBundle/Controller/RegisterController.php
// ...

public function registerAction(Request $request)
{
    $defaultData = array(
        'username' => 'Leia',
    );

    $form = $this->createFormBuilder($defaultData)
        // ...
        ->getForm()
    ;

    // ...
}

Refresh and check that out.

Having the Form to a User object: The data_class Option

When we submit, $form->getData() gives us an associative array. That’s cool, but what if it actually built the User object for us? Remove the default data we just added and pass a second argument to createFormBuilder. This is an array of options for the form and we’ll pass it a data_class key that’s set to our User class:

// src/Yoda/UserBundle/Controller/RegisterController.php
// ...

public function registerAction(Request $request)
{
    $form = $this->createFormBuilder(null, array(
        'data_class' => 'Yoda\UserBundle\Entity\User',
    ))
        // ...
        ->getForm()
    ;

    // ...
}

Let’s dump the form values again and try it:

// src/Yoda/UserBundle/Controller/RegisterController.php
// ...

if ($form->isValid()) {
    $data = $form->getData();
    var_dump($data);die;

    // all the User saving code from before ...
}

Cool! Instead of an associative array, we get back a full User object populated with the form data. Behind the scenes, the form creates a new User object and then calls setUsername, setEmail and setPassword on it, passing each the value from the form.

Now, We can simplify things on our controller:

// inside registerAction()
if ($form->isValid()) {
    $user = $form->getData();

    $user->setPassword(
        $this->encodePassword($user, $user->getPassword())
    );

    $em = $this->getDoctrine()->getManager();
    // save the user and redirect just as before
}

Default Data with an Object

So how can we set default data on the form now? Put back the array we had earlier:

$defaultData = array(
    'username' => 'Leia',
);

$form = $this->createFormBuilder($defaultData, array(
    'data_class' => 'Yoda\UserBundle\Entity\User',
))
    // ...
    ->getForm()
;

Refresh and look at the error message closely:

The form's view data is expected to be an instance of class
Yoda\UserBundle\Entity\User, but is a(n) array. You can avoid
this error by setting the "data_class" option to null or by adding
a view transformer that transforms a(n) array to an instance
of Yoda\UserBundle\Entity\User.

It’s telling us that we gave the form an array but it was expecting a User object. The data_class option tells the form that both the output and the input of the form should be a User. So to set default data, just create a User object, give it some data and pass it in:

$user = new User();
$user->setUsername('Leia');

$form = $this->createFormBuilder($user, array(
    'data_class' => 'Yoda\UserBundle\Entity\User',
))
    // ...
    ->getForm()
;

Refresh now! It looks great!

Leave a comment!

  • 2016-04-26 Diego Aguiar

    Thank you very much for your answer

    I'm totally agree, option A and B doesn't worth it, it is like reinventing the wheel, but worse.
    Option C is not bad at all, if I add a method to the repository, but as you said, it's premature optimizing

    Thanks again bro, have a good day.

  • 2016-04-26 weaverryan

    Yo Diego!

    Hmm, I don't think that you can: the second query (for the options) is completely unaware of the underlying data in your form (the main entity). Plus, it definitely needs to make the independent query for a "new" action. Now, technically, you *can* avoid the second query if you *really* wanted to, but I think you're probably over-optimizing. You would:

    A) In buildForm, get the main entity via $options['data'] (but check to see if this is your object - it will be either null or an unsaved object in "new" mode depending on your setup)
    B) If $options['data'] is your persisted main entity, then add a choices key to your EntityType field that is an array of the related objects you want in your list (e.g. $genus->getNotes() to follow with the relationship we use in the new Symfony 3 course)).

    At this point, you're basically manually creating the list of choices, instead of letting the EntityType do it for you. Your form should render, but it'll still have that extra query. Finally:

    C) Add a join to the related entity when you query for the main entity, so that $genus->getNotes() doesn't require the extra query: https://knpuniversity.com/scre...

    That *technically* answers your question... but it's not worth it for me :).

    Cheers!

  • 2016-04-25 Diego Aguiar

    Hey Ryan,

    I've a question about formtypes, I have a form builder for an entity with a relationship to other entity, when I create an Edit Action I found that doctrine is making 2 queries, in order to create the select option with the current entity selected
    The first one to get the data of the related entity
    and the second for the list of records on the Database (In order to show the list of options for that entity)

    I'm wondering what can I do to reduce that to only 1 query

    Thanks in advance

  • 2015-07-01 weaverryan

    Hi Shairyar!

    Hmm, I'm not sure about this. What version of Symfony? Some things in this area changed in 2.7.

    But strictly speaking, if the `interview` property on the `Offer` object that you're passing into the form has a value of "Yes" or "No" exactly (i.e. you have this string stored in the database), then it should auto-select. But if you're storing something more like a 1/0 in the database, then this will *not* work - as the form can't figure out which option to show for 1/0.

    Cheers!

  • 2015-07-01 Shairyar Baig

    I have a dropdown (choice) field on a form that is linked with an Entity and I am able to save the data just fine in database, the problem I am having is when i open the form to edit the details, all form fields are pre-filled with correct information except the dropdown field that is linked with the Entity

    This is what my form class looks like and the dropdown (choice) field i am referring to is called 'project'




    add('interview', 'choice', array('choices' => array(
    'Yes'=> 'Yes',
    'No' => 'No'),
    'placeholder' => 'Interview Outcome'))
    ->add('place', 'choice', array('choices' => array(
    'Yes'=> 'Yes',
    'No' => 'No'),
    'placeholder' => 'Offer Outcome'))
    ->add('project', 'entity', array(
    'class' => 'AdminBundle:Programs',
    'property' => 'name',
    'placeholder' => 'Assigned Program'
    ));
    }

    /**
    * @param OptionsResolverInterface $resolver
    */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    $resolver->setDefaults(array(
    'data_class' => 'ProjectEverest\AdminBundle\Entity\Offer'
    ));
    }

    /**
    * @return string
    */
    public function getName()
    {
    return 'projecteverest_adminbundle_offer';
    }
    }


    What can i do to make the dropdown show the value saved in database selected by default when editing information.

  • 2014-12-18 Guest

    thanks,
    My error was thinking that

    When we define a data_class like this..
    $form = $this->createFormBuilder(null, array(
    'data_class' => 'Yoda\UserBundle\Entity\User',
    ))->getForm();
    we don't need to add the elements...

    but we still need to define the elements with "->add(email... ) " .

    Symfony could detect them automatically.. .

    Thanks for ur time a your great tutos

  • 2014-12-14 weaverryan

    Hey Marco!

    Hmm, that should still work just fine. The first argument to createFormBuilder is the data, and passing null data is totally fine. The second argument is an array of options, and the data_class option tells the form we want a User object. You're totally right to point out that this can be done exactly the same with an external form class - but this should also work.

    So if you're seeing issues, let me know what the error is!

    Cheers!

  • 2014-12-13 Guest

    This syntax

    $form = $this->createFormBuilder(null, array(
    'data_class' => 'Yoda\UserBundle\Entity\User',
    )) isn't not working with the last version of symfony..

    Go directly to the " Form Type Class Chapter.."