Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Form: Default Data

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

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!

8
Login or Register to join the conversation

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

Reply

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/s...

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

Cheers!

Reply

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.

Reply
Default user avatar
Default user avatar Shairyar Baig | posted 4 years ago

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.

Reply

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!

Reply
Default user avatar

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.."

Reply

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!

Reply
Default user avatar

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

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.3.3",
        "symfony/symfony": "~2.4", // v2.4.2
        "doctrine/orm": "~2.2,>=2.2.3", // v2.4.2
        "doctrine/doctrine-bundle": "~1.2", // v1.2.0
        "twig/extensions": "~1.0", // v1.0.1
        "symfony/assetic-bundle": "~2.3", // v2.3.0
        "symfony/swiftmailer-bundle": "~2.3", // v2.3.5
        "symfony/monolog-bundle": "~2.4", // v2.5.0
        "sensio/distribution-bundle": "~2.3", // v2.3.4
        "sensio/framework-extra-bundle": "~3.0", // v3.0.0
        "sensio/generator-bundle": "~2.3", // v2.3.4
        "incenteev/composer-parameter-handler": "~2.0", // v2.1.0
        "doctrine/doctrine-fixtures-bundle": "~2.2.0", // v2.2.0
        "ircmaxell/password-compat": "~1.0.3", // 1.0.3
        "phpunit/phpunit": "~4.1" // 4.1.0
    }
}