@@ -7,7 +7,7 @@ How to Create a Custom Form Field Type
77Symfony comes with a bunch of core field types available for building forms.
88However there are situations where you may want to create a custom form field
99type 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
1111explains how the field is defined, how you can customize its layout and finally,
1212how you can register it for use in your application.
1313
@@ -16,24 +16,25 @@ Defining the Field Type
1616
1717In order to create the custom field type, first you have to create the class
1818representing 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
2020for form fields, which is ``<BundleName>\Form\Type ``. Make sure the field extends
2121:class: `Symfony\\ Component\\ Form\\ AbstractType `::
2222
23- // src/AppBundle/Form/Type/GenderType .php
23+ // src/AppBundle/Form/Type/ShippingType .php
2424 namespace AppBundle\Form\Type;
2525
2626 use Symfony\Component\Form\AbstractType;
2727 use Symfony\Component\OptionsResolver\OptionsResolver;
2828
29- class GenderType extends AbstractType
29+ class ShippingType extends AbstractType
3030 {
3131 public function configureOptions(OptionsResolver $resolver)
3232 {
3333 $resolver->setDefaults(array(
3434 'choices' => array(
35- 'm' => 'Male',
36- 'f' => 'Female',
35+ 'standard' => 'Standard Shipping',
36+ 'expedited' => 'Expedited Shipping',
37+ 'priority' => 'Priority Shipping',
3738 )
3839 ));
3940 }
@@ -45,7 +46,7 @@ for form fields, which is ``<BundleName>\Form\Type``. Make sure the field extend
4546
4647 public function getName()
4748 {
48- return 'app_gender ';
49+ return 'app_shipping ';
4950 }
5051 }
5152
@@ -69,8 +70,8 @@ important:
6970 This method is used to set any extra variables you'll
7071 need when rendering your field in a template. For example, in `ChoiceType `_,
7172 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.
7475
7576.. versionadded :: 2.7
7677 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
9394your application. This is used in various places, such as when customizing
9495how your form type will be rendered.
9596
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 .
99100
100101Creating a Template for the Field
101102---------------------------------
@@ -109,14 +110,14 @@ any work as the custom field type will automatically be rendered like a ``choice
109110type. But for the sake of this example, suppose that when your field is "expanded"
110111(i.e. radio buttons or checkboxes, instead of a select field), you want to
111112always 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:
113114
114115.. configuration-block ::
115116
116117 .. code-block :: html+twig
117118
118119 {# app/Resources/views/form/fields.html.twig #}
119- {% block gender_widget %}
120+ {% block shipping_widget %}
120121 {% spaceless %}
121122 {% if expanded %}
122123 <ul {{ block('widget_container_attributes') }}>
@@ -136,7 +137,7 @@ link for details), create a ``gender_widget`` block to handle this:
136137
137138 .. code-block :: html+php
138139
139- <!-- app/Resources/views/form/gender_widget .html.php -->
140+ <!-- app/Resources/views/form/shipping_widget .html.php -->
140141 <?php if ($expanded) : ?>
141142 <ul <?php $view['form']->block($form, 'widget_container_attributes') ?>>
142143 <?php foreach ($form as $child) : ?>
@@ -154,7 +155,7 @@ link for details), create a ``gender_widget`` block to handle this:
154155.. note ::
155156
156157 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() ``.
158159 Further, the main config file should point to the custom form template
159160 so that it's used when rendering all forms.
160161
@@ -252,18 +253,18 @@ new instance of the type in one of your forms::
252253 use Symfony\Component\Form\AbstractType;
253254 use Symfony\Component\Form\FormBuilderInterface;
254255
255- class AuthorType extends AbstractType
256+ class OrderType extends AbstractType
256257 {
257258 public function buildForm(FormBuilderInterface $builder, array $options)
258259 {
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 ',
261262 ));
262263 }
263264 }
264265
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
267268section explains how more complex field types solve this problem.
268269
269270.. versionadded :: 2.6
@@ -278,17 +279,18 @@ Creating your Field Type as a Service
278279So far, this entry has assumed that you have a very simple custom field type.
279280But if you need access to configuration, a database connection, or some other
280281service, 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:
282283
283284.. configuration-block ::
284285
285286 .. code-block :: yaml
286287
287288 # app/config/config.yml
288289 parameters :
289- genders :
290- m : Male
291- f : Female
290+ shipping_options :
291+ standard : Standard Shipping
292+ expedited : Expedited Shipping
293+ priority : Priority Shipping
292294
293295 .. code-block :: xml
294296
@@ -300,21 +302,23 @@ example, suppose that you're storing the gender parameters in configuration:
300302 http://symfony.com/schema/dic/services/services-1.0.xsd" >
301303
302304 <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 >
306309 </parameter >
307310 </parameters >
308311 </container >
309312
310313 .. code-block :: php
311314
312315 // 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');
315319
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
318322``__construct() `` function:
319323
320324.. configuration-block ::
@@ -323,12 +327,12 @@ the ``genders`` parameter value as the first argument to its to-be-created
323327
324328 # src/AppBundle/Resources/config/services.yml
325329 services :
326- app.form.type.gender :
327- class : AppBundle\Form\Type\GenderType
330+ app.form.type.shipping :
331+ class : AppBundle\Form\Type\ShippingType
328332 arguments :
329- - ' %genders %'
333+ - ' %shipping_options %'
330334 tags :
331- - { name: form.type, alias: app_gender }
335+ - { name: form.type, alias: app_shipping }
332336
333337 .. code-block :: xml
334338
@@ -340,22 +344,22 @@ the ``genders`` parameter value as the first argument to its to-be-created
340344 http://symfony.com/schema/dic/services/services-1.0.xsd" >
341345
342346 <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 " />
346350 </service >
347351 </services >
348352 </container >
349353
350354 .. code-block :: php
351355
352356 // src/AppBundle/Resources/config/services.php
353- use AppBundle\Form\Type\GenderType ;
357+ use AppBundle\Form\Type\ShippingType ;
354358
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 %')
357361 ->addTag('form.type', array(
358- 'alias' => 'app_gender ',
362+ 'alias' => 'app_shipping ',
359363 ));
360364
361365 .. tip ::
@@ -366,36 +370,36 @@ the ``genders`` parameter value as the first argument to its to-be-created
366370Be sure that the ``alias `` attribute of the tag corresponds with the value
367371returned by the ``getName() `` method defined earlier. You'll see the importance
368372of 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::
370374
371- // src/AppBundle/Form/Type/GenderType .php
375+ // src/AppBundle/Form/Type/ShippingType .php
372376 namespace AppBundle\Form\Type;
373377
374378 use Symfony\Component\OptionsResolver\OptionsResolver;
375379
376380 // ...
377381
378382 // ...
379- class GenderType extends AbstractType
383+ class ShippingType extends AbstractType
380384 {
381- private $genderChoices ;
385+ private $shippingOptions ;
382386
383- public function __construct(array $genderChoices )
387+ public function __construct(array $shippingOptions )
384388 {
385- $this->genderChoices = $genderChoices ;
389+ $this->shippingOptions = $shippingOptions ;
386390 }
387391
388392 public function configureOptions(OptionsResolver $resolver)
389393 {
390394 $resolver->setDefaults(array(
391- 'choices' => $this->genderChoices ,
395+ 'choices' => $this->shippingOptions ,
392396 ));
393397 }
394398
395399 // ...
396400 }
397401
398- Great! The ``GenderType `` is now fueled by the configuration parameters and
402+ Great! The ``ShippingType `` is now fueled by the configuration parameters and
399403registered as a service. Additionally, because you used the ``form.type `` tag in its
400404configuration, using the field is now much easier::
401405
@@ -406,18 +410,18 @@ configuration, using the field is now much easier::
406410
407411 // ...
408412
409- class AuthorType extends AbstractType
413+ class OrderType extends AbstractType
410414 {
411415 public function buildForm(FormBuilderInterface $builder, array $options)
412416 {
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 ',
415419 ));
416420 }
417421 }
418422
419423Notice 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!
421425
422426.. _`ChoiceType` : https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
423427.. _`FieldType` : https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
0 commit comments