@@ -7,7 +7,7 @@ How to Create a Custom Form Field Type
7
7
Symfony comes with a bunch of core field types available for building forms.
8
8
However there are situations where you may want to create a custom form field
9
9
type for a specific purpose. This recipe assumes you need a field definition
10
- that holds a person's gender , based on the existing choice field. This section
10
+ that holds a shipping option , based on the existing choice field. This section
11
11
explains how the field is defined, how you can customize its layout and finally,
12
12
how you can register it for use in your application.
13
13
@@ -16,24 +16,25 @@ Defining the Field Type
16
16
17
17
In order to create the custom field type, first you have to create the class
18
18
representing the field. In this situation the class holding the field type
19
- will be called ``GenderType `` and the file will be stored in the default location
19
+ will be called ``ShippingType `` and the file will be stored in the default location
20
20
for form fields, which is ``<BundleName>\Form\Type ``. Make sure the field extends
21
21
:class: `Symfony\\ Component\\ Form\\ AbstractType `::
22
22
23
- // src/AppBundle/Form/Type/GenderType .php
23
+ // src/AppBundle/Form/Type/ShippingType .php
24
24
namespace AppBundle\Form\Type;
25
25
26
26
use Symfony\Component\Form\AbstractType;
27
27
use Symfony\Component\OptionsResolver\OptionsResolver;
28
28
29
- class GenderType extends AbstractType
29
+ class ShippingType extends AbstractType
30
30
{
31
31
public function configureOptions(OptionsResolver $resolver)
32
32
{
33
33
$resolver->setDefaults(array(
34
34
'choices' => array(
35
- 'm' => 'Male',
36
- 'f' => 'Female',
35
+ 'standard' => 'Standard Shipping',
36
+ 'expedited' => 'Expedited Shipping',
37
+ 'priority' => 'Priority Shipping',
37
38
)
38
39
));
39
40
}
@@ -45,7 +46,7 @@ for form fields, which is ``<BundleName>\Form\Type``. Make sure the field extend
45
46
46
47
public function getName()
47
48
{
48
- return 'app_gender ';
49
+ return 'app_shipping ';
49
50
}
50
51
}
51
52
@@ -69,8 +70,8 @@ important:
69
70
This method is used to set any extra variables you'll
70
71
need when rendering your field in a template. For example, in `ChoiceType `_,
71
72
a ``multiple `` variable is set and used in the template to set (or not
72
- set) the ``multiple `` attribute on the ``select `` field. See ` Creating a Template for the Field `_
73
- for more details.
73
+ set) the ``multiple `` attribute on the ``select `` field. See
74
+ ` Creating a Template for the Field `_ for more details.
74
75
75
76
.. versionadded :: 2.7
76
77
The ``configureOptions() `` method was introduced in Symfony 2.7. Previously,
@@ -93,9 +94,9 @@ The ``getName()`` method returns an identifier which should be unique in
93
94
your application. This is used in various places, such as when customizing
94
95
how your form type will be rendered.
95
96
96
- The goal of this field was to extend the choice type to enable selection of
97
- a gender . This is achieved by fixing the ``choices `` to a list of possible
98
- genders .
97
+ The goal of this field was to extend the choice type to enable selection of the
98
+ shipping type . This is achieved by fixing the ``choices `` to a list of available
99
+ shipping options .
99
100
100
101
Creating a Template for the Field
101
102
---------------------------------
@@ -109,14 +110,14 @@ any work as the custom field type will automatically be rendered like a ``choice
109
110
type. But for the sake of this example, suppose that when your field is "expanded"
110
111
(i.e. radio buttons or checkboxes, instead of a select field), you want to
111
112
always render it in a ``ul `` element. In your form theme template (see above
112
- link for details), create a ``gender_widget `` block to handle this:
113
+ link for details), create a ``shipping_widget `` block to handle this:
113
114
114
115
.. configuration-block ::
115
116
116
117
.. code-block :: html+twig
117
118
118
119
{# app/Resources/views/form/fields.html.twig #}
119
- {% block gender_widget %}
120
+ {% block shipping_widget %}
120
121
{% spaceless %}
121
122
{% if expanded %}
122
123
<ul {{ block('widget_container_attributes') }}>
@@ -136,7 +137,7 @@ link for details), create a ``gender_widget`` block to handle this:
136
137
137
138
.. code-block :: html+php
138
139
139
- <!-- app/Resources/views/form/gender_widget .html.php -->
140
+ <!-- app/Resources/views/form/shipping_widget .html.php -->
140
141
<?php if ($expanded) : ?>
141
142
<ul <?php $view['form']->block($form, 'widget_container_attributes') ?>>
142
143
<?php foreach ($form as $child) : ?>
@@ -154,7 +155,7 @@ link for details), create a ``gender_widget`` block to handle this:
154
155
.. note ::
155
156
156
157
Make sure the correct widget prefix is used. In this example the name should
157
- be ``gender_widget ``, according to the value returned by ``getName() ``.
158
+ be ``shipping_widget ``, according to the value returned by ``getName() ``.
158
159
Further, the main config file should point to the custom form template
159
160
so that it's used when rendering all forms.
160
161
@@ -252,18 +253,18 @@ new instance of the type in one of your forms::
252
253
use Symfony\Component\Form\AbstractType;
253
254
use Symfony\Component\Form\FormBuilderInterface;
254
255
255
- class AuthorType extends AbstractType
256
+ class OrderType extends AbstractType
256
257
{
257
258
public function buildForm(FormBuilderInterface $builder, array $options)
258
259
{
259
- $builder->add('gender_code ', new GenderType (), array(
260
- 'placeholder' => 'Choose a gender ',
260
+ $builder->add('shipping_code ', new ShippingType (), array(
261
+ 'placeholder' => 'Choose a delivery option ',
261
262
));
262
263
}
263
264
}
264
265
265
- But this only works because the ``GenderType () `` is very simple. What if
266
- the gender codes were stored in configuration or in a database? The next
266
+ But this only works because the ``ShippingType () `` is very simple. What if
267
+ the shipping codes were stored in configuration or in a database? The next
267
268
section explains how more complex field types solve this problem.
268
269
269
270
.. versionadded :: 2.6
@@ -278,17 +279,18 @@ Creating your Field Type as a Service
278
279
So far, this entry has assumed that you have a very simple custom field type.
279
280
But if you need access to configuration, a database connection, or some other
280
281
service, then you'll want to register your custom type as a service. For
281
- example, suppose that you're storing the gender parameters in configuration:
282
+ example, suppose that you're storing the shipping parameters in configuration:
282
283
283
284
.. configuration-block ::
284
285
285
286
.. code-block :: yaml
286
287
287
288
# app/config/config.yml
288
289
parameters :
289
- genders :
290
- m : Male
291
- f : Female
290
+ shipping_options :
291
+ standard : Standard Shipping
292
+ expedited : Expedited Shipping
293
+ priority : Priority Shipping
292
294
293
295
.. code-block :: xml
294
296
@@ -300,21 +302,23 @@ example, suppose that you're storing the gender parameters in configuration:
300
302
http://symfony.com/schema/dic/services/services-1.0.xsd" >
301
303
302
304
<parameters >
303
- <parameter key =" genders" type =" collection" >
304
- <parameter key =" m" >Male</parameter >
305
- <parameter key =" f" >Female</parameter >
305
+ <parameter key =" shipping_options" type =" collection" >
306
+ <parameter key =" standard" >Standard Shipping</parameter >
307
+ <parameter key =" expedited" >Expedited Shipping</parameter >
308
+ <parameter key =" priority" >Priority Shipping</parameter >
306
309
</parameter >
307
310
</parameters >
308
311
</container >
309
312
310
313
.. code-block :: php
311
314
312
315
// app/config/config.php
313
- $container->setParameter('genders.m', 'Male');
314
- $container->setParameter('genders.f', 'Female');
316
+ $container->setParameter('shipping_options.standard', 'Standard Shipping');
317
+ $container->setParameter('shipping_options.expedited', 'Expedited Shipping');
318
+ $container->setParameter('shipping_options.priority', 'Priority Shipping');
315
319
316
- To use the parameter, define your custom field type as a service, injecting
317
- the `` genders `` parameter value as the first argument to its to-be-created
320
+ To use the parameter, define your custom field type as a service, injecting the
321
+ `` shipping_options `` parameter value as the first argument to its to-be-created
318
322
``__construct() `` function:
319
323
320
324
.. configuration-block ::
@@ -323,12 +327,12 @@ the ``genders`` parameter value as the first argument to its to-be-created
323
327
324
328
# src/AppBundle/Resources/config/services.yml
325
329
services :
326
- app.form.type.gender :
327
- class : AppBundle\Form\Type\GenderType
330
+ app.form.type.shipping :
331
+ class : AppBundle\Form\Type\ShippingType
328
332
arguments :
329
- - ' %genders %'
333
+ - ' %shipping_options %'
330
334
tags :
331
- - { name: form.type, alias: app_gender }
335
+ - { name: form.type, alias: app_shipping }
332
336
333
337
.. code-block :: xml
334
338
@@ -340,22 +344,22 @@ the ``genders`` parameter value as the first argument to its to-be-created
340
344
http://symfony.com/schema/dic/services/services-1.0.xsd" >
341
345
342
346
<services >
343
- <service id =" app.form.type.gender " class =" AppBundle\Form\Type\GenderType " >
344
- <argument >%genders %</argument >
345
- <tag name =" form.type" alias =" app_gender " />
347
+ <service id =" app.form.type.shipping " class =" AppBundle\Form\Type\ShippingType " >
348
+ <argument >%shipping_options %</argument >
349
+ <tag name =" form.type" alias =" app_shipping " />
346
350
</service >
347
351
</services >
348
352
</container >
349
353
350
354
.. code-block :: php
351
355
352
356
// src/AppBundle/Resources/config/services.php
353
- use AppBundle\Form\Type\GenderType ;
357
+ use AppBundle\Form\Type\ShippingType ;
354
358
355
- $container->register('app.form.type.gender ', GenderType ::class)
356
- ->addArgument('%genders %')
359
+ $container->register('app.form.type.shipping ', ShippingType ::class)
360
+ ->addArgument('%shipping_options %')
357
361
->addTag('form.type', array(
358
- 'alias' => 'app_gender ',
362
+ 'alias' => 'app_shipping ',
359
363
));
360
364
361
365
.. tip ::
@@ -366,36 +370,36 @@ the ``genders`` parameter value as the first argument to its to-be-created
366
370
Be sure that the ``alias `` attribute of the tag corresponds with the value
367
371
returned by the ``getName() `` method defined earlier. You'll see the importance
368
372
of this in a moment when you use the custom field type. But first, add a ``__construct ``
369
- method to ``GenderType ``, which receives the gender configuration::
373
+ method to ``ShippingType ``, which receives the shipping configuration::
370
374
371
- // src/AppBundle/Form/Type/GenderType .php
375
+ // src/AppBundle/Form/Type/ShippingType .php
372
376
namespace AppBundle\Form\Type;
373
377
374
378
use Symfony\Component\OptionsResolver\OptionsResolver;
375
379
376
380
// ...
377
381
378
382
// ...
379
- class GenderType extends AbstractType
383
+ class ShippingType extends AbstractType
380
384
{
381
- private $genderChoices ;
385
+ private $shippingOptions ;
382
386
383
- public function __construct(array $genderChoices )
387
+ public function __construct(array $shippingOptions )
384
388
{
385
- $this->genderChoices = $genderChoices ;
389
+ $this->shippingOptions = $shippingOptions ;
386
390
}
387
391
388
392
public function configureOptions(OptionsResolver $resolver)
389
393
{
390
394
$resolver->setDefaults(array(
391
- 'choices' => $this->genderChoices ,
395
+ 'choices' => $this->shippingOptions ,
392
396
));
393
397
}
394
398
395
399
// ...
396
400
}
397
401
398
- Great! The ``GenderType `` is now fueled by the configuration parameters and
402
+ Great! The ``ShippingType `` is now fueled by the configuration parameters and
399
403
registered as a service. Additionally, because you used the ``form.type `` tag in its
400
404
configuration, using the field is now much easier::
401
405
@@ -406,18 +410,18 @@ configuration, using the field is now much easier::
406
410
407
411
// ...
408
412
409
- class AuthorType extends AbstractType
413
+ class OrderType extends AbstractType
410
414
{
411
415
public function buildForm(FormBuilderInterface $builder, array $options)
412
416
{
413
- $builder->add('gender_code ', 'app_gender ', array(
414
- 'placeholder' => 'Choose a gender ',
417
+ $builder->add('shipping_code ', 'app_shipping ', array(
418
+ 'placeholder' => 'Choose a delivery option ',
415
419
));
416
420
}
417
421
}
418
422
419
423
Notice that instead of instantiating a new instance, you can just refer to
420
- it by the alias used in your service configuration, ``app_gender ``. Have fun!
424
+ it by the alias used in your service configuration, ``app_shipping ``. Have fun!
421
425
422
426
.. _`ChoiceType` : https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
423
427
.. _`FieldType` : https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
0 commit comments