Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Form Variables are the Bomb

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

My favorite form rendering function is form_row() - pass the field as the first argument and... um... something weird called variables as the second argument. What are these variables?

Overriding the label Variable

Apparently, it's an array, and one variable you can pass is called label. So if you want to override a field's label, one way is with variables.

Give that a try with the subFamily field: add a second argument - a Twig array or hash - and say label set to Taxonomic Subfamily:

{{ form_start(genusForm) }}
... lines 2 - 5
{{ form_row(genusForm.subFamily, {
'label': 'Taxonomic Subfamily'
}) }}
... lines 9 - 16
{{ form_end(genusForm) }}

Try that - refresh! Okay, that's cool.

Overriding the attr Variable

So what else can we do with these variables? It also turns out that every field has a variable called attr, which is itself, an array. These are attributes that you want set on the widget, meaning the actual field itself.

So, you can give your field a class foo, or set disabled to disabled:

{{ form_start(genusForm) }}
... lines 2 - 5
{{ form_row(genusForm.subFamily, {
'label': 'Taxonomic Subfamily',
'attr': {
'class': 'foo',
'disabled': 'disabled'
}
}) }}
... lines 13 - 20
{{ form_end(genusForm) }}

Try that out. Perfect! The field is disabled and if you dig a little, there's the foo class.

These variables give us huge control over our fields. But, this still does not answer my original question: what are the variables that I can use on a field beyond just label and attr?

Listing all Available Variables

It turns out, the answer is hiding right down here in your web debug toolbar. Click the clipboard icon to go to the forms section of the profiler. Check this out: if you select a single field - like subFamily - you'll get a ton of good information. It shows you stuff about the submitted data, the options you passed when you originally created the field, and - most importantly - View Variables! Yes! This is your master list of every variable that's being used to render this field. And you can override

  • get this - everything.

This gives you access to the id attribute, the name attribute, the label we just overrode and even a way to add an attribute to your label element! Heck there's even a variable called disabled: we can just use that instead of setting the attribute.

Remove the disabled attribute, and then set disabled to true:

{{ form_start(genusForm) }}
... lines 2 - 5
{{ form_row(genusForm.subFamily, {
'label': 'Taxonomic Subfamily',
'attr': {
'class': 'foo'
},
'disabled': 'disabled',
}) }}
... lines 13 - 20
{{ form_end(genusForm) }}

That'll have the same effect: the field is still disabled.

Field Options Versus Variables

Head back into the profiler. The subFamily field has a variable called placeholder set to "Choose a Sub Family". To see what this does, remove the disabled variable. Then, refresh. There it is! The placeholder is the option that appears at the top of the select element.

Why is this set to "Choose a Sub Family"? Because that's what we passed as the placeholder option when we configured the field:

... lines 1 - 6
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
... lines 8 - 13
class GenusFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
... line 19
->add('subFamily', EntityType::class, [
'placeholder' => 'Choose a Sub Family',
... lines 22 - 25
])
... lines 27 - 39
;
}
... lines 42 - 48
}

Back in the template, override the variable, set placeholder to Select a Subfamily:

{{ form_start(genusForm) }}
... lines 2 - 5
{{ form_row(genusForm.subFamily, {
'label': 'Taxonomic Subfamily',
'attr': {
'class': 'foo'
},
'placeholder': 'Select a Subfamily'
}) }}
... lines 13 - 20
{{ form_end(genusForm) }}

So, which will win? The placeholder option, or the placeholder variable? Let's find out! Refresh!

It's "Select a Subfamily": the variable wins.

I wanted to show you this because this touches on a really important thing. When you configure a field in your form class, each field has a set of options. These are not the same thing as the variables you can override in your template.

Nope: your form class holds field options, and your rendering functions have variables. Occasionally, a field has an option and a variable with the same name, like placeholder. But for the most part, these are two totally separate ideas: a field has a set of options, which mostly influence how the field should function, and a different set of variables, which help decide how the field will be rendered.

Dumping Form Variables

Before we move into form theming, there's one other way to get a list of the variables for a field: dump them!

When we write genusForm.subFamily, this is actually an instance of an object called FormView. A FormView object doesn't really have much information on it, except for a public $vars property that holds all of its variables:

... lines 1 - 11
namespace Symfony\Component\Form;
... lines 13 - 18
class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
{
/**
* The variables assigned to this view.
*
* @var array
*/
public $vars = array(
'value' => null,
'attr' => array(),
);
... lines 30 - 161
}

Print them with dump(genusForm.subFamily.vars):

{{ form_start(genusForm) }}
... lines 2 - 5
{{ dump(genusForm.subFamily.vars) }}
... lines 7 - 22
{{ form_end(genusForm) }}

Head back, refresh, and boom! Check out this beautiful list. This will become even more important later. Ok, let's talk about form theming.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial is built on Symfony 3 but form theming hasn't changed much in Symfony 4 and Symfony 5. Other than some path differences - this tutorial should work fine.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "symfony/symfony": "3.4.*", // v3.4.49
        "doctrine/orm": "^2.5", // 2.7.5
        "doctrine/doctrine-bundle": "^1.6", // 1.12.13
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.4.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.6.7
        "symfony/monolog-bundle": "^2.8", // v2.12.1
        "symfony/polyfill-apcu": "^1.0", // v1.23.0
        "sensio/distribution-bundle": "^5.0", // v5.0.25
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.29
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.4
        "composer/package-versions-deprecated": "^1.11", // 1.11.99.4
        "knplabs/knp-markdown-bundle": "^1.4", // 1.9.0
        "doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
        "stof/doctrine-extensions-bundle": "^1.2" // v1.3.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.7
        "symfony/phpunit-bridge": "^3.0", // v3.4.47
        "nelmio/alice": "^2.1", // v2.3.6
        "doctrine/doctrine-fixtures-bundle": "^2.3" // v2.4.1
    }
}
userVoice