User Dependent Forms in Symfony2

In a lot of cases it can happen that you want to make your forms different based on the user currently browsing your app.

The cookbook currently shows how to change a form with event subscribers depending on the data in that form. Say creating a record rather than updating something could require a different form for example.

Here we’re gonna take a look at what happens when your form should be customized based on something that is not readily available in the form’s data. Such as the user data.

In many cases though I’d tell you it’s better to not have to do that. There’s a lot of UI ways to make things so you never need the form to hold user specific data. Like letting a user browse to the thing she’s trying to update rather than have a huge select box inside of the form. But if you need something like that, here’s a clean way to do it!

What’s wrong with the cookbook?

The cookbook article on dynamically generating forms currently shows an example like this:

FormType.php hosted with ❤ by GitHub

It doesn’t really matter for now what the subscriber actually does. The important thing is that we create a subscriber class and add it to the form. Then, when some specific form event is triggered, the subscriber will be allowed to perform some actions on the form.

The issue is that we created the subscriber inside of the form class. So doing like this, it’s impossible to get access to the user, or to your database, or to whatever else you could think of. Everything else works wonders here, just how to access some other services???

This is gonna sound boring

Because like all the time in Symfony2, the answer is gonna be:

Dependency Injection, you guessed it!

Form types can (and will) be defined as services. And our subscriber can, and will also be defined as a service!

Our form type only changes in that we add a constructor that takes our event subscriber as a parameter. Let’s say we want a form to send a message and the user should only be able to send messages to her friends and not any user on the website:

Now let’s take a look at our subscriber:

So before the data is set in the form we:

  1. Create our form options for a ‘document’ type field (or ‘entity’ when using an SQL database)
  2. Set the query builder option (this is the interesting part)
  3. Add a ‘document’ field with these options to our form under the name ‘friend’

The query builder part is the interesting one because it takes the user id as a parameter. This wouldn’t be available in the form otherwise.

Also take a look at the constructor. It takes the security context as a parameter (as this will allow us to retrieve the current user), which is not available in the form, so we couldn’t directly create this object from within the form like is done in the first example of this article. We need to define services for these two now. And quite simply, in your config.yml, all you need is to add:

The form takes the subscriber as a parameter, and the subscriber will be instantiated with the form factory and the security context.

Tying it all together in the controller

There you go. Your forms can now be customized on any service / data even outside of the form itself.