If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeLet'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.
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.
... lines 1 - 4 | |
{% block body %} | |
... lines 6 - 10 | |
{{ form_start(registrationForm) }} | |
{{ form_widget(registrationForm) }} | |
... line 13 | |
{{ form_end(registrationForm) }} | |
... lines 15 - 17 | |
{% endblock %} |
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
.
... lines 1 - 16 | |
public function buildForm(FormBuilderInterface $builder, array $options): void | |
{ | |
$builder | |
->add('email', null, [ | |
'priority' => 3, | |
]) | |
->add('agreeTerms', CheckboxType::class, [ | |
'priority' => 1, | |
... lines 25 - 30 | |
]) | |
->add('firstName', null, [ | |
'priority' => 4, | |
]) | |
->add('plainPassword', PasswordType::class, [ | |
'priority' => 2, | |
... lines 37 - 52 | |
]) | |
; | |
} | |
... lines 56 - 62 | |
} |
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.
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.
... lines 1 - 16 | |
class RegistrationController extends AbstractController | |
{ | |
... line 19 | |
public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, VerifyEmailHelperInterface $verifyEmailHelper, EntityManagerInterface $entityManager): Response | |
{ | |
... lines 22 - 53 | |
return $this->renderForm('registration/register.html.twig', [ | |
'registrationForm' => $form, | |
]); | |
} | |
... lines 58 - 88 | |
} |
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.
"Houston: no signs of life"
Start the conversation!
// 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", // 1.11.99.5
"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
}
}