|
3
|
1 |
Overriding Default FOSUserBundle Forms |
|
|
2 |
====================================== |
|
|
3 |
|
|
|
4 |
## Overriding a Form Type |
|
|
5 |
|
|
|
6 |
The default forms packaged with the FOSUserBundle provide functionality for |
|
|
7 |
registering new user, updating your profile, changing your password and |
|
|
8 |
much more. These forms work well with the bundle's default classes and controllers. |
|
|
9 |
But, as you start to add more properties to your `User` |
|
|
10 |
class or you decide you want to add a few options to the registration form you |
|
|
11 |
will find that you need to override the forms in the bundle. |
|
|
12 |
|
|
|
13 |
Suppose that you have created an ORM user class with the following class name, |
|
|
14 |
`Acme\UserBundle\Entity\User`. In this class, you have added a `name` property |
|
|
15 |
because you would like to save the user's name as well as their username and |
|
|
16 |
email address. Now, when a user registers for your site they should enter in their |
|
|
17 |
name as well as their username, email and password. Below is an example `$name` |
|
|
18 |
property and its validators. |
|
|
19 |
|
|
|
20 |
``` php |
|
|
21 |
// src/Acme/UserBundle/Entity/User.php |
|
|
22 |
<?php |
|
|
23 |
|
|
|
24 |
use FOS\UserBundle\Entity\User as BaseUser; |
|
|
25 |
use Doctrine\ORM\Mapping as ORM; |
|
|
26 |
use Symfony\Component\Validator\Constraints as Assert; |
|
|
27 |
|
|
|
28 |
class User extends BaseUser |
|
|
29 |
{ |
|
|
30 |
/** |
|
|
31 |
* @ORM\Id |
|
|
32 |
* @ORM\Column(type="integer") |
|
|
33 |
* @ORM\GeneratedValue(strategy="AUTO") |
|
|
34 |
*/ |
|
|
35 |
protected $id; |
|
|
36 |
|
|
|
37 |
/** |
|
|
38 |
* @ORM\Column(type="string", length="255") |
|
|
39 |
* |
|
|
40 |
* @Assert\NotBlank(message="Please enter your name.", groups={"Registration", "Profile"}) |
|
|
41 |
* @Assert\MinLength(limit="3", message="The name is too short.", groups={"Registration", "Profile"}) |
|
|
42 |
* @Assert\MaxLength(limit="255", message="The name is too long.", groups={"Registration", "Profile"}) |
|
|
43 |
*/ |
|
|
44 |
protected $name; |
|
|
45 |
|
|
|
46 |
// ... |
|
|
47 |
} |
|
|
48 |
``` |
|
|
49 |
|
|
|
50 |
**Note:** |
|
|
51 |
|
|
|
52 |
``` |
|
|
53 |
By default, the Registration validation group is used when validating a new |
|
|
54 |
user registration. Unless you have overriden this value in the configuration, |
|
|
55 |
make sure you add the validation group named Registration to your name property. |
|
|
56 |
``` |
|
|
57 |
|
|
|
58 |
If you try and register using the default registration form you will find that |
|
|
59 |
your new `name` property is not part of the form. You need to create a custom |
|
|
60 |
form type and configure the bundle to use it. |
|
|
61 |
|
|
|
62 |
The first step is to create a new form type in your own bundle. The following |
|
|
63 |
class extends the base FOSUserBundle `RegistrationFormType` and then adds the |
|
|
64 |
custom `name` field. |
|
|
65 |
|
|
|
66 |
``` php |
|
|
67 |
// src/Acme/UserBundle/Form/Type/RegistrationFormType.php |
|
|
68 |
<?php |
|
|
69 |
|
|
|
70 |
namespace Acme\UserBundle\Form\Type; |
|
|
71 |
|
|
|
72 |
use Symfony\Component\Form\FormBuilder; |
|
|
73 |
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType; |
|
|
74 |
|
|
|
75 |
class RegistrationFormType extends BaseType |
|
|
76 |
{ |
|
|
77 |
public function buildForm(FormBuilder $builder, array $options) |
|
|
78 |
{ |
|
|
79 |
parent::buildForm($builder, $options); |
|
|
80 |
|
|
|
81 |
// add your custom field |
|
|
82 |
$builder->add('name'); |
|
|
83 |
} |
|
|
84 |
|
|
|
85 |
public function getName() |
|
|
86 |
{ |
|
|
87 |
return 'acme_user_registration'; |
|
|
88 |
} |
|
|
89 |
} |
|
|
90 |
``` |
|
|
91 |
|
|
|
92 |
Now that you have created your custom form type, you must declare it as a service |
|
|
93 |
and add a tag to it. The tag must have a `name` value of `form.type` and an `alias` |
|
|
94 |
value that is the equal to the string returned from the `getName` method of your |
|
|
95 |
form type class. The `alias` that you specify is what you will use in the FOSUserBundle |
|
|
96 |
configuration to let the bundle know that you want to use your custom form. |
|
|
97 |
|
|
|
98 |
Below is an example of configuring your form type as a service in XML: |
|
|
99 |
|
|
|
100 |
``` xml |
|
|
101 |
<!-- src/Acme/UserBundle/Resources/config/services.xml --> |
|
|
102 |
<?xml version="1.0" encoding="UTF-8" ?> |
|
|
103 |
|
|
|
104 |
<container xmlns="http://symfony.com/schema/dic/services" |
|
|
105 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
|
106 |
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> |
|
|
107 |
|
|
|
108 |
<services> |
|
|
109 |
|
|
|
110 |
<service id="acme_user.registration.form.type" class="Acme\UserBundle\Form\Type\RegistrationFormType"> |
|
|
111 |
<tag name="form.type" alias="acme_user_registration" /> |
|
|
112 |
<argument>%fos_user.model.user.class%</argument> |
|
|
113 |
</service> |
|
|
114 |
|
|
|
115 |
</services> |
|
|
116 |
|
|
|
117 |
</container> |
|
|
118 |
``` |
|
|
119 |
|
|
|
120 |
Or if you prefer YAML: |
|
|
121 |
|
|
|
122 |
``` yaml |
|
|
123 |
# src/Acme/UserBundle/Resources/config/services.yml |
|
|
124 |
services: |
|
|
125 |
acme_user.registration.form.type: |
|
|
126 |
class: Acme\UserBundle\Form\Type\RegistrationFormType |
|
|
127 |
arguments: [%fos_user.model.user.class%] |
|
|
128 |
tags: |
|
|
129 |
- { name: form.type, alias: acme_user_registration } |
|
|
130 |
``` |
|
|
131 |
|
|
|
132 |
**Note:** |
|
|
133 |
|
|
|
134 |
``` |
|
|
135 |
In the form type service configuration you have specified the `fos_user.model.user.class` |
|
|
136 |
container parameter as a constructor argument. Unless you have redefined the |
|
|
137 |
constructor in your form type class, you must include this argument as it is a |
|
|
138 |
requirement of the FOSUserBundle form type that you extended. |
|
|
139 |
``` |
|
|
140 |
|
|
|
141 |
Finally, you must update the configuration of the FOSUserBundle so that it will |
|
|
142 |
use your form type instead of the default one. Below is the configuration for |
|
|
143 |
changing the registration form type in YAML. |
|
|
144 |
|
|
|
145 |
``` yaml |
|
|
146 |
# app/config/config.yml |
|
|
147 |
fos_user: |
|
|
148 |
# ... |
|
|
149 |
registration: |
|
|
150 |
form: |
|
|
151 |
type: acme_user_registration |
|
|
152 |
``` |
|
|
153 |
|
|
|
154 |
Note how the `alias` value used in your form type's service configuration tag |
|
|
155 |
is used in the bundle configuration to tell the FOSUserBundle to use your custom |
|
|
156 |
form type. |
|
|
157 |
|
|
|
158 |
## Overriding Form Handlers |
|
|
159 |
|
|
|
160 |
There are two ways to override the default functionality provided by the |
|
|
161 |
FOSUserBundle form handlers. The easiest way is to override the `onSuccess` |
|
|
162 |
method of the handler. The `onSuccess` method is called after the form has been |
|
|
163 |
bound and validated. |
|
|
164 |
|
|
|
165 |
The second way is to override the `process` method. Overriding |
|
|
166 |
the `process` method should only be necessary when more advanced functionality |
|
|
167 |
is necessary when binding and validating the form. |
|
|
168 |
|
|
|
169 |
Suppose you want to add some functionality that takes place after a successful |
|
|
170 |
user registration. First you need to create a new class that extends |
|
|
171 |
`FOS\UserBundle\Form\Handler\RegistrationFormHandler` and then override the |
|
|
172 |
protected `onSuccess` method. |
|
|
173 |
|
|
|
174 |
``` php |
|
|
175 |
// src/Acme/UserBundle/Form/Handler/RegistrationFormHandler.php |
|
|
176 |
<?php |
|
|
177 |
|
|
|
178 |
namespace Acme\UserBundle\Form\Handler; |
|
|
179 |
|
|
|
180 |
use FOS\UserBundle\Form\Handler\RegistrationFormHandler as BaseHandler; |
|
|
181 |
use FOS\UserBundle\Model\UserInterface; |
|
|
182 |
|
|
|
183 |
class RegistrationFormHandler extends BaseHandler |
|
|
184 |
{ |
|
|
185 |
protected function onSuccess(UserInterface $user, $confirmation) |
|
|
186 |
{ |
|
|
187 |
// Note: if you plan on modifying the user then do it before calling the |
|
|
188 |
// parent method as the parent method will flush the changes |
|
|
189 |
|
|
|
190 |
parent::onSuccess($user, $confirmation); |
|
|
191 |
|
|
|
192 |
// otherwise add your functionality here |
|
|
193 |
} |
|
|
194 |
} |
|
|
195 |
``` |
|
|
196 |
|
|
|
197 |
**Note:** |
|
|
198 |
|
|
|
199 |
``` |
|
|
200 |
If you do not call the onSuccess method of the parent class then the default |
|
|
201 |
logic that the FOSUserBundle handler normally executes upon a successful |
|
|
202 |
submission will not be performed. |
|
|
203 |
``` |
|
|
204 |
|
|
|
205 |
You can also choose to override the `process` method of the handler. If you choose |
|
|
206 |
to override the `process` method then you will be responsible for binding the form |
|
|
207 |
data and validating it, as well as implementing the logic required upon a |
|
|
208 |
successful submission. |
|
|
209 |
|
|
|
210 |
``` php |
|
|
211 |
// src/Acme/UserBundle/Form/Handler/RegistrationFormHandler.php |
|
|
212 |
<?php |
|
|
213 |
|
|
|
214 |
namespace Acme\UserBundle\Form\Handler; |
|
|
215 |
|
|
|
216 |
use FOS\UserBundle\Form\Handler\RegistrationFormHandler as BaseHandler; |
|
|
217 |
|
|
|
218 |
class RegistrationFormHandler extends BaseHandler |
|
|
219 |
{ |
|
|
220 |
public function process($confirmation = false) |
|
|
221 |
{ |
|
|
222 |
$user = $this->userManager->createUser(); |
|
|
223 |
$this->form->setData($user); |
|
|
224 |
|
|
|
225 |
if ('POST' == $this->request->getMethod()) { |
|
|
226 |
$this->form->bindRequest($this->request); |
|
|
227 |
if ($this->form->isValid()) { |
|
|
228 |
|
|
|
229 |
// do your custom logic here |
|
|
230 |
|
|
|
231 |
return true; |
|
|
232 |
} |
|
|
233 |
} |
|
|
234 |
|
|
|
235 |
return false; |
|
|
236 |
} |
|
|
237 |
} |
|
|
238 |
``` |
|
|
239 |
|
|
|
240 |
**Note:** |
|
|
241 |
|
|
|
242 |
``` |
|
|
243 |
The process method should return true for a successful submission and false |
|
|
244 |
otherwise. |
|
|
245 |
``` |
|
|
246 |
|
|
|
247 |
Now that you have created and implemented your custom form handler class, you |
|
|
248 |
must configure it as a service in the container. Below is an example of |
|
|
249 |
configuring your form handler as a service in XML: |
|
|
250 |
|
|
|
251 |
``` xml |
|
|
252 |
<!-- src/Acme/UserBundle/Resources/config/services.xml --> |
|
|
253 |
<?xml version="1.0" encoding="UTF-8" ?> |
|
|
254 |
|
|
|
255 |
<container xmlns="http://symfony.com/schema/dic/services" |
|
|
256 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
|
257 |
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> |
|
|
258 |
|
|
|
259 |
<services> |
|
|
260 |
|
|
|
261 |
<service id="acme_user.form.handler.registration" class="Acme\UserBundle\Form\Handler\RegistrationFormHandler" scope="request" public="false"> |
|
|
262 |
<argument type="service" id="fos_user.registration.form" /> |
|
|
263 |
<argument type="service" id="request" /> |
|
|
264 |
<argument type="service" id="fos_user.user_manager" /> |
|
|
265 |
<argument type="service" id="fos_user.mailer" /> |
|
|
266 |
</service> |
|
|
267 |
|
|
|
268 |
</services> |
|
|
269 |
|
|
|
270 |
</container> |
|
|
271 |
``` |
|
|
272 |
|
|
|
273 |
Or if you prefer YAML: |
|
|
274 |
|
|
|
275 |
``` yaml |
|
|
276 |
# src/Acme/UserBundle/Resources/config/services.yml |
|
|
277 |
services: |
|
|
278 |
acme_user.form.handler.registration: |
|
|
279 |
class: Acme\UserBundle\Form\Handler\RegistrationFormHandler |
|
|
280 |
arguments: ["@fos_user.registration.form", "@request", "@fos_user.user_manager", "@fos_user.mailer"] |
|
|
281 |
scope: request |
|
|
282 |
public: false |
|
|
283 |
``` |
|
|
284 |
|
|
|
285 |
Here you have injected other services as arguments to the constructor of our class |
|
|
286 |
because these arguments are required by the base FOSUserBundle form handler class |
|
|
287 |
which you extended. |
|
|
288 |
|
|
|
289 |
Now that your new form handler has been configured in the container, all that is |
|
|
290 |
left to do is update the FOSUserBundle configuration. |
|
|
291 |
|
|
|
292 |
``` yaml |
|
|
293 |
# app/config/config.yml |
|
|
294 |
fos_user: |
|
|
295 |
# ... |
|
|
296 |
registration: |
|
|
297 |
form: |
|
|
298 |
handler: acme_user.form.handler.registration |
|
|
299 |
``` |
|
|
300 |
|
|
|
301 |
Note how the `id` of your configured service is used in the bundle configuration |
|
|
302 |
to tell the FOSUserBundle to use your custom form handler. |
|
|
303 |
|
|
|
304 |
At this point, when a user registers on your site your service will be used to |
|
|
305 |
handle the form submission. |