Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Forms

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Tip

This screencast shows the old, 2.7 and earlier form syntax. But, the code blocks below have been updated to show the new syntax!

Now that we've got our entity let's create a form! Click on AppBundle, press our handy shortcut command+n, and if you search form you'll find that option in the menu! It's all coming together!

We'll call this MovieType:

<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class MovieType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
}
public function configureOptions(OptionsResolver $resolver)
{
}
}

Notice it was actually smart enough to put that inside of a Form directory and build out the whole structure that we'll need. All I need next is for it to pour me a cup of coffee.

The first thing we always do inside of here is call $resolver->setDefaults(array()) and pass the data_class option so that it binds it to our Movie entity. Conveniently, this gives us more autocomplete: we can just type Movie and it adds the rest:

... lines 1 - 8
class MovieType extends AbstractType
{
... lines 11 - 15
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Movie'
));
}
}

Configuring Form Fields

This will even help us build our fields. If we type $builder->add('') here, because this is bound to our Movie entity, it knows all the properties we have there. So let's plug in our property of title which should be a text field, samsCharacterName which is probably a text field as well and isMainCharacter which will be a checkbox. We'll want to make sure that we prevent html5 validation on that. A third argument of 'required' => false will take care of that for us and even that has autocomplete. It's madness!

... lines 1 - 5
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
... lines 7 - 8
use Symfony\Component\Form\Extension\Core\Type\TextType;
... lines 10 - 12
class MovieType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title', TextType::class)
->add('samsCharacterName', TextType::class)
->add('isMainCharacter', CheckboxType::class, array(
'required' => false,
))
... lines 22 - 25
}
... lines 27 - 33
}

Let's also include rating as an integer field and lastly, releasedAt which is a date field:

... lines 1 - 6
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
... lines 10 - 12
class MovieType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title', TextType::class)
... lines 18 - 21
->add('rating', IntegerType::class)
->add('releasedAt', DateType::class, array(
... line 24
));
}
... lines 27 - 33
}

Digging into Options and Fields

We can control how this date field renders: by default with Symfony it would be 3 select boxes. I'll set a widget option, except I don't remember what value to set that to. No worries, I'll just hold the command key over the widget option and it will take me straight to where that is setup inside of the core code:

... lines 1 - 11
namespace Symfony\Component\Form\Extension\Core\Type;
... lines 13 - 26
class DateType extends AbstractType
{
const DEFAULT_FORMAT = \IntlDateFormatter::MEDIUM;
... lines 30 - 167
public function configureOptions(OptionsResolver $resolver)
{
... lines 170 - 202
$resolver->setDefaults(array(
... lines 204 - 206
'widget' => 'choice',
... lines 208 - 224
));
... lines 226 - 235
$resolver->setAllowedValues('widget', array(
'single_text',
'text',
'choice',
));
... lines 241 - 245
}
... lines 247 - 321
}

Why is that awesome you ask? Because I can search for what I need inside of here and boom setAllowedValues single_text, text and choice. So let's paste single_text back into our file.

... lines 1 - 6
use Symfony\Component\Form\Extension\Core\Type\DateType;
... line 8
use Symfony\Component\Form\Extension\Core\Type\TextType;
... lines 10 - 12
class MovieType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title', TextType::class)
... lines 18 - 22
->add('releasedAt', DateType::class, array(
'widget' => 'single_text'
));
}
... lines 27 - 33
}

That trick of holding command and clicking works for the field types too: command+click integer and suddenly you're inside the class that provides this!

... lines 1 - 11
namespace Symfony\Component\Form\Extension\Core\Type;
... lines 13 - 19
class IntegerType extends AbstractType
{
... lines 22 - 37
public function configureOptions(OptionsResolver $resolver)
{
... lines 40 - 47
$resolver->setDefaults(array(
// deprecated as of Symfony 2.7, to be removed in Symfony 3.0.
'precision' => null,
// default scale is locale specific (usually around 3)
'scale' => $scale,
'grouping' => false,
// Integer cast rounds towards 0, so do the same when displaying fractions
'rounding_mode' => IntegerToLocalizedStringTransformer::ROUND_DOWN,
'compound' => false,
));
... lines 58 - 69
}
... lines 71 - 78
}

It's like being teleported but, you know, without any risk to your atoms. You can even use this to take you to the property inside of Movie for that specific field.

Form Rendering

Our form is setup so let's go ahead and create this inside of our controller, $form = $this->createForm(new MovieType(), $movie);. Like always, we need to pass our form back into our template with $form->createView():

... lines 1 - 5
use AppBundle\Form\MovieType;
... lines 7 - 10
class MovieController extends Controller
{
... lines 13 - 15
public function newAction()
{
$movie = new Movie();
$form = $this->createForm(MovieType::class, $movie);
return $this->render('movie/new.html.twig', array(
'quote' => 'If my answers frighten you then you should cease asking scary questions. (Pulp Fiction)',
'form' => $form->createView()
));
}
... lines 27 - 34
}

Time to render this! Click into the new.html.twig template, ah that's right my form is actually going to be over here in _form.html.twig. It shouldn't surprise you that you'll get autocomplete here on things like form_start and form_end:

{{ form_start(form) }}
... lines 2 - 8
{{ form_end(form) }}

Want more autocomplete awesomeness you say? You're mad! But ok: type {{ form_row(form) }} and it'll auto-complete the title field for you. So we'll plug in all of our fields here:

{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.samsCharacterName) }}
{{ form_row(form.isMainCharacter) }}
... lines 5 - 8
{{ form_end(form) }}

And if I forget one of them, I can hit control+space to bring up all of my options. This will also show you some other methods that exist on that FormView object. Ah ok so we still have rating and releasedAt to add here. Clean up a bit of indentation here and perfect!

{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.samsCharacterName) }}
{{ form_row(form.isMainCharacter) }}
{{ form_row(form.rating) }}
{{ form_row(form.releasedAt) }}
<button type="submit" class="btn btn-primary">Save</button>
{{ form_end(form) }}

Time to try this out: back to our new movies page, refresh and there we go! It renders with no problems other than the fact that this is a form only it's developer could love. And well, maybe not even that: I'm going to make it prettier. In config.yml, down in the twig key add form_themes:

... lines 1 - 34
twig:
... lines 36 - 37
form_themes:
... lines 39 - 83

Now this should autocomplete, but for whatever reason this one key is not doing that. But for the most part, you will see autocompletion inside of your configuration files.

Form Theming

Right here let's plug in the bootstrap form theme: and the plugin isn't perfect because we don't get autocomplete on this either. But I do know that there is a file inside the project for bootstrap, so I'll go to find, file and start typing in bootstrap. We want the one called bootstrap_3_layout.html.twig. To cheat, I'll just copy that file name and paste that in here:

... lines 1 - 34
twig:
... lines 36 - 37
form_themes:
- bootstrap_3_layout.html.twig
... lines 40 - 83

Refresh with our new form theme and .... Awesome!

Leave a comment!

26
Login or Register to join the conversation
Default user avatar
Default user avatar Andrew Grudin | posted 5 years ago

I found the issue.

WAS OK BEFORE(sf 2.8):
$builder->add('title', 'text')
->add('samsCharacterName', 'text')
->add('isMainCharacter', 'checkbox', array(
'required' => false
))
->add('rating', 'integer')
->add('releasedAt', 'date', array(
'widget' => 'single_text',
));

SHOULD BE (from sf 2.8):

use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
$builder->add('title', TextType::class)
->add('samsCharacterName', TextType::class)
->add('isMainCharacter', CheckboxType::class, array(
'required' => false
))
->add('rating', IntegerType::class)
->add('releasedAt', DateType::class , array(
'widget' => 'single_text',
));

3 Reply
Default user avatar
Default user avatar Andrew Grudin | posted 5 years ago

When I tried to reload my new form I got exeption:
Expected argument of type "string", "AppBundle\Form\MovieType" given
I have changed :
$form = $this->createForm(new MovieType(), $movie);
for:
$form = $this->createForm(MovieType::class, $movie);
Got new:
Could not load type "text"
500 Internal Server Error - InvalidArgumentException
Your comments suggestions would be greatly appreciated

1 Reply

Hey Andrew!

You've already got the right fix actually! This tutorial was on Symfony 2, where we did things like "new MovieType" and ->add('someField', 'text'). In Symfony 3, change it to MovieType::class (you already did this) *and* make a similar change in your form class - e.g. ->add('someField', TextType::class); That'll fix things :).

Cheers!

1 Reply

I literally wrote this and then saw you solved the issue yourself :). Thanks for posting the detailed update! https://knpuniversity.com/s...

Reply
Graymath technology Avatar
Graymath technology Avatar Graymath technology | posted 3 years ago

Does this still work. I am using Ubuntu 20.04 with latest version of PhpStorm with Symfony5 and I initiated the project with the full option
symfony new --full my_project.

I don't see any of the options in the new menu. Just one option for symfony service and when click on that nothing happens as well. I uninstalled and re-installed the symfony support plugin and enabled it as well for the project.

Reply

Hey Graymath technology

I believe Symfony plugin people dropped that feature because I can't do it either but the good news is you don't need it anymore, you can generate any boiler plate file by using the MakerBundle. It's a super handy bundle that you should give it a try https://symfony.com/doc/cur...

Cheers!

Reply
Default user avatar
Default user avatar Andrew Grudin | posted 5 years ago

I did all as you do, but when my form is rendered the field 'Released at' does not display

'mm/dd/yyyy' inside , just empty. Could you give me, please, any hint how to fix it.

Reply

Hey Andrew!

You're probably doing it correctly :). Symfony renders this fields as an input type="date" field. *Some* browsers (like mine - Chrome) are smart enough to turn that into a "smart" field - that's what you're seeing. I (and Symfony) did *not* add that mm/dd/yyyy - my browser is adding that because it knows this is a date field. If you try Chrome, you will likely see that same behavior. But even if you don't, you can just fill in the field with something like 06/20/2000 and it will submit. If you'd like to have a fancy date picker in *all* browsers, you should use a JavaScript library to help the user fill in the right date (e.g. 06/20/2000).

Cheers!

Reply
Default user avatar
Default user avatar Andrew Grudin | weaverryan | posted 5 years ago

Probably my Google Chrome is silly and don't displayt mm/dd/yyyy either.
From your point of view , is Chrome more advanced for web development now then Fox?
Best regards!

Reply

Ah, so strange! I mostly prefer Chrome because I like its native web inspector better! I *do* (for whatever reason) see it used by most developers, probably with Safari second.

Reply
Default user avatar
Default user avatar fabienne | posted 5 years ago

Hello, first thanks to Andrew for the solution with the 500 error, I had the same problem.

I have another question, I have bootstrap under web/vendors/bootstrap, but the code has no effect. Inspect shows that the bootstrap classes are there, but the page looks the same as before, is it a path problem?
thanks.

Reply
Default user avatar
Default user avatar fabienne | posted 5 years ago

Me again and sorry! Of course I needed to add the reference to the css in base.html.twig....

Reply
Default user avatar
Default user avatar Raphael Schubert | posted 5 years ago

Hello there!!! i`m in love with Symfony and KNPU... I have a question... There is a way to render the fields of FORM in columns? like [ 'class'=>'col-md-3' ]??? I`m not founding where to change the variables... thanks!!!

Reply

Hi Raphael!

Ah, thank you so much!!!! I'm glad you love both things :p.

I might have an easy answer to your question: have you tried the bootstrap_3_horizontal_layout.html.twig form theme? It organizes labels and fields into columns: https://github.com/symfony/...

You can configure to use this form theme in the same way as the other bootstrap form theme.

Cheers!

Reply
Richard Avatar
Richard Avatar Richard | posted 5 years ago

Help! I'm not getting completion on the add type fields. eg in $builder->add('title','text') "text" is not completing. What is missing? So much going on so quickly I'm not sure what I might have missed. I tab completed the add call so assume all the right "usages" are in. But all I have are:

namespace AppBundle\Form;

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

Reply
Richard Avatar

OK. the code below doesn't match the video. The correct syntax for 3.2 is : $builder->add('title',TextType::class) which is in the code forms but not in the video. Or am I going doolally? ;)

Reply

Yo Richard ,

Yes, you're right, code blocks related to the Symfony forms mismatch the video. We updated code blocks to use the new Symfony 3 syntax, but not the video. Btw, we have a note about it at the beginning of this article: https://knpuniversity.com/s... ;)

Cheers!

Reply

Hey Richard ,

If you're on Symfony 3 - you should use `TextType::class` as you figured out below by yourself. The 'text' way is deprecated and doesn't work since Symfony 3.

Cheers!

Reply
Default user avatar
Default user avatar Cédric Gournay | posted 5 years ago | edited

The same exception was thrown when I tried to reload the form page (expected argument of type string ...).
I finally found a solution to fix it.

I REPLACED >> "$form = $this->createForm(new MovieType(), $movie);"
BY >> "form = $this->get('form.factory')->create(MovieType::class, $movie);"

I also used fully-qualified class name in the buildForm function (as described by there ) .

Reply

Yep, you guys are absolutely right - the "new MovieType" was one of the changes that was deprecated in 2.x and removed for Symfony 3.x (replaced with the MoveType::class form). That's the key change to make :).

Reply
Default user avatar
Default user avatar Paulius | posted 5 years ago

I'm using PHPStorm on Ubuntu OS.

When I'm trying to create new Form or Controller nothing happens when I click on 'New->Form' or 'New->Controller'

Reply

Hey Paulius!

So, you have the New->Form and New->Controller options, but they don't do anything when you click them? Or are the options missing? If clicking them does nothing, that sounds like some sort of a bug with the Symfony plugin.

Reply
Default user avatar

Yes, I have the options but they do nothing :(

Reply

Hmm, I've never seen that before, unfortunately :(. You could try re-installing the plugin/phpstorm - it's the best advice I can give!

Reply
Default user avatar
Default user avatar Andrew Grudin | posted 5 years ago

I have PHPstorm on my windows7 and symfony 3.
When I try (Ctrl + click) over 'widget' I do not get to Core/Type/DateType.php as you do but see "Can't find declaration to go to".
All the same for 'integer'. What can it be?

-1 Reply

Hi Andrew!

Do you have the Symfony plugin installed and (more importantly) enabled for this project? That's the most likely cause - let me know! *Sometimes* things won't work, even when you have the plugin installed+enabled, but I don't have problems with forms usually.

Cheers!

Reply
Cat in space

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

This is an older tutorial using an older version of PhpStorm. However, most of the tricks we show in PhpStorm still work beautifully.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.3.9, <7.3.0",
        "symfony/symfony": "2.8.*", // v2.8.15
        "doctrine/orm": "^2.4.8", // v2.4.8
        "doctrine/dbal": "<2.5", // v2.4.5
        "doctrine/doctrine-bundle": "~1.4", // 1.6.4
        "symfony/assetic-bundle": "~2.3", // v2.8.1
        "symfony/swiftmailer-bundle": "~2.3,>=2.3.10", // v2.4.2
        "symfony/monolog-bundle": "^3.0.2", // v3.0.2
        "sensio/distribution-bundle": "~5.0", // v5.0.17
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.18
        "incenteev/composer-parameter-handler": "~2.0" // v2.1.2
    },
    "require-dev": {
        "sensio/generator-bundle": "~3.0", // v3.1.2
        "symfony/phpunit-bridge": "~2.7" // v2.8.15
    }
}
userVoice