Creating a Registration Form

Some forms have extra fields whose values don't need to be stored in the database. In this example, we'll create a registration form with such field ("terms accepted" checkbox field) and embed the form that actually stores the account information. We'll use MongoDB for storing the data.

The User Model

We begin this tutorial with the model for a User document:

1// src/Document/User.php namespace App\Document; use Doctrine\Bundle\MongoDBBundle\Validator\Constraints\Unique as MongoDBUnique; use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; use Symfony\Component\Validator\Constraints as Assert; #[MongoDB\Document(collection: 'users')] #[MongoDB\Unique(fields: 'email')] class User { /** * @MongoDB\Id */ #[MongoDB\Id] protected string $id; #[MongoDB\Field(type: 'string')] #[Assert\NotBlank] #[Assert\Email] protected ?string $email = null; #[MongoDB\Field(type: 'string')] #[Assert\NotBlank] protected ?string $password = null; public function getId(): string { return $this->id; } public function getEmail(): ?string { return $this->email; } public function setEmail(?string $email): void { $this->email = $email; } public function getPassword(): ?string { return $this->password; } // stupid simple encryption (please don't copy it!) public function setPassword(?string $password): void { $this->password = sha1($password); } }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

This User document contains three fields and two of them (email and password) should be displayed in the form. The email property must be unique in the database, so we've added this validation at the top of the class.

If you want to integrate this User within the security system, you need to implement the UserInterface of the Security component.

Create a Form for the Model

Next, create the form for the User model:

1// src/Form/Type/UserType.php namespace App\Form\Type; use App\Document\User; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class UserType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('email', EmailType::class); $builder->add('password', RepeatedType::class, [ 'first_name' => 'password', 'second_name' => 'confirm', 'type' => PasswordType::class ]); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => User::class, ]); } }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

We added two fields: email and password (repeated to confirm the entered password). The data_class option tells the form the name of the class that holds the underlying data (i.e. your User document).

To explore more things about the Form component, read its documentation.

Embedding the User form into a Registration Form

The form that you'll use for the registration page is not the same as the form used to modify the User (i.e. UserType). The registration form will contain further fields like "accept the terms", whose value won't be stored in the database.

In other words, create a second form for registration, which embeds the User form and adds the extra field needed:

1// src/Form/Model/Registration.php namespace App\Form\Model; use App\Document\User; use Symfony\Component\Validator\Constraints as Assert; class Registration { /** * @Assert\Type(type="App\Document\User") */ protected $user; /** * @Assert\NotBlank() * @Assert\IsTrue() */ protected $termsAccepted; public function setUser(User $user) { $this->user = $user; } public function getUser() { return $this->user; } public function getTermsAccepted() { return $this->termsAccepted; } public function setTermsAccepted($termsAccepted) { $this->termsAccepted = (bool) $termsAccepted; } }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

Next, create the form for this Registration model:

1// src/Form/Type/RegistrationType.php namespace App\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\FormBuilderInterface; class RegistrationType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('user', UserType::class); $builder->add('terms', CheckboxType::class, ['property_path' => 'termsAccepted']); } }
2
3
4
5
6
7
8
9
10
11
12
13
14
15

You don't need to use any special method to embed the UserType form. A form is a field, too - you can add it like any other field, with the expectation that the corresponding user property will hold an instance of the class UserType.

Handling the Form Submission

Next, you need a controller to handle the form. Start by creating a controller that will display the registration form:

1// src/Controller/AccountController.php namespace App\Controller; use App\Form\Model\Registration; use App\Form\Type\RegistrationType; use Doctrine\ODM\MongoDB\DocumentManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; class AccountController extends AbstractController { public function registerAction() { $form = $this->createForm(RegistrationType::class, new Registration()); return $this->render('Account/register.html.twig', [ 'form' => $form->createView() ]); } }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

and its template:

1{# templates/Account/register.html.twig #} {{ form_start(form, {'action': path('create'), 'method': 'POST'}) }} {{ form_widget(form) }} <input type="submit" /> {{ form_end(form) }}
2
3
4
5
6

Finally, create another action in AccountController, which will handle the form submission - perform its validation and save the User into MongoDB:

1// src/Controller/AccountController.php public function createAction(DocumentManager $dm, Request $request) { $form = $this->createForm(RegistrationType::class, new Registration()); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $registration = $form->getData(); $dm->persist($registration->getUser()); $dm->flush(); return $this->redirect(...); } return $this->render('Account/register.html.twig', [ 'form' => $form->createView() ]); }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

That's it! Your form now validates sent data and allows you to save the User object to MongoDB.