- Speaker: Bernhard Schussek
- Date: Friday 28 September 2012
- Duration: 40m
- Location: Online video (held at the Symfony Live San Francisco 2012 conference)
Slides are available here.
In Symfony, a form is a
Form object, and every field of this form is also a
Form. A date field is made of three fields, each of them is also
To access any
Form element inside a
To create a field:
<?php $builder->add('name', 'type');
To fill a form tree programmatically, associate a form with a corresponding entity:
To fill a form tree via submitted values1:
Requests only transport data as strings.
Each Form object store its data in 2 formats:
- the model data, used in the application
- the view data, used in the views, usually strings
- text type: stores both model and view data as strings
- number type: model format is a float; view format is a localized string (for separators, ...)
- date type: model format can be stored as a string, an integer (Unix timestamp), an array or a
DateTime; view format can be a string or an array depending on the model format (the model format is selected in the
inputoption of the field)
Consequence of this modularity: it is really difficult to access the data because each format type has to be handled.
Form object stores a third normalized format, not configurable, accessible with
$form->getNormData() (for the date type, it is an instance of
The normalized data should contain as much information as possible.
The transformation from model data to normalized data (resp. from normalized data to view data) is done using model transformers (resp. view transformers).
setData() sets the model data,
bind() sets the view data. Transformations to the other formats are then done using the data transformers in order to keep all data synchronized.
Data transformers implement 2 methods of
Data transformers should never change the information stored in a form, but only the data's representation. To change information, use events instead.
To create an extension of an existing class, data transformers can be chained to convert a type to another and then to another type again.
Data mapping is the exchange of information between a form and its fields (its direct children).
setData() is called on a form, it also calls
setData() on each field of its direct children. Same behavior appears when calling
bind() on a form. The default and only data mapper of Symfony,
DataMapperInterface), calls the getters/setters of the entity.
In order to not store a field value in the model object, i.e. not apply the data mapper to this field, the
mapped option has to be set to false:
<?php $builder->add('name', 'type', array ( 'mapped' => false ));
Since it is not synchronized with the model, data has to be set either using the
data option of the
add() method or the
setData() on this field. To access the value of the field,
getData() must be explicitely called on this field because the model does not store this value.
Customized getters/setters or public property names can be used by setting the
property_path option of the
add() method to the name of these getters/setters or this property. This can also be done with classes implementing the
ArrayAccess interface. The same property can also be used to chain getters/setters. Finally, all these capabilities can be mixed.
Events are meant to modify the content of the form itself: filtering (convert to lowercase, strip HTML tags, ...), cleaning, dynamically modifying forms, ...
A common event is
BIND, called during the data normalization.
Form types vs form instances
Form types exist once in an application and should only have global dependencies that every form needs (e.g. an
EntityManager, ...). Also, they do not change after construction time.
Form instances exist multiple times and can and will change after construction.
Do not pass data to the constructor of form types.
PRE_SET_DATA event instead, called at the beginning of the
setData() method. Allows you to attach children to the form before processing the method.
- Dynamic form fields should be added and removed using events instead of creating all of them in the type and then remove them when not needed.
- Advice on performance when creating big forms: rely on Symfony optimizations to display multiple entity fields instead of doing custom DB queries, and profile.
- To display an embedded form along with another form, use form themes.
As of Symfony 2.3, this is done using