If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
So far, we set the property name of the form fields and Symfony tries to guess
the best field type to render. Since isPublished
is a boolean
in the database,
it guessed a checkbox field:
... lines 1 - 11 | |
class Genus | |
{ | |
... lines 14 - 41 | |
/** | |
* @ORM\Column(type="boolean") | |
*/ | |
private $isPublished = true; | |
... lines 46 - 137 | |
} |
But obviously, that's not always going to work.
Google for "Symfony form field types", and find a document called Form Types Reference.
These are all the different field types we can choose from. It's got stuff you'd
expect - like text
and textarea
, some HTML5 fields - like email
and integer
and
some more unusual types, like date
, which helps render date fields, either
as three drop-downs or a single text field.
Right now, isPublished
is a checkbox. But instead, I'd rather have a select drop-down
with "yes" and "no" options. But... you won't see a "select" type in this list. Instead,
it's called ChoiceType.
ChoiceType
is a little special: it can render a drop-down, radio buttons or checkboxes
based on what options you pass to it. One of the options is choices
, which, if
you look down at the example, you can see controls the actual items in the drop-down.
Let's use this! In GenusFormType
, the optional second argument to the add
function
is the field type you want to use. Set it to ChoiceType::class
:
... lines 1 - 5 | |
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |
... lines 7 - 9 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
... lines 15 - 18 | |
->add('isPublished', ChoiceType::class, [ | |
... lines 20 - 23 | |
]) | |
... line 25 | |
; | |
} | |
... lines 28 - 34 | |
} |
The third argument is an array of options to configure that field. What can you pass here? Well, each field type has different options... though there are a lot of options shared by all types, like the ability to customize the label.
Either way, the reference section will tell you what you can use. Pass in the choices
option and set that to an array. Add Yes
mapped to true
and No
mapped to false
.
The keys - Yes
and No
will be the text in the drop down:
... lines 1 - 9 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
... lines 15 - 18 | |
->add('isPublished', ChoiceType::class, [ | |
'choices' => [ | |
'Yes' => true, | |
'No' => false, | |
] | |
]) | |
... line 25 | |
; | |
} | |
... lines 28 - 34 | |
} |
The values - true
and false
will be the value that's passed to setIsPublished()
if
that option is chosen.
Try it out! Head back to the form and refresh! Perfect.
Let's keep going with this. This subFamily
field is also a drop-down. So that's
probably being guessed as a ChoiceType
, right? Almost. Check out the EntityType.
This is just like the ChoiceType
, except it's really good at fetching the options
by querying an entity.
In this case, it's automatically querying for the SubFamily
entity: it guessed
which type to use and auto-configured it. And yeah, I know - these sub-families
are totally silly. They're actually just the last names of people - coming from the
Faker library - I was being lazy.
But I do have one problem with this EntityType
field: it auto-selects the first
option. That's lame - I'd rather have an option on top that says "Choose a Sub-Family".
Check out the options for EntityType
: there's one called placeholder
. Click to
read more about that. Yes! This is exactly what we want!
Open the form class back up. We know that Symfony is guessing the EntityType
for
the subFamily
field. We could now manually pass EntityType::class
as the second
argument. But don't! Pass null
instead. Now, add a placeholder
option set
to Choose a Sub-Family
:
... lines 1 - 10 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
... line 16 | |
->add('subFamily', null, [ | |
'placeholder' => 'Choose a Sub Family' | |
]) | |
... lines 20 - 28 | |
; | |
} | |
... lines 31 - 37 | |
} |
But wait, why did I pass null
as the second argument? Well first, because I can!
I can be lazy here: if I pass null
, Symfony will guess the EntityType
. That's
cool.
Second, when you use the EntityType
, there's a required option called class
.
Let me show you an example: 'class' => 'AppBundle:User'
. You have to tell
it which entity to query from. But if you let Symfony guess the field type for
you, then it will also guess any options it can, including this one. So by being
lazy and passing null
, it will continue to guess the field type and a few other
options for me, like class
.
Anyways, go back, refresh, and there it is. Here are the key takeaways. First, you
have a giant dictionary of built-in form field types. And second: you configure each
field by passing a third argument to the add()
function.
Now, how could we further control the query that's made for the SubFamily
options?
What if we need them to be listed alphabetically?
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.1.*", // v3.1.4
"doctrine/orm": "^2.5", // v2.7.2
"doctrine/doctrine-bundle": "^1.6", // 1.6.4
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
"symfony/swiftmailer-bundle": "^2.3", // v2.3.11
"symfony/monolog-bundle": "^2.8", // 2.11.1
"symfony/polyfill-apcu": "^1.0", // v1.2.0
"sensio/distribution-bundle": "^5.0", // v5.0.22
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
"doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.0.7
"symfony/phpunit-bridge": "^3.0", // v3.1.3
"nelmio/alice": "^2.1", // 2.1.4
"doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
}
}