This course is archived!
Customizing the Forms
What if we wanted to add our own fields to the registration form? Like, what if we needed to add a "First Name" field? No problem!
Adding a firstName field to User
Start in our User
class. This is a normal entity... so we can add whatever fields we want, like private $firstName
. I'll go to Code->Generate, or Command+N on a Mac, then select "ORM Annoations" to annotate firstName
. Then I'll go back to Code->Generate to add the getter and setter methods.
// ... lines 2 - 11 | |
class User extends BaseUser | |
{ | |
// ... lines 14 - 20 | |
/** | |
* @ORM\Column(type="string") | |
*/ | |
private $firstName; | |
// ... lines 25 - 30 | |
public function getFirstName() | |
{ | |
return $this->firstName; | |
} | |
public function setFirstName($firstName) | |
{ | |
$this->firstName = $firstName; | |
} | |
} |
Notice, right now, firstName
is not nullable... meaning it's required in the database... and that's fine! If firstName
is optional in your app, you can of course add nullable=true
. I'm mentioning this for one reason: if you add any required fields to your User
, the fos:user:create
command will no longer work... because it will create a new User
but leave those fields blank. I never use that command in production anyways, but, you've been warned!
Move over to your terminal to generate the migration:
php bin/console doctrine:migrations:diff
That looks right! Run it:
php bin/console doctrine:migrations:migrate
New field added! Now, how can we add it to the form? Simple! We can create our own new form class and tell FOSUserBundle to use it instead.
Creating the Override Form
In src/AppBundle
, create a new Form
directory and a new class called RegistrationFormType
. Extend the normal AbstractType
. Then, I'll use Code->Generate Menu or Command+N to override the buildForm()
method. Inside, just say $builder->add('firstName')
.
// ... line 2 | |
namespace AppBundle\Form; | |
// ... lines 4 - 8 | |
class RegistrationFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
->add('firstName'); | |
} | |
// ... lines 16 - 20 | |
} |
In a minute, we'll tell FOSUserBundle to use this form instead of its normal registration form. But... instead of completely replacing the default form, what I really want to do is just add one field to it. Is there a way to extend the existing form?
Extending the Core Form
Totally! And once again, the web debug toolbar can help us out. Mouse over the form icon and click that. This tells us what form is used on this page: it's called RegistrationFormType
- the same as our form class!
To build on top of that form, you don't actually extend it. Instead, override a method called getParent()
. Inside, we'll return the class that we want to extend. At the top, add use
, autocomplete RegistrationFormType
from the bundle and put as BaseRegistrationFormType
to avoid conflicting.
Now in getParent()
, we can say return BaseRegistrationFormType::class
.
// ... lines 2 - 6 | |
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseRegistrationFormType; | |
// ... line 8 | |
class RegistrationFormType extends AbstractType | |
{ | |
// ... lines 11 - 16 | |
public function getParent() | |
{ | |
return BaseRegistrationFormType::class; | |
} | |
} |
And that is it! This form will have the existing fields plus firstName
.
Registering the Form with FOSUserBundle
To tell FOSUserBundle about our form, we need to do two things. First, register this as a service. In my app/config/services.yml
, add app.form.registration
with class
set to the RegistrationFormType
. It also needs to be tagged with name: form.type
.
// ... lines 1 - 5 | |
services: | |
// ... lines 7 - 17 | |
app.form.registration: | |
class: AppBundle\Form\RegistrationFormType | |
tags: | |
- { name: form.type } |
Finally, copy the class name and go into app/config/config.yml
. This bundle has a lot of configuration. And at the bottom of the documentation page, you can find a reference called FOSUserBundle Configuration Reference
. I'll open it in a new tab.
This is pretty awesome: a full dump of all of the configuration options. Some of these are explained in more detail in other places in the docs, but I love seeing everything right in front of me. And we can see what we're looking for under registration.form.type
.
Go back to your editor and add those: registration
, form
and type
. Paste our class name!
// ... lines 1 - 74 | |
fos_user: | |
// ... lines 76 - 81 | |
registration: | |
form: | |
type: AppBundle\Form\RegistrationFormType |
And... we're done! Go back to registration and refresh. We got it! And that will save when we submit.
Customizing the Form Order
Why is firstName
at the bottom? Well, remember inside of register_content.html.twig
, we're using form_widget(form)
... which just dumps out the fields in whatever order they were added. Need more control? Cool: remove that and instead use form_row(form.email)
, form_row(form.username)
, form_row(form.firstName)
and form_row(form.plainPassword)
.
// ... lines 1 - 2 | |
<h1>Register Aquanaut!</h1> | |
// ... line 4 | |
{{ form_start(form, {'method': 'post', 'action': path('fos_user_registration_register'), 'attr': {'class': 'fos_user_registration_register'}}) }} | |
{{ form_row(form.email) }} | |
{{ form_row(form.username) }} | |
{{ form_row(form.firstName) }} | |
{{ form_row(form.plainPassword) }} | |
// ... lines 10 - 12 | |
{{ form_end(form) }} |
If you're not sure what the field names are called, again, use your web debug toolbar for the form: it shows you everything.
Refresh that page! Yes! First Name is exactly where we want it to be. Next, what about the username? Could we remove that if our app only needs an email?
Hello I have one question here. Can I add and how can I add custom function to form in customType class.
My goal: I would like to be able to do something like
$myForm->myCustomFunction()
I have tried to add it directly in customType class but when I try to use it in controller like I did above I get not existing method name error. Is that possible?
Regards,
Rob