Skip to content

Commit 447df01

Browse files
committed
added documentation for PHP templates (fields_as_templates branch)
1 parent 962e813 commit 447df01

File tree

4 files changed

+675
-8
lines changed

4 files changed

+675
-8
lines changed

guides/form/index.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Symfony2 Forms
2+
==============
3+
4+
.. toctree::
5+
:maxdepth: 2
6+
7+
overview
8+
view
9+
twig

guides/form/overview.rst

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
.. index::
2+
single: Forms
3+
4+
Forms
5+
=====
6+
7+
.. caution::
8+
9+
This chapter describes a feature that is only available in the
10+
``fields_as_templates`` `branch`_.
11+
12+
Symfony2 features a sophisticated Form component that allows you to easily
13+
create mighty forms.
14+
15+
Your First Form
16+
---------------
17+
18+
A form in Symfony2 is a transparent layer on top of your domain model. It
19+
reads properties from an object, displays the values in the form, and allows
20+
the user to change them. When the form is submitted, the values are written
21+
back into the object.
22+
23+
Let's see how this works in a practical example. Let's create a simple
24+
``Customer`` class::
25+
26+
class Customer
27+
{
28+
public $name;
29+
private $age = 20;
30+
31+
public function getAge()
32+
{
33+
return $this->age;
34+
}
35+
36+
public function setAge($age)
37+
{
38+
$this->age = $age;
39+
}
40+
}
41+
42+
The class contains two properties ``name`` and "age". The property ``$name``
43+
is public, while ``$age`` can only be modified through setters and getters.
44+
45+
Now let's create a form to let the visitor fill the data of the object::
46+
47+
// src/Application/HelloBundle/Controller/HelloController.php
48+
public function signupAction()
49+
{
50+
$customer = new Customer();
51+
52+
$form = new Form('customer', $customer, $this['validator']);
53+
$form->add(new TextField('name'));
54+
$form->add(new IntegerField('age'));
55+
56+
return $this->render('HelloBundle:Hello:signup.php', array(
57+
'form' => $this['templating.form']->get($form)
58+
));
59+
}
60+
61+
A form consists of various fields. Each field represents a property in your
62+
class. The property must have the same name as the field and must either be
63+
public or accessible through public getters and setters.
64+
65+
Instead of passing the form instance directly to the view, we wrap it with an
66+
object that provides methods that help render the form with more flexibility
67+
(``$this['templating.form']->get($form)``).
68+
69+
Let's create a simple template to render the form:
70+
71+
.. code-block:: html+php
72+
73+
# src/Application/HelloBundle/Resources/views/Hello/signup.php
74+
<?php $view->extend('HelloBundle::layout.php') ?>
75+
76+
<?php echo $form->form('#') ?>
77+
<?php echo $form->render() ?>
78+
79+
<input type="submit" value="Send!" />
80+
</form>
81+
82+
.. note::
83+
Form rendering in templates is covered in two dedicated chapters: one for
84+
:doc:`PHP templates </guides/forms/view>`, and one for :doc:`Twig
85+
templates </guides/forms/twig>`.
86+
87+
When the user submits the form, we also need to handle the submitted data. All
88+
the data is stored in a POST parameter with the name of the form::
89+
90+
# src/Application/HelloBundle/Controller/HelloController.php
91+
public function signupAction()
92+
{
93+
$customer = new Customer();
94+
$form = new Form('customer', $customer, $this['validator']);
95+
96+
// form setup...
97+
98+
if ('POST' === $this['request']->getMethod()) {
99+
$form->bind($this['request']->request->get('customer'));
100+
101+
if ($form->isValid()) {
102+
// save $customer object and redirect
103+
}
104+
}
105+
106+
return $this->render('HelloBundle:Hello:signup.php', array('form' => $form));
107+
}
108+
109+
Congratulations! You just created your first fully-functional form with
110+
Symfony2.
111+
112+
.. index::
113+
single: Forms; Fields
114+
115+
Form Fields
116+
-----------
117+
118+
As you have learned, a form consists of one or more form fields. A field knows
119+
how to convert data between normalized and humane representations.
120+
121+
Let's look at the ``DateField`` for example. While you probably prefer to
122+
store dates as strings or ``DateTime`` objects, users rather like to choose
123+
them from a list of drop downs. ``DateField`` handles the rendering and type
124+
conversion for you.
125+
126+
Basic Fields
127+
~~~~~~~~~~~~
128+
129+
Symfony2 ships with all fields available in plain HTML:
130+
131+
============= ==================
132+
Field Name Description
133+
============= ==================
134+
TextField An input tag for entering short text
135+
TextareaField A textarea tag for entering long text
136+
CheckboxField A checkbox
137+
ChoiceField A drop-down or multiple radio-buttons/checkboxes for selecting values
138+
PasswordField A password input tag
139+
HiddenField A hidden input tag
140+
============= ==================
141+
142+
Localized Fields
143+
~~~~~~~~~~~~~~~~
144+
145+
The Form component also features fields that render differently depending on
146+
the locale of the user:
147+
148+
============= ==================
149+
Field Name Description
150+
============= ==================
151+
NumberField A text field for entering numbers
152+
IntegerField A text field for entering integers
153+
PercentField A text field for entering percent values
154+
MoneyField A text field for entering money values
155+
DateField A text field or multiple drop-downs for entering dates
156+
BirthdayField An extension of DateField for selecting birthdays
157+
TimeField A text field or multiple drop-downs for entering a time
158+
DateTimeField A combination of DateField and TimeField
159+
TimezoneField An extension of ChoiceField for selecting a timezone
160+
============= ==================
161+
162+
Field Groups
163+
~~~~~~~~~~~~
164+
165+
Field groups allow you to combine multiple fields together. While normal
166+
fields only allow you to edit scalar data types, field groups can be used to
167+
edit whole objects or arrays. Let's add a new class ``Address`` to our model::
168+
169+
class Address
170+
{
171+
public $street;
172+
public $zipCode;
173+
}
174+
175+
Now we can add a property ``$address`` to the customer that stores one
176+
``Address`` object::
177+
178+
class Customer
179+
{
180+
// other properties ...
181+
182+
public $address;
183+
}
184+
185+
We can use a field group to show fields for the customer and the nested
186+
address at the same time::
187+
188+
# src/Application/HelloBundle/Controller/HelloController.php
189+
public function signupAction()
190+
{
191+
$customer = new Customer();
192+
$customer->address = new Address();
193+
194+
// form configuration ...
195+
196+
$group = new FieldGroup('address');
197+
$group->add(new TextField('street'));
198+
$group->add(new TextField('zipCode'));
199+
$form->add($group);
200+
201+
// process form ...
202+
}
203+
204+
With only these little changes you can now edit also the ``Address`` object!
205+
Cool, ey?
206+
207+
Repeated Fields
208+
~~~~~~~~~~~~~~~
209+
210+
The ``RepeatedField`` is an extended field group that allows you to output a
211+
field twice. The repeated field will only validate if the user enters the same
212+
value in both fields::
213+
214+
$form->add(new RepeatedField(new TextField('email')));
215+
216+
This is a very useful field for querying email addresses or passwords!
217+
218+
Collection Fields
219+
~~~~~~~~~~~~~~~~~
220+
221+
The ``CollectionField`` is a special field group for manipulating arrays or
222+
objects that implement the interface ``Traversable``. To demonstrate this, we
223+
will extend the ``Customer`` class to store three email addresses::
224+
225+
class Customer
226+
{
227+
// other properties ...
228+
229+
public $emails = array('', '', '');
230+
}
231+
232+
We will now add a ``CollectionField`` to manipulate these addresses::
233+
234+
$form->add(new CollectionField(new TextField('emails')));
235+
236+
If you set the option "modifiable" to ``true``, you can even add or remove
237+
rows in the collection via JavaScript! The ``CollectionField`` will notice it
238+
and resize the underlying array accordingly.
239+
240+
.. index::
241+
pair: Forms; Validation
242+
243+
Form Validation
244+
---------------
245+
246+
You have already learned in the last part of this tutorial how to set up
247+
validation constraints for a PHP class. The nice thing is that this is enough
248+
to validate a Form! Remember that a form is nothing more than a gateway for
249+
changing data in an object.
250+
251+
What now if there are further validation constraints for a specific form, that
252+
are irrelevant for the underlying class? What if the form contains fields that
253+
should not be written into the object?
254+
255+
The answer to that question is most of the time to extend your domain model.
256+
We'll demonstrate this approach by extending our form with a checkbox for
257+
accepting terms and conditions.
258+
259+
Let's create a simple ``Registration`` class for this purpose::
260+
261+
class Registration
262+
{
263+
/** @validation:Valid */
264+
public $customer;
265+
266+
/** @validation:AssertTrue(message="Please accept the terms and conditions") */
267+
public $termsAccepted = false;
268+
269+
public function process()
270+
{
271+
// save user, send emails etc.
272+
}
273+
}
274+
275+
Now we can easily adapt the form in the controller::
276+
277+
# src/Application/HelloBundle/Controller/HelloController.php
278+
public function signupAction()
279+
{
280+
$registration = new Registration();
281+
$registration->customer = new Customer();
282+
283+
$form = new Form('registration', $registration, $this['validator']);
284+
$form->add(new CheckboxField('termsAccepted'));
285+
286+
$group = new FieldGroup('customer');
287+
288+
// add customer fields to this group ...
289+
290+
$form->add($group);
291+
292+
if ('POST' === $this['request']->getMethod()) {
293+
$form->bind($this['request']->request->get('registration'));
294+
295+
if ($form->isValid()) {
296+
$registration->process();
297+
}
298+
}
299+
300+
return $this->render('HelloBundle:Hello:signup.php', array('form' => $form));
301+
}
302+
303+
The big benefit of this refactoring is that we can reuse the ``Registration``
304+
class. Extending the application to allow users to sign up via XML is no
305+
problem at all!
306+
307+
Final Thoughts
308+
--------------
309+
310+
This chapter showed you how the Form component of Symfony2 can help you to
311+
rapidly create forms for your domain objects. The component embraces a strict
312+
separation between business logic and presentation. Many fields are
313+
automatically localized to make your visitors feel comfortable on your
314+
website. And with a flexible architecture, this is just the beginning of many
315+
mighty user-created fields!

0 commit comments

Comments
 (0)