Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Lucky you! You found an early release chapter - it will be fully polished and published shortly!

Form Improvements for Symfony 6

This Chapter isn't
quite ready...

Rest assured, the gnomes are hard at work
completing this video!

Browse Tutorials

Let's explore some new features! There are tons of them, and we've already seen a bunch. I don't have time to show everything but fortunately, I don't need to! If you go to https://symfony.com/blog, the new stuff is really well-documented. Click on "Living on the Edge". Here, you can see blog posts that are categorized by each version. This is a collection of blog posts about what's new in Symfony 5.1, like the new security system. And... here are posts about what's new in Symfony 5.3, or 5.4 through 6.0. So if you want to go deeper and see all the new stuff, it's been beautifully documented in these posts.

The new features I want to show right now have to do with the form component.

Form Field Sorting

Since Symfony 5.3, we have a nice new feature called Form Field Sorting. If you go to the registration page, this renders four fields. Let's open the template for that: templates/registration/register.html.twig. I'm rendering all the fields by hand. Let's replace this with the very lazy {{ form_widget(registrationForm) }}... which just dumps out all of the fields in whatever order they're added.

Unfortunately... now the form... looks weird. To fix this, open the form type class for this, which is src/Form/RegistrationFormType.php. Every single field now has an option called priority. Let's add that.

Starting with firstName, pass null for the type so Symfony keeps guessing. Then, set priority to 4, because I want this to be the first field. email should be the second field, so pass null again and set its priority to 3. Then give plainPassword a priority of 2... and finally set agreeTerms to priority 1.

And now... it looks great! So if you want to lazily render your fields, you can do that... and not have to worry about them being in a strange order.

Hello renderForm()

While we're on the topic of forms, open up the controller for this page: src/Controller/RegistrationController.php. In Symfony 5.3, when you render a template and pass in a form, there's a new shortcut! Instead of render() say renderForm(). The only other difference is that you get to remove the ->createView() call.

That's it! this renderForm() method is just like render(). It still renders this template, and it still passes any of these variables into the template. But if any of the variables we're passing are a "form" object, it calls the createView() method for us... which is nice!

This also makes one other change, which isn't very noticeable. If you have a validation error, your controller will now return a response with its status code set to 422. But that won't look any different in your browser. If I submit a password that's too short, it all looks the same... though the status code is now 422.

Symfony made this change for two reasons. First... it's just technically more correct to have an error status code if there is a validation error. And second, if you're using Turbo, this is needed so that Turbo knows that your form validation failed. You get that for free just by using the new shortcut method.

Next, Symfony comes with some nice and optional Docker integration for local development. Some parts of this integration have recently changed. Let's see how we can use Docker to get a cool email catching system added to our app that will help us test emails.

Leave a comment!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": "^8.0.2",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.6", // v3.6.1
        "composer/package-versions-deprecated": "^1.11", //
        "doctrine/annotations": "^1.13", // 1.13.2
        "doctrine/dbal": "^3.3", // 3.3.5
        "doctrine/doctrine-bundle": "^2.0", // 2.6.2
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.0", // 2.11.2
        "knplabs/knp-markdown-bundle": "^1.8", // 1.10.0
        "knplabs/knp-time-bundle": "^1.18", // v1.18.0
        "pagerfanta/doctrine-orm-adapter": "^3.6", // v3.6.1
        "pagerfanta/twig": "^3.6", // v3.6.1
        "sensio/framework-extra-bundle": "^6.0", // v6.2.6
        "sentry/sentry-symfony": "^4.0", // 4.2.8
        "stof/doctrine-extensions-bundle": "^1.5", // v1.7.0
        "symfony/asset": "6.0.*", // v6.0.7
        "symfony/console": "6.0.*", // v6.0.7
        "symfony/dotenv": "6.0.*", // v6.0.5
        "symfony/flex": "^2.1", // v2.1.7
        "symfony/form": "6.0.*", // v6.0.7
        "symfony/framework-bundle": "6.0.*", // v6.0.7
        "symfony/mailer": "6.0.*", // v6.0.5
        "symfony/monolog-bundle": "^3.0", // v3.7.1
        "symfony/property-access": "6.0.*", // v6.0.7
        "symfony/property-info": "6.0.*", // v6.0.7
        "symfony/proxy-manager-bridge": "6.0.*", // v6.0.6
        "symfony/routing": "6.0.*", // v6.0.5
        "symfony/runtime": "6.0.*", // v6.0.7
        "symfony/security-bundle": "6.0.*", // v6.0.5
        "symfony/serializer": "6.0.*", // v6.0.7
        "symfony/stopwatch": "6.0.*", // v6.0.5
        "symfony/twig-bundle": "6.0.*", // v6.0.3
        "symfony/ux-chartjs": "^2.0", // v2.1.0
        "symfony/validator": "6.0.*", // v6.0.7
        "symfony/webpack-encore-bundle": "^1.7", // v1.14.0
        "symfony/yaml": "6.0.*", // v6.0.3
        "symfonycasts/verify-email-bundle": "^1.7", // v1.10.0
        "twig/extra-bundle": "^2.12|^3.0", // v3.3.8
        "twig/string-extra": "^3.3", // v3.3.5
        "twig/twig": "^2.12|^3.0" // v3.3.10
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.1
        "phpunit/phpunit": "^9.5", // 9.5.20
        "rector/rector": "^0.12.17", // 0.12.20
        "symfony/debug-bundle": "6.0.*", // v6.0.3
        "symfony/maker-bundle": "^1.15", // v1.38.0
        "symfony/var-dumper": "6.0.*", // v6.0.6
        "symfony/web-profiler-bundle": "6.0.*", // v6.0.6
        "zenstruck/foundry": "^1.16" // v1.18.0