Rich Sage

> home

Adding non-entity fields to your Symfony2 forms

july 2011

UPDATE: The example below is for Symfony 2.0. For Symfony 2.1 onwards, you should use the "mapped" option instead of "property_path".

UPDATE #2: Bernhard Schussek has provided a simplified version for Symfony 2.1 onwards - thanks Bernhard:

use Symfony\Component\Validator\Constraints\True;

// in your buildForm() method:
    ->add("firstName", "text")
    ->add("lastName", "text")
    ->add("emailAddress", "email")
    ->add("t_and_c", "checkbox", array(
        "mapped" => false,
        "constraints" => new True(array(
            "message" => "Please accept the Terms and conditions in order to register")

I’ve had a case recently whereby I needed to implement a registration form in my current Symfony2 application, based on a Mandango model. This form consisted of selected fields from my model, along with a separate “I accept the terms and conditions” checkbox; pretty standard. In Symfony 1, it was straightforward to add in non-model fields, however in Symfony2 the convention for forms is to create a domain model which represents your form, which then gets populated with the data.

Initially I went with extending from the Mandango model (in my case, Model\MyOwnBundle\User being the original model) and adding in a separate get/setTermsAndConditions() method, but this caused problems when saving the model down, as Mandango couldn’t find the document class (since I’d extended it and called it UserRegistration).

After a bit of digging and experimentation however, the following code does what I need it to, without having to extend my existing model or create a new one (which I’d then have to use to populate my actual Mandango model):

use Symfony\Component\Form\AbstractType,

class RegisterFormType extends AbstractType
     * Constructs our registration form
     * @param \Symfony\Component\Form\FormBuilder $builder
     * @param array $options
     * @return void
    public function buildForm(FormBuilder $builder, array $options)
        // Build the form
            add("firstName", "text")->
            add("lastName", "text")->
            add("emailAddress", "email")->
                    "property_path" => false,

        // "True" validator on the form for t&c
            addValidator(new CallbackValidator(function(FormInterface $form)
                if (!$form["t_and_c"]->getData())
                    $form->addError(new FormError('Please accept the terms and conditions in order to register'));

    // ...

The above adds the t_and_c field but using "property_path" => false means it’s not validated against the model and therefore no need to implement separate get/set() methods. Instead we use a callback validator on the form to check the value of the t_and_c field and ensure it’s been checked. Et voila :-)

comments powered by Disqus
Rich Sage

Hello, I'm Rich :-)