Creating a custom form field type in symfony 2 11


I am finally starting to dive into symfony 2 properly. Yes – it’s taken a while, work has taken me in different directions! I found myself needing to create a custom form field type pretty quickly, but couldn’t find much in the way of documentation to do so, so I thought I’ld throw it up here; partly to help others, but mostly to get feedback to make sure I’m not approaching this from the wrong angle.

I have a model called Person, and this Person has a attribute of preferredTranportMethod, which could be either Train, Car or Bike. This is similar to what one might use an enum for with doctrine, but for portability I’m making this an integer. This means my model looks something like this:

 
class Person
{
  const TRANSPORT_CAR = 1;
  const TRANSPORT_TRAIN = 2;
  const TRANSPORT_BIKE = 3;
 
  protected $preferredTransportMethod;
}

In a form I wan this to be a select box, so it was typical for me to do something like this in my form type:

 
class XXX extends BaseType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
      $builder->add('preferredTransportMethod', 'choice', array(
        'choices'  => array(
          Person::TRANSPORT_CAR => 'car',
          Person::TRANSPORT_TRAIN => 'train',
          Person::TRANSPORT_BIKE => 'bike',
        )));
    }
}

The problem with this is that it’s not reusable – if I had several forms with this choice, and needed to add PLANE to the options, I’d have to modify them all. So, the solution was to add my own form field type of ‘transportmethod’

To start with, I looked at how the Timezone field type worked, looking at the source in

'vendor/symfony/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php'

. It seemed pretty simple, take al ook at the code yourself. You’ll notice is separates out the choices into a separate class of TimezoneChoiceList. I copied this structure to create my transportmethod type in my own bundle.

In the file src/Acme/ProfileBundle/Form/Extension/Type/TransportMethodType.php

 
namespace Acme\ProfileBundle\Form\Extension\Type;
 
use Symfony\Component\Form\AbstractType;
 
use Acme\ProfileBundle\Form\Extension\ChoiceList\TransportMethodChoiceList;
 
class TransportMethodType extends AbstractType
{
 
    /**
     * {@inheritdoc}
     */
    public function getDefaultOptions(array $options)
    {
        return array(
            'choice_list' => new TransportMethodChoiceList(),
        );
    }
 
    /**
     * {@inheritdoc}
     */
    public function getParent(array $options)
    {
        return 'choice';
    }
 
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'timezone';
    }
 
}

As you can see, this references TransportMethodChoiceList, which is in

src/Acme/ProfileBundle/Form/Extension/ChoiceList/TransportMethodChoiceList.php

 
namespace Acme\ProfileBundle\Form\Extension\ChoiceList;
 
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
 
use Acme\ProfileBundle\Entity\Person;
 
class TransportMethodChoiceList implements ChoiceListInterface
{
  public function getChoices()
  {
    return array(
          Person::TRANSPORT_CAR => 'car',
          Person::TRANSPORT_TRAIN => 'train',
          Person::TRANSPORT_BIKE => 'bike',
    );
  }
}

Now I need to register this new field type as a service in my Bundle

src/Acme/ProfileBundle/Resources/config/services.xml
      <service id="form.type.transportmethod" class="Acme\ProfileBundle\Form\Extension\Type\TransportMethodType">
        <tag name="form.type" alias="transportmethod" />
      </service>

Now in my form types, I can simply do:

class PersonFormType extends AbstractType
{
 
  public function buildForm(FormBuilder $builder, array $options)
  {
 
    $builder->add('name');
    $builder->add('dateOfBirth', 'birthday');
 
    $builder->add('preferredTransportMethod', 'transportmethod');
  }

Hope that helps! :)


Leave a comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

11 thoughts on “Creating a custom form field type in symfony 2