|
| 1 | +Forms in Twig Templates |
| 2 | +======================= |
| 3 | + |
| 4 | +.. caution:: |
| 5 | + |
| 6 | + This chapter describes a feature that is only available in the |
| 7 | + ``fields_as_templates`` `branch`_. |
| 8 | + |
| 9 | +A Symfony2 :doc:`Form </guides/forms>` is made of fields. Fields describe the |
| 10 | +form semantic, not its end-user representation; it means that a form is not |
| 11 | +tied to HTML. Instead, it is the responsibility of the web designer to display |
| 12 | +each form field the way he wants. So, displaying a Symfony2 form in a template |
| 13 | +can easily be done manually. But, Twig eases form integration and |
| 14 | +customization by providing a set of filters that can be applied on the form |
| 15 | +and field instances. |
| 16 | + |
| 17 | +Displaying a Form |
| 18 | +----------------- |
| 19 | + |
| 20 | +As the global structure of a form (the form tag, the submit button, ...) is |
| 21 | +not defined by the form instance, you are free to use the HTML code you want. |
| 22 | +A simple form template reads as follows: |
| 23 | + |
| 24 | +.. code-block:: html |
| 25 | + |
| 26 | + <form action="#" method="post"> |
| 27 | + <!-- Display the form fields --> |
| 28 | + |
| 29 | + <input type="submit" /> |
| 30 | + </form> |
| 31 | + |
| 32 | +Besides the global form structure, you need a way to display global errors and |
| 33 | +hidden fields; that's the job of the ``render_errors`` and ``render_hidden`` |
| 34 | +filters respectively: |
| 35 | + |
| 36 | +.. code-block:: jinja |
| 37 | +
|
| 38 | + <form action="#" method="post"> |
| 39 | + {{ form|render_errors }} |
| 40 | +
|
| 41 | + <!-- Display the form fields --> |
| 42 | +
|
| 43 | + {{ form|render_hidden }} |
| 44 | + <input type="submit" /> |
| 45 | + </form> |
| 46 | +
|
| 47 | +.. note:: |
| 48 | + By default, the ``render_errors`` generates a ``<ul>`` list, but this can |
| 49 | + be easily customized as you will see later in this document. |
| 50 | + |
| 51 | +Last but not the least, a form containing a file input must contain the |
| 52 | +``enctype`` attribute; use the ``render_enctype`` filter to render it: |
| 53 | + |
| 54 | +.. code-block:: jinja |
| 55 | +
|
| 56 | + <form action="#" {{ form|render_enctype }} method="post"> |
| 57 | +
|
| 58 | +Displaying Fields |
| 59 | +----------------- |
| 60 | + |
| 61 | +Accessing form fields is easy as a Symfony2 form acts as an array: |
| 62 | + |
| 63 | +.. code-block:: jinja |
| 64 | +
|
| 65 | + {{ form.title }} |
| 66 | +
|
| 67 | + {# access a field (first_name) nested in a group (user) #} |
| 68 | + {{ form.user.first_name }} |
| 69 | +
|
| 70 | +As each field is a Field instance, it cannot be displayed as show above; use |
| 71 | +one of the field filters instead. |
| 72 | + |
| 73 | +The ``render_widget`` filter renders the HTML representation of a field: |
| 74 | + |
| 75 | +.. code-block:: jinja |
| 76 | +
|
| 77 | + {{ form.title|render_widget }} |
| 78 | +
|
| 79 | +.. note:: |
| 80 | + The field's widget is selected based on the field class name (more |
| 81 | + information below). |
| 82 | + |
| 83 | +The ``render_label`` renders the ``<label>`` tag associated with the field: |
| 84 | + |
| 85 | +.. code-block:: jinja |
| 86 | +
|
| 87 | + {{ form.title|render_label }} |
| 88 | +
|
| 89 | +By default, Symfony2 "humanizes" the field name, but you can give your own |
| 90 | +label: |
| 91 | + |
| 92 | +.. code-block:: jinja |
| 93 | +
|
| 94 | + {{ form.title|render_label('Give me a title') }} |
| 95 | +
|
| 96 | +.. note:: |
| 97 | + Symfony2 automatically internationalizes all labels and error messages. |
| 98 | + |
| 99 | +The ``render_errors`` filter renders the field errors: |
| 100 | + |
| 101 | +.. code-block:: jinja |
| 102 | +
|
| 103 | + {{ form.title|render_errors }} |
| 104 | +
|
| 105 | +.. tip:: |
| 106 | + The ``render_errors`` can be used on a form or on a field. |
| 107 | + |
| 108 | +You can also get the data associated with the field (the default data or the |
| 109 | +data submitted by the user), via the ``render_data`` filter: |
| 110 | + |
| 111 | +.. code-block:: jinja |
| 112 | +
|
| 113 | + {{ form.title|render_data }} |
| 114 | +
|
| 115 | + {{ form.created_at|render_data|date('Y-m-d') }} |
| 116 | +
|
| 117 | +Defining the HTML Representation |
| 118 | +-------------------------------- |
| 119 | + |
| 120 | +All filters rely on Twig template blocks to render HTML. By default, Symfony2 |
| 121 | +comes bundled with two templates that define all the needed blocks; one for |
| 122 | +form instances (``form.twig``), and one for field instances |
| 123 | +(``widgets.twig``). |
| 124 | + |
| 125 | +Each filter is associated with one template block. For instance, the |
| 126 | +``render_errors`` filter looks for an ``errors`` block. The built-in one reads |
| 127 | +as follows: |
| 128 | + |
| 129 | +.. code-block:: jinja |
| 130 | +
|
| 131 | + {# TwigBundle::form.twig #} |
| 132 | +
|
| 133 | + {% block errors %} |
| 134 | + {% if errors %} |
| 135 | + <ul> |
| 136 | + {% for error in errors %} |
| 137 | + <li>{% trans error.0 with error.1 from validators %}</li> |
| 138 | + {% endfor %} |
| 139 | + </ul> |
| 140 | + {% endif %} |
| 141 | + {% endblock errors %} |
| 142 | +
|
| 143 | +Here is the full list of filters and their associated block names: |
| 144 | + |
| 145 | +================= ================== |
| 146 | +Filter Block Name |
| 147 | +================= ================== |
| 148 | +``render_errors`` ``errors`` |
| 149 | +``render_hidden`` ``hidden`` |
| 150 | +``render_label`` ``label`` |
| 151 | +``render`` ``group`` or ``field`` (see below) |
| 152 | +================= ================== |
| 153 | + |
| 154 | +The ``render_widget`` filter is a bit different as it selects the block to |
| 155 | +render based on the underscore version of the field class name. For instance, |
| 156 | +it looks for an ``input_field`` block when rendering an ``InputField`` |
| 157 | +instance: |
| 158 | + |
| 159 | +.. code-block:: jinja |
| 160 | +
|
| 161 | + {# TwigBundle::widgets.twig #} |
| 162 | +
|
| 163 | + {% block input_field %} |
| 164 | + {% tag "input" with attributes %} |
| 165 | + {% endblock input_field %} |
| 166 | +
|
| 167 | +If the block does not exist, the filter looks for a block for one of the field |
| 168 | +parent classes. That's why there is no default ``password_field`` block as its |
| 169 | +representation is exactly the same as its parent class (``input_field``). |
| 170 | + |
| 171 | +Customizing Field Representation |
| 172 | +-------------------------------- |
| 173 | + |
| 174 | +The easiest way to customize a widget is by passing custom HTML attributes as |
| 175 | +an argument to ``render_widget``: |
| 176 | + |
| 177 | +.. code-block:: jinja |
| 178 | +
|
| 179 | + {{ form.title|render_widget(['class': 'important']) }} |
| 180 | +
|
| 181 | +If you want to completely override the HTML representation of a widget, pass a |
| 182 | +Twig template that defines the needed template block: |
| 183 | + |
| 184 | +.. code-block:: jinja |
| 185 | +
|
| 186 | + {{ form.title|render_widget([], 'HelloBundle::widgets.twig') }} |
| 187 | +
|
| 188 | +The ``HelloBundle::widgets.twig`` is a regular Twig template containing blocks |
| 189 | +defining the HTML representation for widgets you want to override: |
| 190 | + |
| 191 | +.. code-block:: jinja |
| 192 | +
|
| 193 | + {# HelloBundle/Resources/views/widgets.twig #} |
| 194 | +
|
| 195 | + {% block input_field %} |
| 196 | + <div class="input_field"> |
| 197 | + {% tag "input" with attributes %} |
| 198 | + </div> |
| 199 | + {% endblock input_field %} |
| 200 | +
|
| 201 | +In this example, the ``input_field`` block is redefined. Instead of changing |
| 202 | +the default representation, you can also extend the default one by using the |
| 203 | +Twig native inheritance feature: |
| 204 | + |
| 205 | +.. code-block:: jinja |
| 206 | +
|
| 207 | + {# HelloBundle/Resources/views/widgets.twig #} |
| 208 | +
|
| 209 | + {% extends 'TwigBundle::widgets.twig' %} |
| 210 | +
|
| 211 | + {% block date_time_field %} |
| 212 | + <div class="important_date_field"> |
| 213 | + {% parent %} |
| 214 | + </div> |
| 215 | + {% endblock date_time_field %} |
| 216 | +
|
| 217 | +If you want to customize all fields of a given form, use the ``form_theme`` |
| 218 | +tag: |
| 219 | + |
| 220 | +.. code-block:: jinja |
| 221 | +
|
| 222 | + {% form_theme form 'HelloBundle::widgets.twig' %} |
| 223 | +
|
| 224 | +Whenever you call the ``render_widget`` filter on the ``form`` after this |
| 225 | +call, Symfony2 will look for a representation in your template before falling |
| 226 | +back to the default one. |
| 227 | + |
| 228 | +If the widget blocks are defined in several templates, add them as an ordered |
| 229 | +array: |
| 230 | + |
| 231 | +.. code-block:: jinja |
| 232 | +
|
| 233 | + {% form_theme form ['HelloBundle::form.twig', 'HelloBundle::widgets.twig', 'HelloBundle::hello_widgets.twig'] %} |
| 234 | +
|
| 235 | +A theme can be attached to a whole form (as above) or just for a field group: |
| 236 | + |
| 237 | +.. code-block:: jinja |
| 238 | +
|
| 239 | + {% form_theme form.user 'HelloBundle::widgets.twig' %} |
| 240 | +
|
| 241 | +Finally, customizing the representation of all forms of an application is |
| 242 | +possible via configuration: |
| 243 | + |
| 244 | +.. configuration-block:: |
| 245 | + |
| 246 | + .. code-block:: yaml |
| 247 | +
|
| 248 | + # app/config/config.yml |
| 249 | + twig.config: |
| 250 | + form: |
| 251 | + resources: [BlogBundle::widgets.twig] |
| 252 | +
|
| 253 | + .. code-block:: xml |
| 254 | +
|
| 255 | + <!-- app/config/config.xml --> |
| 256 | + <twig:config> |
| 257 | + <twig:form> |
| 258 | + <twig:resource>BlogBundle::widgets.twig</twig:resource> |
| 259 | + </twig:form> |
| 260 | + </twig:config> |
| 261 | +
|
| 262 | + .. code-block:: php |
| 263 | +
|
| 264 | + // app/config/config.php |
| 265 | + $container->loadFromExtension('twig', 'config', array('form' => array( |
| 266 | + 'resources' => array('BlogBundle::widgets.twig'), |
| 267 | + ))); |
| 268 | +
|
| 269 | + ... configuration XML/YAML/PHP |
| 270 | + |
| 271 | +Prototyping |
| 272 | +----------- |
| 273 | + |
| 274 | +When prototyping a form, you can use the ``render`` filter instead of manually |
| 275 | +rendering all fields: |
| 276 | + |
| 277 | +.. code-block:: jinja |
| 278 | +
|
| 279 | + <form action="#" {{ form|render_enctype }} method="post"> |
| 280 | + {{ form|render }} |
| 281 | + <input type="submit" /> |
| 282 | + </form> |
| 283 | +
|
| 284 | +The ``render`` filter can also be used to render a field "row": |
| 285 | + |
| 286 | +.. code-block:: jinja |
| 287 | +
|
| 288 | + <form action="#" {{ form|render_enctype }} method="post"> |
| 289 | + {{ form|render_errors }} |
| 290 | + <table> |
| 291 | + {{ form.first_name|render }} |
| 292 | + {{ form.last_name|render }} |
| 293 | + </table> |
| 294 | + {{ form|render_hidden }} |
| 295 | + <input type="submit" /> |
| 296 | + </form> |
| 297 | +
|
| 298 | +The ``render`` filter uses the ``group`` and ``field`` blocks for rendering: |
| 299 | + |
| 300 | +.. code-block:: jinja |
| 301 | +
|
| 302 | + {# TwigBundle::form.twig #} |
| 303 | +
|
| 304 | + {% block group %} |
| 305 | + {{ group|render_errors }} |
| 306 | + <table> |
| 307 | + {% for field in group %} |
| 308 | + {% if not field.ishidden %} |
| 309 | + {{ field|render }} |
| 310 | + {% endif %} |
| 311 | + {% endfor %} |
| 312 | + </table> |
| 313 | + {{ group|render_hidden }} |
| 314 | + {% endblock group %} |
| 315 | +
|
| 316 | + {% block field %} |
| 317 | + <tr> |
| 318 | + <th>{{ field|render_label }}</th> |
| 319 | + <td> |
| 320 | + {{ field|render_errors }} |
| 321 | + {{ field|render_widget }} |
| 322 | + </td> |
| 323 | + </tr> |
| 324 | + {% endblock field %} |
| 325 | +
|
| 326 | +As for any other filter, ``render`` accepts a template as an argument to |
| 327 | +override the default representation: |
| 328 | + |
| 329 | +.. code-block:: jinja |
| 330 | +
|
| 331 | + {{ form|render("HelloBundle::form.twig") }} |
| 332 | +
|
| 333 | +.. caution:: |
| 334 | + The ``render`` filter is not very flexible and should only be used to |
| 335 | + build prototypes. |
| 336 | + |
| 337 | +.. _branch: http://github.com/fabpot/symfony/tree/fields_as_templates |
0 commit comments